diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d702359f8ab5..79d07ddf2f87 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -124,7 +124,7 @@ config RISCV
 	select PCI_DOMAINS_GENERIC if PCI
 	select PCI_MSI if PCI
 	select RISCV_INTC
-	select RISCV_TIMER if RISCV_SBI
+	select RISCV_TIMER if RISCV_SBI && !SOPHGO_MULTI_CHIP_CLOCK_SYNC
 	select SPARSE_IRQ
 	select SYSCTL_EXCEPTION_TRACE
 	select THREAD_INFO_IN_TASK
@@ -316,6 +316,31 @@ config SMP
 
 	  If you don't know what to do here, say N.
 
+config SCHED_MC
+	bool "Multi-core scheduler support"
+	depends on SMP
+	help
+	  Multi-core scheduler support improves the CPU scheduler's decision
+	  making when dealing with multi-core CPU chips at a cost of slightly
+	  increased overhead in some places. If unsure say N here.
+
+config SCHED_CLUSTER
+	bool "Cluster scheduler support"
+	help
+	  Cluster scheduler support improves the CPU scheduler's decision
+	  making when dealing with machines that have clusters of CPUs.
+	  Cluster usually means a couple of CPUs which are placed closely
+	  by sharing mid-level caches, last-level cache tags or internal
+	  busses.
+
+config SCHED_SMT
+	bool "SMT scheduler support"
+	depends on SMP
+	help
+	  Improves the CPU scheduler's decision making when dealing with
+	  MultiThreading at a cost of slightly increased overhead in some
+	  places. If unsure say N here.
+
 config NR_CPUS
 	int "Maximum number of CPUs (2-512)"
 	depends on SMP
@@ -345,6 +370,29 @@ config TUNE_GENERIC
 
 endchoice
 
+config HIGHMEM
+	bool "High Memory Support"
+	depends on MMU
+	select KMAP_LOCAL
+	default y
+	help
+	  Enable high memory support on riscv64 which uses supports
+	  max 39-bit virtual address spaces.
+
+config FORCE_MAX_ZONEORDER
+	int "Maximum zone order"
+	default 13
+	help
+	  The kernel memory allocator divides physically contiguous memory
+	  blocks into "zones", where each zone is a power of two number of
+	  pages.  This option selects the largest power of two that the kernel
+	  keeps in the memory allocator.  If you need to allocate very large
+	  blocks of physically contiguous memory, then you may need to
+	  increase this value.
+
+	  This config option is actually maximum order plus one. For example,
+	  a value of 13 means that the largest free memory block is 2^12 pages.
+
 # Common NUMA Features
 config NUMA
 	bool "NUMA Memory Allocation and Scheduler Support"
@@ -481,6 +529,15 @@ config FPU
 
 	  If you don't know what to do here, say Y.
 
+config VECTOR
+	bool "VECTOR support"
+	default n
+	help
+	  Say N here if you want to disable all vector related procedure
+	  in the kernel.
+
+	  If you don't know what to do here, say Y.
+
 endmenu # "Platform type"
 
 menu "Kernel features"
diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.erratas
index f3623df23b5f..69621ae6d647 100644
--- a/arch/riscv/Kconfig.erratas
+++ b/arch/riscv/Kconfig.erratas
@@ -66,4 +66,17 @@ config ERRATA_THEAD_CMO
 
 	  If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_PMU
+	bool "Apply T-Head PMU errata"
+	depends on ERRATA_THEAD && RISCV_PMU_SBI
+	default y
+	help
+	  The T-Head C9xx cores implement a PMU overflow extension very
+	  similar to the core SSCOFPMF extension.
+
+	  This will apply the overflow errata to handle the non-standard
+	  behaviour via the regular SBI PMU driver and interface.
+
+	  If you don't know what to do here, say "Y".
+
 endmenu # "CPU errata selection"
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 29d78eefc889..9a32d7ef52c9 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -81,4 +81,19 @@ config SOC_CANAAN_K210_DTB_SOURCE
 
 endif # SOC_CANAAN
 
+config ARCH_SOPHGO
+	bool "Sophgo SoCs"
+	select SIFIVE_PLIC
+	select DW_APB_TIMER_OF
+	help
+	  This enables support for Sophgo SoC platform hardware.
+
+config SOPHGO_MULTI_CHIP_CLOCK_SYNC
+	bool "Sophgo multi-chip clock synchronous"
+	depends on ARCH_SOPHGO
+	default n
+	help
+	  To solve the problem of asynchronous multi-chip clocks,
+	  the local timer has been replaced with an APB timer.
+
 endmenu # "SoC selection"
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 3cb876f83187..1dbc7b978f95 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -51,26 +51,9 @@ endif
 endif
 endif
 
-# ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
-riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
-riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
-
-ifdef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC
-KBUILD_CFLAGS += -Wa,-misa-spec=2.2
-KBUILD_AFLAGS += -Wa,-misa-spec=2.2
-else
-riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei
-endif
-
-# Check if the toolchain supports Zicbom extension
-riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZICBOM) := $(riscv-march-y)_zicbom
-
-# Check if the toolchain supports Zihintpause extension
-riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE) := $(riscv-march-y)_zihintpause
+include $(srctree)/arch/riscv/Makefile.isa
 
-KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
+KBUILD_CFLAGS += -march=$(subst v0p7,,$(subst fd,,$(riscv-march-y)))
 KBUILD_AFLAGS += -march=$(riscv-march-y)
 
 KBUILD_CFLAGS += -mno-save-restore
diff --git a/arch/riscv/Makefile.isa b/arch/riscv/Makefile.isa
new file mode 100644
index 000000000000..cdc885a4e267
--- /dev/null
+++ b/arch/riscv/Makefile.isa
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# ISA string setting
+riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
+riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
+riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
+riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
+riscv-march-$(CONFIG_VECTOR)		:= $(riscv-march-y)v0p7
+
+ifndef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC
+riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei
+endif
+
+# Check if the toolchain supports Zicbom extension
+riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZICBOM) := $(riscv-march-y)_zicbom
+
+# Check if the toolchain supports Zihintpause extension
+riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE) := $(riscv-march-y)_zihintpause
diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
index ff174996cdfd..befe9c222235 100644
--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -3,5 +3,6 @@ subdir-y += sifive
 subdir-y += starfive
 subdir-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += canaan
 subdir-y += microchip
+subdir-y += sophgo
 
 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile
new file mode 100644
index 000000000000..f6fb3d4850b3
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x8evb.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-milkv-pioneer.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-pisces.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x4evb.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-yixin-s2110.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-capricorn.dtb
diff --git a/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi b/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi
new file mode 100644
index 000000000000..97de3fdcad38
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi
@@ -0,0 +1,700 @@
+#define NR_CPUS 128
+
+#include "mango.dtsi"
+#if NR_CPUS > 64
+#include "mango-cpus-socket1.dtsi"
+#endif
+#include "mango-clock-socket1.dtsi"
+
+/ {
+	/delete-node/ distance-map;
+	distance-map {
+		compatible = "numa-distance-map-v1";
+		distance-matrix = <0 0 10>,	//chip0
+				  <0 1 15>,
+				  <0 2 25>,
+				  <0 3 30>,
+				  <0 4 110>,
+				  <0 5 115>,
+				  <0 6 125>,
+				  <0 7 130>,
+				  <1 0 15>,
+				  <1 1 10>,
+				  <1 2 30>,
+				  <1 3 25>,
+				  <1 4 115>,
+				  <1 5 110>,
+				  <1 6 130>,
+				  <1 7 125>,
+				  <2 0 25>,
+				  <2 1 30>,
+				  <2 2 10>,
+				  <2 3 15>,
+				  <2 4 125>,
+				  <2 5 130>,
+				  <2 6 110>,
+				  <2 7 115>,
+				  <3 0 30>,
+				  <3 1 25>,
+				  <3 2 15>,
+				  <3 3 10>,
+				  <3 4 130>,
+				  <3 5 125>,
+				  <3 6 115>,
+				  <3 7 110>,
+				  <4 0 110>,	//chip1
+				  <4 1 115>,
+				  <4 2 125>,
+				  <4 3 130>,
+				  <4 4 10>,
+				  <4 5 15>,
+				  <4 6 25>,
+				  <4 7 30>,
+				  <5 0 115>,
+				  <5 1 110>,
+				  <5 2 130>,
+				  <5 3 125>,
+				  <5 4 15>,
+				  <5 5 10>,
+				  <5 6 30>,
+				  <5 7 25>,
+				  <6 0 125>,
+				  <6 1 130>,
+				  <6 2 110>,
+				  <6 3 115>,
+				  <6 4 25>,
+				  <6 5 30>,
+				  <6 6 10>,
+				  <6 7 15>,
+				  <7 0 130>,
+				  <7 1 125>,
+				  <7 2 115>,
+				  <7 3 110>,
+				  <7 4 30>,
+				  <7 5 25>,
+				  <7 6 15>,
+				  <7 7 10>;
+	};
+
+	soc {
+#if NR_CPUS > 64
+		/delete-node/ clint-mswi@7094000000;
+		clint_mswi: clint-mswi@7094000000 {
+			compatible = "thead,c900-clint-mswi";
+			reg = <0x00000070 0x94000000 0x00000000 0x00004000>;
+			interrupts-extended = <
+				&cpu0_intc 3
+				&cpu1_intc 3
+				&cpu2_intc 3
+				&cpu3_intc 3
+				&cpu4_intc 3
+				&cpu5_intc 3
+				&cpu6_intc 3
+				&cpu7_intc 3
+				&cpu8_intc 3
+				&cpu9_intc 3
+				&cpu10_intc 3
+				&cpu11_intc 3
+				&cpu12_intc 3
+				&cpu13_intc 3
+				&cpu14_intc 3
+				&cpu15_intc 3
+				&cpu16_intc 3
+				&cpu17_intc 3
+				&cpu18_intc 3
+				&cpu19_intc 3
+				&cpu20_intc 3
+				&cpu21_intc 3
+				&cpu22_intc 3
+				&cpu23_intc 3
+				&cpu24_intc 3
+				&cpu25_intc 3
+				&cpu26_intc 3
+				&cpu27_intc 3
+				&cpu28_intc 3
+				&cpu29_intc 3
+				&cpu30_intc 3
+				&cpu31_intc 3
+				&cpu32_intc 3
+				&cpu33_intc 3
+				&cpu34_intc 3
+				&cpu35_intc 3
+				&cpu36_intc 3
+				&cpu37_intc 3
+				&cpu38_intc 3
+				&cpu39_intc 3
+				&cpu40_intc 3
+				&cpu41_intc 3
+				&cpu42_intc 3
+				&cpu43_intc 3
+				&cpu44_intc 3
+				&cpu45_intc 3
+				&cpu46_intc 3
+				&cpu47_intc 3
+				&cpu48_intc 3
+				&cpu49_intc 3
+				&cpu50_intc 3
+				&cpu51_intc 3
+				&cpu52_intc 3
+				&cpu53_intc 3
+				&cpu54_intc 3
+				&cpu55_intc 3
+				&cpu56_intc 3
+				&cpu57_intc 3
+				&cpu58_intc 3
+				&cpu59_intc 3
+				&cpu60_intc 3
+				&cpu61_intc 3
+				&cpu62_intc 3
+				&cpu63_intc 3
+
+				// chip 1
+				&cpu64_intc 3
+				&cpu65_intc 3
+				&cpu66_intc 3
+				&cpu67_intc 3
+				&cpu68_intc 3
+				&cpu69_intc 3
+				&cpu70_intc 3
+				&cpu71_intc 3
+				&cpu72_intc 3
+				&cpu73_intc 3
+				&cpu74_intc 3
+				&cpu75_intc 3
+				&cpu76_intc 3
+				&cpu77_intc 3
+				&cpu78_intc 3
+				&cpu79_intc 3
+				&cpu80_intc 3
+				&cpu81_intc 3
+				&cpu82_intc 3
+				&cpu83_intc 3
+				&cpu84_intc 3
+				&cpu85_intc 3
+				&cpu86_intc 3
+				&cpu87_intc 3
+				&cpu88_intc 3
+				&cpu89_intc 3
+				&cpu90_intc 3
+				&cpu91_intc 3
+				&cpu92_intc 3
+				&cpu93_intc 3
+				&cpu94_intc 3
+				&cpu95_intc 3
+				&cpu96_intc 3
+				&cpu97_intc 3
+				&cpu98_intc 3
+				&cpu99_intc 3
+				&cpu100_intc 3
+				&cpu101_intc 3
+				&cpu102_intc 3
+				&cpu103_intc 3
+				&cpu104_intc 3
+				&cpu105_intc 3
+				&cpu106_intc 3
+				&cpu107_intc 3
+				&cpu108_intc 3
+				&cpu109_intc 3
+				&cpu110_intc 3
+				&cpu111_intc 3
+				&cpu112_intc 3
+				&cpu113_intc 3
+				&cpu114_intc 3
+				&cpu115_intc 3
+				&cpu116_intc 3
+				&cpu117_intc 3
+				&cpu118_intc 3
+				&cpu119_intc 3
+				&cpu120_intc 3
+				&cpu121_intc 3
+				&cpu122_intc 3
+				&cpu123_intc 3
+				&cpu124_intc 3
+				&cpu125_intc 3
+				&cpu126_intc 3
+				&cpu127_intc 3
+				>;
+		};
+
+		clint_mtimer16: clint-mtimer@70ac100000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac100000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu64_intc 7
+				&cpu65_intc 7
+				&cpu66_intc 7
+				&cpu67_intc 7
+				>;
+		};
+
+		clint_mtimer17: clint-mtimer@70ac110000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac110000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu68_intc 7
+				&cpu69_intc 7
+				&cpu70_intc 7
+				&cpu71_intc 7
+				>;
+		};
+
+		clint_mtimer18: clint-mtimer@70ac120000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac120000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu72_intc 7
+				&cpu73_intc 7
+				&cpu74_intc 7
+				&cpu75_intc 7
+				>;
+		};
+
+		clint_mtimer19: clint-mtimer@70ac130000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac130000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu76_intc 7
+				&cpu77_intc 7
+				&cpu78_intc 7
+				&cpu79_intc 7
+				>;
+		};
+
+		clint_mtimer20: clint-mtimer@70ac140000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac140000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu80_intc 7
+				&cpu81_intc 7
+				&cpu82_intc 7
+				&cpu83_intc 7
+				>;
+		};
+
+		clint_mtimer21: clint-mtimer@70ac150000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac150000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu84_intc 7
+				&cpu85_intc 7
+				&cpu86_intc 7
+				&cpu87_intc 7
+				>;
+		};
+
+		clint_mtimer22: clint-mtimer@70ac160000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac160000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu88_intc 7
+				&cpu89_intc 7
+				&cpu90_intc 7
+				&cpu91_intc 7
+				>;
+		};
+
+		clint_mtimer23: clint-mtimer@70ac170000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac170000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu92_intc 7
+				&cpu93_intc 7
+				&cpu94_intc 7
+				&cpu95_intc 7
+				>;
+		};
+
+		clint_mtimer24: clint-mtimer@70ac180000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac180000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu96_intc 7
+				&cpu97_intc 7
+				&cpu98_intc 7
+				&cpu99_intc 7
+				>;
+		};
+
+		clint_mtimer25: clint-mtimer@70ac190000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac190000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu100_intc 7
+				&cpu101_intc 7
+				&cpu102_intc 7
+				&cpu103_intc 7
+				>;
+		};
+
+		clint_mtimer26: clint-mtimer@70ac1a0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1a0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu104_intc 7
+				&cpu105_intc 7
+				&cpu106_intc 7
+				&cpu107_intc 7
+				>;
+		};
+
+		clint_mtimer27: clint-mtimer@70ac1b0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1b0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu108_intc 7
+				&cpu109_intc 7
+				&cpu110_intc 7
+				&cpu111_intc 7
+				>;
+		};
+
+		clint_mtimer28: clint-mtimer@70ac1c0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1c0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu112_intc 7
+				&cpu113_intc 7
+				&cpu114_intc 7
+				&cpu115_intc 7
+				>;
+		};
+
+		clint_mtimer29: clint-mtimer@70ac1d0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1d0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu116_intc 7
+				&cpu117_intc 7
+				&cpu118_intc 7
+				&cpu119_intc 7
+				>;
+		};
+
+		clint_mtimer30: clint-mtimer@70ac1e0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1e0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu120_intc 7
+				&cpu121_intc 7
+				&cpu122_intc 7
+				&cpu123_intc 7
+				>;
+		};
+
+		clint_mtimer31: clint-mtimer@70ac1f0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac1f0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu124_intc 7
+				&cpu125_intc 7
+				&cpu126_intc 7
+				&cpu127_intc 7
+				>;
+		};
+#endif
+
+		/delete-node/ interrupt-controller@7090000000;
+		intc: interrupt-controller@7090000000 {
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			compatible = "thead,c900-plic";
+			interrupt-controller;
+			interrupts-extended = <
+				&cpu0_intc  11 &cpu0_intc  9
+				&cpu1_intc  11 &cpu1_intc  9
+				&cpu2_intc  11 &cpu2_intc  9
+				&cpu3_intc  11 &cpu3_intc  9
+				&cpu4_intc  11 &cpu4_intc  9
+				&cpu5_intc  11 &cpu5_intc  9
+				&cpu6_intc  11 &cpu6_intc  9
+				&cpu7_intc  11 &cpu7_intc  9
+				&cpu8_intc  11 &cpu8_intc  9
+				&cpu9_intc  11 &cpu9_intc  9
+				&cpu10_intc  11 &cpu10_intc  9
+				&cpu11_intc  11 &cpu11_intc  9
+				&cpu12_intc  11 &cpu12_intc  9
+				&cpu13_intc  11 &cpu13_intc  9
+				&cpu14_intc  11 &cpu14_intc  9
+				&cpu15_intc  11 &cpu15_intc  9
+				&cpu16_intc  11 &cpu16_intc  9
+				&cpu17_intc  11 &cpu17_intc  9
+				&cpu18_intc  11 &cpu18_intc  9
+				&cpu19_intc  11 &cpu19_intc  9
+				&cpu20_intc  11 &cpu20_intc  9
+				&cpu21_intc  11 &cpu21_intc  9
+				&cpu22_intc  11 &cpu22_intc  9
+				&cpu23_intc  11 &cpu23_intc  9
+				&cpu24_intc  11 &cpu24_intc  9
+				&cpu25_intc  11 &cpu25_intc  9
+				&cpu26_intc  11 &cpu26_intc  9
+				&cpu27_intc  11 &cpu27_intc  9
+				&cpu28_intc  11 &cpu28_intc  9
+				&cpu29_intc  11 &cpu29_intc  9
+				&cpu30_intc  11 &cpu30_intc  9
+				&cpu31_intc  11 &cpu31_intc  9
+				&cpu32_intc  11 &cpu32_intc  9
+				&cpu33_intc  11 &cpu33_intc  9
+				&cpu34_intc  11 &cpu34_intc  9
+				&cpu35_intc  11 &cpu35_intc  9
+				&cpu36_intc  11 &cpu36_intc  9
+				&cpu37_intc  11 &cpu37_intc  9
+				&cpu38_intc  11 &cpu38_intc  9
+				&cpu39_intc  11 &cpu39_intc  9
+				&cpu40_intc  11 &cpu40_intc  9
+				&cpu41_intc  11 &cpu41_intc  9
+				&cpu42_intc  11 &cpu42_intc  9
+				&cpu43_intc  11 &cpu43_intc  9
+				&cpu44_intc  11 &cpu44_intc  9
+				&cpu45_intc  11 &cpu45_intc  9
+				&cpu46_intc  11 &cpu46_intc  9
+				&cpu47_intc  11 &cpu47_intc  9
+				&cpu48_intc  11 &cpu48_intc  9
+				&cpu49_intc  11 &cpu49_intc  9
+				&cpu50_intc  11 &cpu50_intc  9
+				&cpu51_intc  11 &cpu51_intc  9
+				&cpu52_intc  11 &cpu52_intc  9
+				&cpu53_intc  11 &cpu53_intc  9
+				&cpu54_intc  11 &cpu54_intc  9
+				&cpu55_intc  11 &cpu55_intc  9
+				&cpu56_intc  11 &cpu56_intc  9
+				&cpu57_intc  11 &cpu57_intc  9
+				&cpu58_intc  11 &cpu58_intc  9
+				&cpu59_intc  11 &cpu59_intc  9
+				&cpu60_intc  11 &cpu60_intc  9
+				&cpu61_intc  11 &cpu61_intc  9
+				&cpu62_intc  11 &cpu62_intc  9
+				&cpu63_intc  11 &cpu63_intc  9
+
+#if NR_CPUS > 64
+				//chip 1
+				&cpu64_intc  11 &cpu64_intc  9
+				&cpu65_intc  11 &cpu65_intc  9
+				&cpu66_intc  11 &cpu66_intc  9
+				&cpu67_intc  11 &cpu67_intc  9
+				&cpu68_intc  11 &cpu68_intc  9
+				&cpu69_intc  11 &cpu69_intc  9
+				&cpu70_intc  11 &cpu70_intc  9
+				&cpu71_intc  11 &cpu71_intc  9
+				&cpu72_intc  11 &cpu72_intc  9
+				&cpu73_intc  11 &cpu73_intc  9
+				&cpu74_intc  11 &cpu74_intc  9
+				&cpu75_intc  11 &cpu75_intc  9
+				&cpu76_intc  11 &cpu76_intc  9
+				&cpu77_intc  11 &cpu77_intc  9
+				&cpu78_intc  11 &cpu78_intc  9
+				&cpu79_intc  11 &cpu79_intc  9
+				&cpu80_intc  11 &cpu80_intc  9
+				&cpu81_intc  11 &cpu81_intc  9
+				&cpu82_intc  11 &cpu82_intc  9
+				&cpu83_intc  11 &cpu83_intc  9
+				&cpu84_intc  11 &cpu84_intc  9
+				&cpu85_intc  11 &cpu85_intc  9
+				&cpu86_intc  11 &cpu86_intc  9
+				&cpu87_intc  11 &cpu87_intc  9
+				&cpu88_intc  11 &cpu88_intc  9
+				&cpu89_intc  11 &cpu89_intc  9
+				&cpu90_intc  11 &cpu90_intc  9
+				&cpu91_intc  11 &cpu91_intc  9
+				&cpu92_intc  11 &cpu92_intc  9
+				&cpu93_intc  11 &cpu93_intc  9
+				&cpu94_intc  11 &cpu94_intc  9
+				&cpu95_intc  11 &cpu95_intc  9
+				&cpu96_intc  11 &cpu96_intc  9
+				&cpu97_intc  11 &cpu97_intc  9
+				&cpu98_intc  11 &cpu98_intc  9
+				&cpu99_intc  11 &cpu99_intc  9
+				&cpu100_intc  11 &cpu100_intc  9
+				&cpu101_intc  11 &cpu101_intc  9
+				&cpu102_intc  11 &cpu102_intc  9
+				&cpu103_intc  11 &cpu103_intc  9
+				&cpu104_intc  11 &cpu104_intc  9
+				&cpu105_intc  11 &cpu105_intc  9
+				&cpu106_intc  11 &cpu106_intc  9
+				&cpu107_intc  11 &cpu107_intc  9
+				&cpu108_intc  11 &cpu108_intc  9
+				&cpu109_intc  11 &cpu109_intc  9
+				&cpu110_intc  11 &cpu110_intc  9
+				&cpu111_intc  11 &cpu111_intc  9
+				&cpu112_intc  11 &cpu112_intc  9
+				&cpu113_intc  11 &cpu113_intc  9
+				&cpu114_intc  11 &cpu114_intc  9
+				&cpu115_intc  11 &cpu115_intc  9
+				&cpu116_intc  11 &cpu116_intc  9
+				&cpu117_intc  11 &cpu117_intc  9
+				&cpu118_intc  11 &cpu118_intc  9
+				&cpu119_intc  11 &cpu119_intc  9
+				&cpu120_intc  11 &cpu120_intc  9
+				&cpu121_intc  11 &cpu121_intc  9
+				&cpu122_intc  11 &cpu122_intc  9
+				&cpu123_intc  11 &cpu123_intc  9
+				&cpu124_intc  11 &cpu124_intc  9
+				&cpu125_intc  11 &cpu125_intc  9
+				&cpu126_intc  11 &cpu126_intc  9
+				&cpu127_intc  11 &cpu127_intc  9
+#endif
+				>;
+			reg = <0x00000070 0x90000000 0x00000000 0x04000000>;
+			reg-names = "control";
+			riscv,max-priority = <7>;
+			riscv,ndev = <448>;
+		};
+
+		top1_misc: top_misc_ctrl@f030010000 {
+			compatible = "syscon";
+			reg = <0xf0 0x30010000 0x0 0x8000>;
+		};
+
+		rst1: reset1-controller {
+			#reset-cells = <1>;
+			compatible = "bitmain,reset";
+			subctrl-syscon = <&top1_misc>;
+			top_rst_offset = <0x3000>;
+			nr_resets = <RST_MAX_NUM>;
+		};
+
+		gpio3: gpio@f030009000 {
+			compatible = "snps,dw-apb-gpio";
+			reg = <0xf0 0x30009000 0x0 0x400>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&s1_div_clk GATE_CLK_APB_GPIO>,
+				 <&s1_div_clk GATE_CLK_APB_GPIO_INTR>,
+				 <&s1_div_clk GATE_CLK_GPIO_DB>;
+			clock-names = "base_clk", "intr_clk", "db_clk";
+
+			port3a: gpio-controller@0 {
+				compatible = "snps,dw-apb-gpio-port";
+				bank-name = "port0a";
+				gpio-controller;
+				#gpio-cells = <2>;
+				snps,nr-gpios = <32>;
+				reg = <0>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupt-parent = <&intc>;
+				interrupts = <SOC_PERIPHERAL_IRQ(320) IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
+		ethernet1: ethernet@f040026000 {
+			compatible = "bitmain,ethernet";
+			reg = <0xf0 0x40026000 0x0 0x4000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(356) IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref";
+			clocks = <&s1_div_clk DIV_CLK_FPLL_TX_ETH0>,
+				   <&s1_div_clk GATE_CLK_TX_ETH0>,
+				   <&s1_div_clk GATE_CLK_AXI_ETH0>,
+				   <&s1_div_clk GATE_CLK_PTP_REF_I_ETH0>,
+				   <&s1_div_clk GATE_CLK_REF_ETH0>;
+
+			/* no hash filter and perfect filter support */
+			snps,multicast-filter-bins = <0>;
+			snps,perfect-filter-entries = <1>;
+
+			snps,txpbl = <32>;
+			snps,rxpbl = <32>;
+			snps,aal;
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,mtl-rx-config = <&mtl_rx_setup>;
+			snps,mtl-tx-config = <&mtl_tx_setup>;
+
+			phy-mode = "rgmii-txid";
+			phy-reset-gpios = <&port3a 27 0>;
+			phy-handle = <&phy1>;
+			mdio {
+				#address-cells = <0x1>;
+				#size-cells = <0x0>;
+				compatible = "snps,dwmac-mdio";
+				phy1: phy@0 {
+					compatible = "ethernet-phy-ieee802.3-c22";
+					device_type = "ethernet-phy";
+					reg = <0x0>;
+				};
+			};
+		};
+
+		emmc1: bm-emmc@f04002A000 {
+			compatible = "bitmain,bm-emmc";
+			reg = <0xf0 0x4002A000 0x0 0x1000>;
+			reg-names = "core_mem";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(358) IRQ_TYPE_LEVEL_HIGH>;
+			bus-width = <4>;
+			non-removable;
+			no-sdio;
+			no-sd;
+			resets = <&rst1 RST_EMMC>;
+			reset-names = "emmc";
+			clocks =
+				<&s1_div_clk GATE_CLK_EMMC_100M>,
+				<&s1_div_clk GATE_CLK_AXI_EMMC>,
+				<&s1_div_clk GATE_CLK_100K_EMMC>;
+			clock-names =
+				"clk_gate_emmc",
+				"clk_gate_axi_emmc",
+				"clk_gate_100k_emmc";
+		};
+
+		sd1: bm-sd@f04002B000 {
+			compatible = "bitmain,bm-sd";
+			reg = <0xf0 0x4002B000 0x0 0x1000>;
+			reg-names = "core_mem";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(360) IRQ_TYPE_LEVEL_HIGH>;
+			bus-width = <4>;
+			no-sdio;
+			no-mmc;
+			resets = <&rst1 RST_SD>;
+			reset-names = "sdio";
+			clocks =
+				<&s1_div_clk GATE_CLK_SD_100M>,
+				<&s1_div_clk GATE_CLK_AXI_SD>,
+				<&s1_div_clk GATE_CLK_100K_SD>;
+			clock-names =
+				"clk_gate_sd",
+				"clk_gate_axi_sd",
+				"clk_gate_100k_sd";
+		};
+	};
+
+	spifmc2: flash-controller@f000180000 {
+		compatible = "sophgo,spifmc";
+		reg = <0xf0 0x00180000 0x0 0x1000000>;
+		reg-names = "memory";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(332) IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <100000000>;
+		clocks = <&s1_div_clk GATE_CLK_AHB_SF>;
+		flash@0 {
+			reg = <0>;
+			compatible = "jedec,spi-nor";
+		};
+	};
+
+	spifmc3: flash-controller@f002180000 {
+		compatible = "sophgo,spifmc";
+		reg = <0xf0 0x02180000 0x0 0x1000000>;
+		reg-names = "memory";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(333) IRQ_TYPE_LEVEL_HIGH>;
+		clock-frequency = <100000000>;
+		clocks = <&s1_div_clk GATE_CLK_AHB_SF>;
+		flash@0 {
+			reg = <0>;
+			compatible = "jedec,spi-nor";
+		};
+	};
+
+	aliases {
+	        serial0 = &uart0;
+	        ethernet0 = &ethernet0;
+	        ethernet1 = &ethernet1;
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi
new file mode 100644
index 000000000000..af3380412f1d
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi
@@ -0,0 +1,124 @@
+/ {
+	socket0-clocks {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		cgi: ctrystal {
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+			clock-output-names = "cgi";
+			#clock-cells = <0>;
+		};
+
+		/* pll clock */
+		mpll: mpll {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <MPLL_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top_misc>;
+			clocks = <&cgi>;
+			clock-output-names = "mpll_clock";
+		};
+
+		fpll: fpll {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <FPLL_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top_misc>;
+			clocks = <&cgi>;
+			clock-output-names = "fpll_clock";
+		};
+
+		dpll0: dpll0 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <DPLL0_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top_misc>;
+			clocks = <&cgi>;
+			clock-output-names = "dpll0_clock";
+		};
+
+		dpll1: dpll1 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top_misc>;
+			clocks = <&cgi>;
+			id = <DPLL1_CLK>;
+			clock-output-names = "dpll1_clock";
+		};
+
+		div_clk: div_clk {
+			compatible = "mango, pll-child-clock";
+			#clock-cells = <1>;
+			id = <S0_DIV_CLK_TABLE>;
+			subctrl-syscon = <&top_misc>;
+		};
+
+		mux_clk: mux_clk {
+			compatible = "mango, pll-mux-clock";
+			#clock-cells = <1>;
+			id = <S0_MUX_CLK_TABLE>;
+			subctrl-syscon = <&top_misc>;
+		};
+
+		socket0_default_rates {
+			compatible = "mango, clk-default-rates";
+			#clock-cells = <1>;
+			subctrl-syscon = <&top_misc>;
+			clocks = \
+				<&mpll>, <&fpll>,
+
+				<&div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>,
+				<&div_clk DIV_CLK_FPLL_50M_A53>,
+				<&div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>,
+				<&div_clk DIV_CLK_FPLL_UART_500M>,
+				<&div_clk DIV_CLK_FPLL_AHB_LPC>,
+				<&div_clk DIV_CLK_FPLL_EFUSE>,
+				<&div_clk DIV_CLK_FPLL_TX_ETH0>,
+				<&div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>,
+				<&div_clk DIV_CLK_FPLL_REF_ETH0>,
+				<&div_clk DIV_CLK_FPLL_EMMC>,
+				<&div_clk DIV_CLK_FPLL_SD>,
+				<&div_clk DIV_CLK_FPLL_TOP_AXI0>,
+				<&div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>,
+				<&div_clk DIV_CLK_FPLL_AXI_DDR_1>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER1>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER2>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER3>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER4>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER5>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER6>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER7>,
+				<&div_clk DIV_CLK_FPLL_DIV_TIMER8>,
+				<&div_clk DIV_CLK_FPLL_100K_EMMC>,
+				<&div_clk DIV_CLK_FPLL_100K_SD>,
+				<&div_clk DIV_CLK_FPLL_GPIO_DB>,
+
+				<&div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>,
+				<&div_clk DIV_CLK_MPLL_AXI_DDR_0>;
+
+			clock-rates = \
+				<2000000000>, <1000000000>,
+
+				<2000000000>, <50000000>,
+				<1000000000>, <500000000>,
+				<200000000>, <25000000>,
+				<125000000>, <50000000>,
+				<25000000>, <100000000>,
+				<100000000>, <100000000>,
+				<250000000>, <1000000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<100000>, <100000>, <100000>,
+
+				<2000000001>, <1000000001>;
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi b/arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi
new file mode 100644
index 000000000000..cfe34495e4fd
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi
@@ -0,0 +1,124 @@
+/ {
+	socket1-clocks {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		cgi1: ctrystal1 {
+			compatible = "fixed-clock";
+			clock-frequency = <25000000>;
+			clock-output-names = "s1_cgi";
+			#clock-cells = <0>;
+		};
+
+		/* pll clock */
+		mpll1: mpll1 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <MPLL_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top1_misc>;
+			clocks = <&cgi1>;
+			clock-output-names = "s1_mpll_clock";
+		};
+
+		fpll1: fpll1 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <FPLL_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top1_misc>;
+			clocks = <&cgi1>;
+			clock-output-names = "s1_fpll_clock";
+		};
+
+		dpll01: dpll01 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			id = <DPLL0_CLK>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top1_misc>;
+			clocks = <&cgi1>;
+			clock-output-names = "s1_dpll0_clock";
+		};
+
+		dpll11: dpll11 {
+			compatible = "mango, pll-clock";
+			#clock-cells = <0>;
+			mode = <NORMAL_MODE>;
+			subctrl-syscon = <&top1_misc>;
+			clocks = <&cgi1>;
+			id = <DPLL1_CLK>;
+			clock-output-names = "s1_dpll1_clock";
+		};
+
+		s1_div_clk: s1_div_clk {
+			compatible = "mango, pll-child-clock";
+			#clock-cells = <1>;
+			id = <S1_DIV_CLK_TABLE>;
+			subctrl-syscon = <&top1_misc>;
+		};
+
+		s1_mux_clk: s1_mux_clk {
+			compatible = "mango, pll-mux-clock";
+			#clock-cells = <1>;
+			id = <S1_MUX_CLK_TABLE>;
+			subctrl-syscon = <&top1_misc>;
+		};
+
+		socket1_default_rates {
+			compatible = "mango, clk-default-rates";
+			#clock-cells = <1>;
+			subctrl-syscon = <&top1_misc>;
+			clocks = \
+				<&mpll1>, <&fpll1>,
+
+				<&s1_div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>,
+				<&s1_div_clk DIV_CLK_FPLL_50M_A53>,
+				<&s1_div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>,
+				<&s1_div_clk DIV_CLK_FPLL_UART_500M>,
+				<&s1_div_clk DIV_CLK_FPLL_AHB_LPC>,
+				<&s1_div_clk DIV_CLK_FPLL_EFUSE>,
+				<&s1_div_clk DIV_CLK_FPLL_TX_ETH0>,
+				<&s1_div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>,
+				<&s1_div_clk DIV_CLK_FPLL_REF_ETH0>,
+				<&s1_div_clk DIV_CLK_FPLL_EMMC>,
+				<&s1_div_clk DIV_CLK_FPLL_SD>,
+				<&s1_div_clk DIV_CLK_FPLL_TOP_AXI0>,
+				<&s1_div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>,
+				<&s1_div_clk DIV_CLK_FPLL_AXI_DDR_1>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER1>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER2>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER3>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER4>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER5>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER6>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER7>,
+				<&s1_div_clk DIV_CLK_FPLL_DIV_TIMER8>,
+				<&s1_div_clk DIV_CLK_FPLL_100K_EMMC>,
+				<&s1_div_clk DIV_CLK_FPLL_100K_SD>,
+				<&s1_div_clk DIV_CLK_FPLL_GPIO_DB>,
+
+				<&s1_div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>,
+				<&s1_div_clk DIV_CLK_MPLL_AXI_DDR_0>;
+
+			clock-rates = \
+				<2000000000>, <1000000000>,
+
+				<2000000000>, <50000000>,
+				<1000000000>, <500000000>,
+				<200000000>, <25000000>,
+				<125000000>, <50000000>,
+				<25000000>, <100000000>,
+				<100000000>, <100000000>,
+				<250000000>, <1000000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<50000000>, <50000000>,
+				<100000>, <100000>, <100000>,
+
+				<2000000001>, <1000000001>;
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi
new file mode 100644
index 000000000000..9165f0a658b0
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi
@@ -0,0 +1,1148 @@
+/ {
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		timebase-frequency = <50000000>;
+
+		cpu-map {
+			socket0 {
+				cluster0 {
+					 core0 {
+						cpu = <&cpu0>;
+					 };
+					 core1 {
+						cpu = <&cpu1>;
+					 };
+					 core2 {
+						cpu = <&cpu2>;
+					 };
+					 core3 {
+						cpu = <&cpu3>;
+					 };
+				};
+
+				cluster1 {
+					 core0 {
+						cpu = <&cpu4>;
+					 };
+					 core1 {
+						cpu = <&cpu5>;
+					 };
+					 core2 {
+						cpu = <&cpu6>;
+					 };
+					 core3 {
+						cpu = <&cpu7>;
+					 };
+				};
+
+				cluster2 {
+					 core0 {
+						cpu = <&cpu16>;
+					 };
+					 core1 {
+						cpu = <&cpu17>;
+					 };
+					 core2 {
+						cpu = <&cpu18>;
+					 };
+					 core3 {
+						cpu = <&cpu19>;
+					 };
+				};
+
+				cluster3 {
+					 core0 {
+						cpu = <&cpu20>;
+					 };
+					 core1 {
+						cpu = <&cpu21>;
+					 };
+					 core2 {
+						cpu = <&cpu22>;
+					 };
+					 core3 {
+						cpu = <&cpu23>;
+					 };
+				};
+
+				cluster4 {
+					 core0 {
+						cpu = <&cpu8>;
+					 };
+					 core1 {
+						cpu = <&cpu9>;
+					 };
+					 core2 {
+						cpu = <&cpu10>;
+					 };
+					 core3 {
+						cpu = <&cpu11>;
+					 };
+				};
+
+				cluster5 {
+					 core0 {
+						cpu = <&cpu12>;
+					 };
+					 core1 {
+						cpu = <&cpu13>;
+					 };
+					 core2 {
+						cpu = <&cpu14>;
+					 };
+					 core3 {
+						cpu = <&cpu15>;
+					 };
+				};
+
+				cluster6 {
+					 core0 {
+						cpu = <&cpu24>;
+					 };
+					 core1 {
+						cpu = <&cpu25>;
+					 };
+					 core2 {
+						cpu = <&cpu26>;
+					 };
+					 core3 {
+						cpu = <&cpu27>;
+					 };
+				};
+
+				cluster7 {
+					 core0 {
+						cpu = <&cpu28>;
+					 };
+					 core1 {
+						cpu = <&cpu29>;
+					 };
+					 core2 {
+						cpu = <&cpu30>;
+					 };
+					 core3 {
+						cpu = <&cpu31>;
+					 };
+				};
+
+				cluster8 {
+					 core0 {
+						cpu = <&cpu32>;
+					 };
+					 core1 {
+						cpu = <&cpu33>;
+					 };
+					 core2 {
+						cpu = <&cpu34>;
+					 };
+					 core3 {
+						cpu = <&cpu35>;
+					 };
+				};
+
+				cluster9 {
+					 core0 {
+						cpu = <&cpu36>;
+					 };
+					 core1 {
+						cpu = <&cpu37>;
+					 };
+					 core2 {
+						cpu = <&cpu38>;
+					 };
+					 core3 {
+						cpu = <&cpu39>;
+					 };
+				};
+
+				cluster10 {
+					 core0 {
+						cpu = <&cpu48>;
+					 };
+					 core1 {
+						cpu = <&cpu49>;
+					 };
+					 core2 {
+						cpu = <&cpu50>;
+					 };
+					 core3 {
+						cpu = <&cpu51>;
+					 };
+				};
+
+				cluster11 {
+					 core0 {
+						cpu = <&cpu52>;
+					 };
+					 core1 {
+						cpu = <&cpu53>;
+					 };
+					 core2 {
+						cpu = <&cpu54>;
+					 };
+					 core3 {
+						cpu = <&cpu55>;
+					 };
+				};
+
+				cluster12 {
+					 core0 {
+						cpu = <&cpu40>;
+					 };
+					 core1 {
+						cpu = <&cpu41>;
+					 };
+					 core2 {
+						cpu = <&cpu42>;
+					 };
+					 core3 {
+						cpu = <&cpu43>;
+					 };
+				};
+
+				cluster13 {
+					 core0 {
+						cpu = <&cpu44>;
+					 };
+					 core1 {
+						cpu = <&cpu45>;
+					 };
+					 core2 {
+						cpu = <&cpu46>;
+					 };
+					 core3 {
+						cpu = <&cpu47>;
+					 };
+				};
+
+				cluster14 {
+					 core0 {
+						cpu = <&cpu56>;
+					 };
+					 core1 {
+						cpu = <&cpu57>;
+					 };
+					 core2 {
+						cpu = <&cpu58>;
+					 };
+					 core3 {
+						cpu = <&cpu59>;
+					 };
+				};
+
+				cluster15 {
+					 core0 {
+						cpu = <&cpu60>;
+					 };
+					 core1 {
+						cpu = <&cpu61>;
+					 };
+					 core2 {
+						cpu = <&cpu62>;
+					 };
+					 core3 {
+						cpu = <&cpu63>;
+					 };
+				};
+			};
+		};
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			reg = <0>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu0_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			reg = <1>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu1_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			reg = <2>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu2_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			reg = <3>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu3_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu4: cpu@4 {
+			device_type = "cpu";
+			reg = <4>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu4_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu5: cpu@5 {
+			device_type = "cpu";
+			reg = <5>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu5_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu6: cpu@6 {
+			device_type = "cpu";
+			reg = <6>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu6_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu7: cpu@7 {
+			device_type = "cpu";
+			reg = <7>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu7_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu8: cpu@8 {
+			device_type = "cpu";
+			reg = <8>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu8_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu9: cpu@9 {
+			device_type = "cpu";
+			reg = <9>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu9_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu10: cpu@10 {
+			device_type = "cpu";
+			reg = <10>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu10_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu11: cpu@11 {
+			device_type = "cpu";
+			reg = <11>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu11_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu12: cpu@12 {
+			device_type = "cpu";
+			reg = <12>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu12_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu13: cpu@13 {
+			device_type = "cpu";
+			reg = <13>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu13_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu14: cpu@14 {
+			device_type = "cpu";
+			reg = <14>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu14_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu15: cpu@15 {
+			device_type = "cpu";
+			reg = <15>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu15_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu16: cpu@16 {
+			device_type = "cpu";
+			reg = <16>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu16_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu17: cpu@17 {
+			device_type = "cpu";
+			reg = <17>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu17_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu18: cpu@18 {
+			device_type = "cpu";
+			reg = <18>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu18_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu19: cpu@19 {
+			device_type = "cpu";
+			reg = <19>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu19_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu20: cpu@20 {
+			device_type = "cpu";
+			reg = <20>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu20_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu21: cpu@21 {
+			device_type = "cpu";
+			reg = <21>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu21_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu22: cpu@22 {
+			device_type = "cpu";
+			reg = <22>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu22_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu23: cpu@23 {
+			device_type = "cpu";
+			reg = <23>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <0>;
+			cpu23_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu24: cpu@24 {
+			device_type = "cpu";
+			reg = <24>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu24_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu25: cpu@25 {
+			device_type = "cpu";
+			reg = <25>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu25_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu26: cpu@26 {
+			device_type = "cpu";
+			reg = <26>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu26_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu27: cpu@27 {
+			device_type = "cpu";
+			reg = <27>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu27_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu28: cpu@28 {
+			device_type = "cpu";
+			reg = <28>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu28_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu29: cpu@29 {
+			device_type = "cpu";
+			reg = <29>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu29_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu30: cpu@30 {
+			device_type = "cpu";
+			reg = <30>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu30_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu31: cpu@31 {
+			device_type = "cpu";
+			reg = <31>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <1>;
+			cpu31_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu32: cpu@32 {
+			device_type = "cpu";
+			reg = <32>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu32_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu33: cpu@33 {
+			device_type = "cpu";
+			reg = <33>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu33_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu34: cpu@34 {
+			device_type = "cpu";
+			reg = <34>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu34_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu35: cpu@35 {
+			device_type = "cpu";
+			reg = <35>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu35_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu36: cpu@36 {
+			device_type = "cpu";
+			reg = <36>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu36_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu37: cpu@37 {
+			device_type = "cpu";
+			reg = <37>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu37_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu38: cpu@38 {
+			device_type = "cpu";
+			reg = <38>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu38_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu39: cpu@39 {
+			device_type = "cpu";
+			reg = <39>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu39_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu40: cpu@40 {
+			device_type = "cpu";
+			reg = <40>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu40_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu41: cpu@41 {
+			device_type = "cpu";
+			reg = <41>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu41_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu42: cpu@42 {
+			device_type = "cpu";
+			reg = <42>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu42_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu43: cpu@43 {
+			device_type = "cpu";
+			reg = <43>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu43_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu44: cpu@44 {
+			device_type = "cpu";
+			reg = <44>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu44_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu45: cpu@45 {
+			device_type = "cpu";
+			reg = <45>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu45_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu46: cpu@46 {
+			device_type = "cpu";
+			reg = <46>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu46_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu47: cpu@47 {
+			device_type = "cpu";
+			reg = <47>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu47_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu48: cpu@48 {
+			device_type = "cpu";
+			reg = <48>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu48_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu49: cpu@49 {
+			device_type = "cpu";
+			reg = <49>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu49_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu50: cpu@50 {
+			device_type = "cpu";
+			reg = <50>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu50_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu51: cpu@51 {
+			device_type = "cpu";
+			reg = <51>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu51_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu52: cpu@52 {
+			device_type = "cpu";
+			reg = <52>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu52_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu53: cpu@53 {
+			device_type = "cpu";
+			reg = <53>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu53_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu54: cpu@54 {
+			device_type = "cpu";
+			reg = <54>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu54_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu55: cpu@55 {
+			device_type = "cpu";
+			reg = <55>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <2>;
+			cpu55_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu56: cpu@56 {
+			device_type = "cpu";
+			reg = <56>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu56_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu57: cpu@57 {
+			device_type = "cpu";
+			reg = <57>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu57_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu58: cpu@58 {
+			device_type = "cpu";
+			reg = <58>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu58_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu59: cpu@59 {
+			device_type = "cpu";
+			reg = <59>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu59_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu60: cpu@60 {
+			device_type = "cpu";
+			reg = <60>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu60_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu61: cpu@61 {
+			device_type = "cpu";
+			reg = <61>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu61_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu62: cpu@62 {
+			device_type = "cpu";
+			reg = <62>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu62_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu63: cpu@63 {
+			device_type = "cpu";
+			reg = <63>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <3>;
+			cpu63_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi
new file mode 100644
index 000000000000..a6d2b439177b
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi
@@ -0,0 +1,1149 @@
+/ {
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		timebase-frequency = <50000000>;
+
+		cpu-map {
+			socket1 {
+				cluster0 {
+					 core0 {
+						cpu = <&cpu64>;
+					 };
+					 core1 {
+						cpu = <&cpu65>;
+					 };
+					 core2 {
+						cpu = <&cpu66>;
+					 };
+					 core3 {
+						cpu = <&cpu67>;
+					 };
+				};
+
+				cluster1 {
+					 core0 {
+						cpu = <&cpu68>;
+					 };
+					 core1 {
+						cpu = <&cpu69>;
+					 };
+					 core2 {
+						cpu = <&cpu70>;
+					 };
+					 core3 {
+						cpu = <&cpu71>;
+					 };
+				};
+
+				cluster2 {
+					 core0 {
+						cpu = <&cpu80>;
+					 };
+					 core1 {
+						cpu = <&cpu81>;
+					 };
+					 core2 {
+						cpu = <&cpu82>;
+					 };
+					 core3 {
+						cpu = <&cpu83>;
+					 };
+				};
+
+				cluster3 {
+					 core0 {
+						cpu = <&cpu84>;
+					 };
+					 core1 {
+						cpu = <&cpu85>;
+					 };
+					 core2 {
+						cpu = <&cpu86>;
+					 };
+					 core3 {
+						cpu = <&cpu87>;
+					 };
+				};
+
+				cluster4 {
+					 core0 {
+						cpu = <&cpu72>;
+					 };
+					 core1 {
+						cpu = <&cpu73>;
+					 };
+					 core2 {
+						cpu = <&cpu74>;
+					 };
+					 core3 {
+						cpu = <&cpu75>;
+					 };
+				};
+
+				cluster5 {
+					 core0 {
+						cpu = <&cpu76>;
+					 };
+					 core1 {
+						cpu = <&cpu77>;
+					 };
+					 core2 {
+						cpu = <&cpu78>;
+					 };
+					 core3 {
+						cpu = <&cpu79>;
+					 };
+				};
+
+				cluster6 {
+					 core0 {
+						cpu = <&cpu88>;
+					 };
+					 core1 {
+						cpu = <&cpu89>;
+					 };
+					 core2 {
+						cpu = <&cpu90>;
+					 };
+					 core3 {
+						cpu = <&cpu91>;
+					 };
+				};
+
+				cluster7 {
+					 core0 {
+						cpu = <&cpu92>;
+					 };
+					 core1 {
+						cpu = <&cpu93>;
+					 };
+					 core2 {
+						cpu = <&cpu94>;
+					 };
+					 core3 {
+						cpu = <&cpu95>;
+					 };
+				};
+
+				cluster8 {
+					 core0 {
+						cpu = <&cpu96>;
+					 };
+					 core1 {
+						cpu = <&cpu97>;
+					 };
+					 core2 {
+						cpu = <&cpu98>;
+					 };
+					 core3 {
+						cpu = <&cpu99>;
+					 };
+				};
+
+				cluster9 {
+					 core0 {
+						cpu = <&cpu100>;
+					 };
+					 core1 {
+						cpu = <&cpu101>;
+					 };
+					 core2 {
+						cpu = <&cpu102>;
+					 };
+					 core3 {
+						cpu = <&cpu103>;
+					 };
+				};
+
+				cluster10 {
+					 core0 {
+						cpu = <&cpu112>;
+					 };
+					 core1 {
+						cpu = <&cpu113>;
+					 };
+					 core2 {
+						cpu = <&cpu114>;
+					 };
+					 core3 {
+						cpu = <&cpu115>;
+					 };
+				};
+
+				cluster11 {
+					 core0 {
+						cpu = <&cpu116>;
+					 };
+					 core1 {
+						cpu = <&cpu117>;
+					 };
+					 core2 {
+						cpu = <&cpu118>;
+					 };
+					 core3 {
+						cpu = <&cpu119>;
+					 };
+				};
+
+				cluster12 {
+					 core0 {
+						cpu = <&cpu104>;
+					 };
+					 core1 {
+						cpu = <&cpu105>;
+					 };
+					 core2 {
+						cpu = <&cpu106>;
+					 };
+					 core3 {
+						cpu = <&cpu107>;
+					 };
+				};
+
+				cluster13 {
+					 core0 {
+						cpu = <&cpu108>;
+					 };
+					 core1 {
+						cpu = <&cpu109>;
+					 };
+					 core2 {
+						cpu = <&cpu110>;
+					 };
+					 core3 {
+						cpu = <&cpu111>;
+					 };
+				};
+
+				cluster14 {
+					 core0 {
+						cpu = <&cpu120>;
+					 };
+					 core1 {
+						cpu = <&cpu121>;
+					 };
+					 core2 {
+						cpu = <&cpu122>;
+					 };
+					 core3 {
+						cpu = <&cpu123>;
+					 };
+				};
+
+				cluster15 {
+					 core0 {
+						cpu = <&cpu124>;
+					 };
+					 core1 {
+						cpu = <&cpu125>;
+					 };
+					 core2 {
+						cpu = <&cpu126>;
+					 };
+					 core3 {
+						cpu = <&cpu127>;
+					 };
+				};
+			};
+		};
+
+
+		cpu64: cpu@64 {
+			device_type = "cpu";
+			reg = <64>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu64_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu65: cpu@65 {
+			device_type = "cpu";
+			reg = <65>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu65_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu66: cpu@66 {
+			device_type = "cpu";
+			reg = <66>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu66_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu67: cpu@67 {
+			device_type = "cpu";
+			reg = <67>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu67_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu68: cpu@68 {
+			device_type = "cpu";
+			reg = <68>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu68_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu69: cpu@69 {
+			device_type = "cpu";
+			reg = <69>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu69_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu70: cpu@70 {
+			device_type = "cpu";
+			reg = <70>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu70_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu71: cpu@71 {
+			device_type = "cpu";
+			reg = <71>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu71_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu72: cpu@72 {
+			device_type = "cpu";
+			reg = <72>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu72_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu73: cpu@73 {
+			device_type = "cpu";
+			reg = <73>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu73_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu74: cpu@74 {
+			device_type = "cpu";
+			reg = <74>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu74_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu75: cpu@75 {
+			device_type = "cpu";
+			reg = <75>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu75_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu76: cpu@76 {
+			device_type = "cpu";
+			reg = <76>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu76_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu77: cpu@77 {
+			device_type = "cpu";
+			reg = <77>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu77_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu78: cpu@78 {
+			device_type = "cpu";
+			reg = <78>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu78_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu79: cpu@79 {
+			device_type = "cpu";
+			reg = <79>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu79_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu80: cpu@80 {
+			device_type = "cpu";
+			reg = <80>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu80_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu81: cpu@81 {
+			device_type = "cpu";
+			reg = <81>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu81_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu82: cpu@82 {
+			device_type = "cpu";
+			reg = <82>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu82_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu83: cpu@83 {
+			device_type = "cpu";
+			reg = <83>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu83_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu84: cpu@84 {
+			device_type = "cpu";
+			reg = <84>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu84_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu85: cpu@85 {
+			device_type = "cpu";
+			reg = <85>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu85_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu86: cpu@86 {
+			device_type = "cpu";
+			reg = <86>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu86_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu87: cpu@87 {
+			device_type = "cpu";
+			reg = <87>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <4>;
+			cpu87_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu88: cpu@88 {
+			device_type = "cpu";
+			reg = <88>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu88_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu89: cpu@89 {
+			device_type = "cpu";
+			reg = <89>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu89_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu90: cpu@90 {
+			device_type = "cpu";
+			reg = <90>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu90_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu91: cpu@91 {
+			device_type = "cpu";
+			reg = <91>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu91_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu92: cpu@92 {
+			device_type = "cpu";
+			reg = <92>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu92_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu93: cpu@93 {
+			device_type = "cpu";
+			reg = <93>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu93_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu94: cpu@94 {
+			device_type = "cpu";
+			reg = <94>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu94_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu95: cpu@95 {
+			device_type = "cpu";
+			reg = <95>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <5>;
+			cpu95_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu96: cpu@96 {
+			device_type = "cpu";
+			reg = <96>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu96_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu97: cpu@97 {
+			device_type = "cpu";
+			reg = <97>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu97_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu98: cpu@98 {
+			device_type = "cpu";
+			reg = <98>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu98_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu99: cpu@99 {
+			device_type = "cpu";
+			reg = <99>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu99_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu100: cpu@100 {
+			device_type = "cpu";
+			reg = <100>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu100_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu101: cpu@101 {
+			device_type = "cpu";
+			reg = <101>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu101_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu102: cpu@102 {
+			device_type = "cpu";
+			reg = <102>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu102_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu103: cpu@103 {
+			device_type = "cpu";
+			reg = <103>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu103_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu104: cpu@104 {
+			device_type = "cpu";
+			reg = <104>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu104_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu105: cpu@105 {
+			device_type = "cpu";
+			reg = <105>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu105_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu106: cpu@106 {
+			device_type = "cpu";
+			reg = <106>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu106_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu107: cpu@107 {
+			device_type = "cpu";
+			reg = <107>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu107_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu108: cpu@108 {
+			device_type = "cpu";
+			reg = <108>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu108_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu109: cpu@109 {
+			device_type = "cpu";
+			reg = <109>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu109_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu110: cpu@110 {
+			device_type = "cpu";
+			reg = <110>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu110_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu111: cpu@111 {
+			device_type = "cpu";
+			reg = <111>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu111_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu112: cpu@112 {
+			device_type = "cpu";
+			reg = <112>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu112_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu113: cpu@113 {
+			device_type = "cpu";
+			reg = <113>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu113_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu114: cpu@114 {
+			device_type = "cpu";
+			reg = <114>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu114_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu115: cpu@115 {
+			device_type = "cpu";
+			reg = <115>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu115_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu116: cpu@116 {
+			device_type = "cpu";
+			reg = <116>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu116_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu117: cpu@117 {
+			device_type = "cpu";
+			reg = <117>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu117_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu118: cpu@118 {
+			device_type = "cpu";
+			reg = <118>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu118_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu119: cpu@119 {
+			device_type = "cpu";
+			reg = <119>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <6>;
+			cpu119_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu120: cpu@120 {
+			device_type = "cpu";
+			reg = <120>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu120_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu121: cpu@121 {
+			device_type = "cpu";
+			reg = <121>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu121_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu122: cpu@122 {
+			device_type = "cpu";
+			reg = <122>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu122_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu123: cpu@123 {
+			device_type = "cpu";
+			reg = <123>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu123_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu124: cpu@124 {
+			device_type = "cpu";
+			reg = <124>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu124_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu125: cpu@125 {
+			device_type = "cpu";
+			reg = <125>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu125_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu126: cpu@126 {
+			device_type = "cpu";
+			reg = <126>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu126_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+		cpu127: cpu@127 {
+			device_type = "cpu";
+			reg = <127>;
+			status = "okay";
+			compatible = "riscv";
+			riscv,isa = "rv64imafdcv";
+			mmu-type = "riscv,sv39";
+			numa-node-id = <7>;
+			cpu127_intc: interrupt-controller {
+				#interrupt-cells = <1>;
+				compatible = "riscv,cpu-intc";
+				interrupt-controller;
+			};
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts
new file mode 100644
index 000000000000..00f2d5e2c674
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts
@@ -0,0 +1,163 @@
+#include "mango.dtsi"
+#include "mango-pcie-4rc.dtsi"
+
+/ {
+	info {
+		file-name = "mango-milkv-pioneer.dts";
+	};
+};
+
+&i2c1 {
+	mcu: sg2042mcu@17 {
+		compatible = "sophgo,sg20xx-mcu";
+		reg = <0x17>;
+		#thermal-sensor-cells = <1>;
+	};
+
+	mango_srst: mango-reset@17 {
+		compatible = "mango,reset";
+		reg = <0x17>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_acquire>;
+};
+
+&soc {
+	/delete-node/ ethernet@7040026000;
+	gpio-poweroff {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pwr_key>;
+
+		power {
+			label = "GPIO Key Power";
+			linux,code = <KEY_POWER>;
+			gpios = <&port0a 22 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+
+	gpio-restart {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&restart_key>;
+
+		restart {
+			label = "GPIO Key Restart";
+			linux,code = <KEY_RESTART>;
+			gpios = <&port0a 23 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+};
+
+&tach0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan0_acquire>;
+};
+
+&tach1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan1_acquire>;
+};
+
+/ {
+	pwmfan: pwm-fan {
+		compatible = "pwm-fan";
+		pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns
+		pwm-names = "pwm0","pwm1";
+		pwm_inuse = "pwm0";
+		#cooling-cells = <2>;
+		cooling-levels = <1 1 1 1 1>;  //total 255
+	};
+
+	thermal_zones: thermal-zones {
+		soc {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 0>;
+
+			trips {
+				soc_pwmfan_trip1: soc_pwmfan_trip@1 {
+					temperature = <30000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip2: soc_pwmfan_trip@2 {
+					temperature = <40000>; /* millicelsius */
+					hysteresis = <12000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip3: soc_pwmfan_trip@3 {
+					temperature = <50000>; /* millicelsius */
+					hysteresis = <10000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip4: soc_pwmfan_trip@4 {
+					temperature = <60000>; /* millicelsius */
+					hysteresis = <5000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&soc_pwmfan_trip1>;
+					cooling-device = <&pwmfan 0 1>;
+				};
+
+				map1 {
+					trip = <&soc_pwmfan_trip2>;
+					cooling-device = <&pwmfan 1 2>;
+				};
+
+				map2 {
+					trip = <&soc_pwmfan_trip3>;
+					cooling-device = <&pwmfan 2 3>;
+				};
+
+				map3 {
+					trip = <&soc_pwmfan_trip4>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+
+		};
+
+		board {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 1>;
+
+			trips {
+				board_pwmfan_trip1: board_pwmfan_trip@1 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map4 {
+					trip = <&board_pwmfan_trip1>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+		};
+	};
+
+};
+
+&chosen {
+	bootargs = "console=ttyS0,115200 console=tty1 earlycon maxcpus=1";
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi
new file mode 100644
index 000000000000..e39b3a80bf06
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi
@@ -0,0 +1,81 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x00 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <1>;
+		interrupt-parent = <&intc1>;
+		//interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
+		//interrupt-names = "msi";
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0000000  0x48 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@f060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xff>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <1>;
+		top-intc-id = <1>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc2>;
+		//interrupts = <SOC_PERIPHERAL_IRQ(346) IRQ_TYPE_LEVEL_HIGH>;
+		//interrupt-names = "msi";
+		reg = <0xf0 0x60000000  0x0 0x02000000>,
+		      <0xc0 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0800000  0xc0 0xc0800000  0x0 0x00800000>,
+			 <0x42000000 0x0  0xd0000000  0xc0 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0xc0 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0xc2 0x00000000  0xc2 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0xc1 0x00000000  0xc1 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi
new file mode 100644
index 000000000000..776889585272
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi
@@ -0,0 +1,116 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x0 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x70 0x60000000  0x0 0x02000000>,
+		      <0x40 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0000000  0x40 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x40 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x40 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x42 0x00000000  0x42 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x41 0x00000000  0x41 0x00000000  0x1 0x00000000>;
+		//dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>;
+
+		status = "okay";
+	};
+
+	pcie@7060800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x40 0x7f>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <0>;
+		top-intc-id = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x44 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0400000  0x44 0xc0400000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xe0000000  0x44 0xe0000000  0x0 0x20000000>,
+			 <0x02000000 0x0  0xd0000000  0x44 0xd0000000  0x0 0x10000000>,
+			 <0x43000000 0x46 0x00000000  0x46 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x45 0x00000000  0x45 0x00000000  0x1 0x00000000>;
+		//dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>;
+
+		status = "okay";
+	};
+
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xff>;
+		linux,pci-domain = <2>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0800000  0x48 0xc0800000  0x0 0x00800000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>;
+		//dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi
new file mode 100644
index 000000000000..9c4c9641e1c0
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi
@@ -0,0 +1,115 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x0 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		top-intc-id = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x60000000  0x0 0x02000000>,
+		      <0x40 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0000000  0x40 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x40 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x40 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x42 0x00000000  0x42 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x41 0x00000000  0x41 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7060800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x40 0x7f>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		//interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
+		//interrupt-names = "msi";
+		reg = <0x44 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0400000  0x44 0xc0400000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xe0000000  0x44 0xe0000000  0x0 0x20000000>,
+			 <0x02000000 0x0  0xd0000000  0x44 0xd0000000  0x0 0x10000000>,
+			 <0x43000000 0x46 0x00000000  0x46 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x45 0x00000000  0x45 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xff>;
+		linux,pci-domain = <2>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0800000  0x48 0xc0800000  0x0 0x00800000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi
new file mode 100644
index 000000000000..63fb41b43809
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi
@@ -0,0 +1,112 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x0 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x60000000  0x0 0x02000000>,
+		      <0x40 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0000000  0x40 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x40 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x40 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x42 0x00000000  0x42 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x41 0x00000000  0x41 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7060800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x40 0x7f>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x44 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0400000  0x44 0xc0400000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x44 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x44 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x46 0x00000000  0x46 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x45 0x00000000  0x45 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xff>;
+		linux,pci-domain = <2>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0800000  0x48 0xc0800000  0x0 0x00800000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>,
+			 <0x03000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi
new file mode 100644
index 000000000000..efbcc5c04740
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi
@@ -0,0 +1,155 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x00 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		/*
+		 * IO, check IO_SPACE_LIMIT
+		 * 32bit prefetchable memory
+		 * 32bit non-prefetchable memory
+		 * 64bit prefetchable memory
+		 * 64bit non-prefetchable memory
+		 */
+		ranges = <0x01000000 0x0  0xc0000000  0x48 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7062800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x40 0x7f>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x4c 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		/*
+		 * IO, check IO_SPACE_LIMIT
+		 * 32bit prefetchable memory
+		 * 32bit non-prefetchable memory
+		 * 64bit prefetchable memory
+		 * 64bit non-prefetchable memory
+		 */
+		ranges = <0x01000000 0x0  0xc0000000  0x4c 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x4c 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x4c 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x4e 0x00000000  0x4e 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x4d 0x00000000  0x4d 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@f060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xbf>;
+		linux,pci-domain = <2>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <1>;
+		top-intc-id = <1>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc2>;
+		reg = <0xf0 0x60000000  0x0 0x02000000>,
+		      <0xc0 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		/*
+		 * IO, check IO_SPACE_LIMIT
+		 * 32bit prefetchable memory
+		 * 32bit non-prefetchable memory
+		 * 64bit prefetchable memory
+		 * 64bit non-prefetchable memory
+		 */
+		ranges = <0x01000000 0x0  0xc0000000  0xc0 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0xc0 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0xc0 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0xc2 0x00000000  0xc2 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0xc1 0x00000000  0xc1 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+	
+	pcie@f068000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0xc0 0xff>;
+		linux,pci-domain = <3>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <1>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc2>;
+		reg = <0xc4 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		/*
+		 * IO, check IO_SPACE_LIMIT
+		 * 32bit prefetchable memory
+		 * 32bit non-prefetchable memory
+		 * 64bit prefetchable memory
+		 * 64bit non-prefetchable memory
+		 */
+		ranges = <0x01000000 0x0  0xc0000000  0xc4 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0xc4 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0xc4 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0xc6 0x00000000  0xc6 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0xc5 0x00000000  0xc5 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi
new file mode 100644
index 000000000000..f17ef8d494a5
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi
@@ -0,0 +1,147 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	pcie@7060000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x0 0x3f>;
+		linux,pci-domain = <0>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x60000000  0x0 0x02000000>,
+		      <0x40 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0000000  0x40 0xc0000000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x40 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x40 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x42 0x00000000  0x42 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x41 0x00000000  0x41 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7060800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x40 0x7f>;
+		linux,pci-domain = <1>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x0>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x44 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0400000  0x44 0xc0400000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x44 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x44 0xe0000000  0x0 0x20000000>,
+			 <0x43000000 0x46 0x00000000  0x46 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x45 0x00000000  0x45 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7062000000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0x80 0xbf>;
+		linux,pci-domain = <2>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x0>;
+		top-intc-used = <0>;
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi";
+		reg = <0x70 0x62000000  0x0 0x02000000>,
+		      <0x48 0x00000000  0x0 0x00001000>;
+		reg-names = "reg", "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0800000  0x48 0xc0800000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xd0000000  0x48 0xd0000000  0x0 0x10000000>,
+			 <0x02000000 0x0  0xe0000000  0x48 0xe0000000  0x0 0x20000000>,
+			 <0x03000000 0x49 0x00000000  0x49 0x00000000  0x1 0x00000000>,
+			 <0x43000000 0x4a 0x00000000  0x4a 0x00000000  0x2 0x00000000>;
+
+		status = "okay";
+	};
+
+	pcie@7062800000 {
+		compatible = "sophgo,cdns-pcie-host";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		bus-range = <0xc0 0xff>;
+		linux,pci-domain = <3>;
+		cdns,max-outbound-regions = <16>;
+		cdns,no-bar-match-nbits = <48>;
+		vendor-id = /bits/ 16 <0x1E30>;
+		device-id = /bits/ 16 <0x2042>;
+		pcie-id = /bits/ 16 <0x1>;
+		link-id = /bits/ 16 <0x1>;
+		top-intc-used = <1>;
+		top-intc-id = <0>;
+		msix-supported = <0>;
+		interrupt-parent = <&intc1>;
+		reg = <0x4c 0x00000000  0x0 0x00001000>;
+		reg-names = "cfg";
+
+		// IO, check IO_SPACE_LIMIT
+		// 32bit prefetchable memory
+		// 32bit non-prefetchable memory
+		// 64bit prefetchable memory
+		// 64bit non-prefetchable memory
+		ranges = <0x01000000 0x0  0xc0c00000  0x4c 0xc0c00000  0x0 0x00400000>,
+			 <0x42000000 0x0  0xf8000000  0x4c 0xf8000000  0x0 0x04000000>,
+			 <0x02000000 0x0  0xfc000000  0x4c 0xfc000000  0x0 0x04000000>,
+			 <0x43000000 0x4e 0x00000000  0x4e 0x00000000  0x2 0x00000000>,
+			 <0x03000000 0x4d 0x00000000  0x4d 0x00000000  0x1 0x00000000>;
+
+		status = "okay";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi
new file mode 100644
index 000000000000..f3fb2e39af26
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi
@@ -0,0 +1,434 @@
+/ {
+	bmpctrl: pinctrl@50010400 {
+		compatible = "sophgo, pinctrl-mango";
+		subctrl-syscon = <&top_misc>;
+		top_pinctl_offset = <0x1000>;
+
+		lpc_acquire: lpc_acquire {
+			mux {
+				groups = "lpc_grp";
+				function = "lpc_a";
+			};
+		};
+
+		lpc_release: lpc_release{
+			mux {
+				groups = "lpc_grp";
+				function = "lpc_r";
+			};
+		};
+
+		pcie_acquire: pcie_acquire {
+			mux {
+				groups = "pcie_grp";
+				function = "pcie_a";
+			};
+		};
+
+		pcie_release: pcie_release{
+			mux {
+				groups = "pcie_grp";
+				function = "pcie_r";
+			};
+		};
+
+		spif_acquire: spif_acquire {
+			mux {
+				groups = "spif_grp";
+				function = "spif_a";
+			};
+		};
+
+		spif_release: spif_release{
+			mux {
+				groups = "spif_grp";
+				function = "spif_r";
+			};
+		};
+
+		emmc_acquire: emmc_acquire {
+			mux {
+				groups = "emmc_grp";
+				function = "emmc_a";
+			};
+		};
+
+		emmc_release: emmc_release{
+			mux {
+				groups = "emmc_grp";
+				function = "emmc_r";
+			};
+		};
+
+		sdio_acquire: sdio_acquire {
+			mux {
+				groups = "sdio_grp";
+				function = "sdio_a";
+			};
+		};
+
+		sdio_release: sdio_release{
+			mux {
+				groups = "sdio_grp";
+				function = "sdio_r";
+			};
+		};
+
+		eth0_acquire: eth0_acquire {
+			mux {
+				groups = "eth0_grp";
+				function = "eth0_a";
+			};
+		};
+
+		eth0_release: eth0_release{
+			mux {
+				groups = "eth0_grp";
+				function = "eth0_r";
+			};
+		};
+
+		pwm0_acquire: pwm0_acquire {
+			mux {
+				groups = "pwm0_grp";
+				function = "pwm0_a";
+			};
+		};
+
+		pwm0_release: pwm0_release{
+			mux {
+				groups = "pwm0_grp";
+				function = "pwm0_r";
+			};
+		};
+
+		pwm1_acquire: pwm1_acquire {
+			mux {
+				groups = "pwm1_grp";
+				function = "pwm1_a";
+			};
+		};
+
+		pwm1_release: pwm1_release{
+			mux {
+				groups = "pwm1_grp";
+				function = "pwm1_r";
+			};
+		};
+
+		pwm2_acquire: pwm2_acquire {
+			mux {
+				groups = "pwm2_grp";
+				function = "pwm2_a";
+			};
+		};
+
+		pwm2_release: pwm2_release{
+			mux {
+				groups = "pwm2_grp";
+				function = "pwm2_r";
+			};
+		};
+
+		pwm3_acquire: pwm3_acquire {
+			mux {
+				groups = "pwm3_grp";
+				function = "pwm3_a";
+			};
+		};
+
+		pwm3_release: pwm3_release{
+			mux {
+				groups = "pwm3_grp";
+				function = "pwm3_r";
+			};
+		};
+
+		fan0_acquire: fan0_acquire {
+			mux {
+				groups = "fan0_grp";
+				function = "fan0_a";
+			};
+		};
+
+		fan0_release: fan0_release{
+			mux {
+				groups = "fan0_grp";
+				function = "fan0_r";
+			};
+		};
+
+		fan1_acquire: fan1_acquire {
+			mux {
+				groups = "fan1_grp";
+				function = "fan1_a";
+			};
+		};
+
+		fan1_release: fan1_release{
+			mux {
+				groups = "fan1_grp";
+				function = "fan1_r";
+			};
+		};
+
+		fan2_acquire: fan2_acquire {
+			mux {
+				groups = "fan2_grp";
+				function = "fan2_a";
+			};
+		};
+
+		fan2_release: fan2_release{
+			mux {
+				roups = "fan2_grp";
+				function = "fan2_r";
+			};
+		};
+
+		fan3_acquire: fan3_acquire {
+			mux {
+				groups = "fan3_grp";
+				function = "fan3_a";
+			};
+		};
+
+		fan3_release: fan3_release{
+			mux {
+				groups = "fan3_grp";
+				function = "fan3_r";
+			};
+		};
+
+		i2c0_acquire: i2c0_acquire {
+			mux {
+				groups = "i2c0_grp";
+				function = "i2c0_a";
+			};
+		};
+
+		i2c0_release: i2c0_release{
+			mux {
+				groups = "i2c0_grp";
+				function = "i2c0_r";
+			};
+		};
+
+		i2c1_acquire: i2c1_acquire {
+			mux {
+				groups = "i2c1_grp";
+				function = "i2c1_a";
+			};
+		};
+
+		i2c1_release: i2c1_release{
+			mux {
+				groups = "i2c1_grp";
+				function = "i2c1_r";
+			};
+		};
+
+		i2c2_acquire: i2c2_acquire {
+			mux {
+				groups = "i2c2_grp";
+				function = "i2c2_a";
+			};
+		};
+
+		i2c2_release: i2c2_release{
+			mux {
+				groups = "i2c2_grp";
+				function = "i2c2_r";
+			};
+		};
+
+		i2c3_acquire: i2c3_acquire {
+			mux {
+				groups = "i2c3_grp";
+				function = "i2c3_a";
+			};
+		};
+
+		i2c3_release: i2c3_release{
+			mux {
+				groups = "i2c3_grp";
+				function = "i2c3_r";
+			};
+		};
+
+		uart0_acquire: uart0_acquire {
+			mux {
+				groups = "uart0_grp";
+				function = "uart0_a";
+			};
+		};
+
+		uart0_release: uart0_release{
+			mux {
+				groups = "uart0_grp";
+				function = "uart0_r";
+			};
+		};
+
+		uart1_acquire: uart1_acquire {
+			mux {
+				groups = "uart1_grp";
+				function = "uart1_a";
+			};
+		};
+
+		uart1_release: uart1_release{
+			mux {
+				groups = "uart1_grp";
+				function = "uart1_r";
+			};
+		};
+
+		uart2_acquire: uart2_acquire {
+			mux {
+				groups = "uart2_grp";
+				function = "uart2_a";
+			};
+		};
+
+		uart2_release: uart2_release{
+			mux {
+				groups = "uart2_grp";
+				function = "uart2_r";
+			};
+		};
+
+		uart3_acquire: uart3_acquire {
+			mux {
+				groups = "uart3_grp";
+				function = "uart3_a";
+			};
+		};
+
+		uart3_release: uart3_release{
+			mux {
+				groups = "uart3_grp";
+				function = "uart3_r";
+			};
+		};
+
+		spi0_acquire: spi0_acquire {
+			mux {
+				groups = "spi0_grp";
+				function = "spi0_a";
+			};
+		};
+
+		spi0_release: spi0_release{
+			mux {
+				groups = "spi0_grp";
+				function = "spi0_r";
+			};
+		};
+
+		spi1_acquire: spi1_acquire {
+			mux {
+				groups = "spi1_grp";
+				function = "spi1_a";
+			};
+		};
+
+		spi1_release: spi1_release{
+			mux {
+				groups = "spi1_grp";
+				function = "spi1_r";
+			};
+		};
+
+		jtag0_acquire: jtag0_acquire {
+			mux {
+				groups = "jtag0_grp";
+				function = "jtag0_a";
+			};
+		};
+
+		jtag0_release: jtag0_release{
+			mux {
+				groups = "jtag0_grp";
+				function = "jtag0_r";
+			};
+		};
+
+		jtag1_acquire: jtag1_acquire {
+			mux {
+				groups = "jtag1_grp";
+				function = "jtag1_a";
+			};
+		};
+
+		jtag1_release: jtag1_release{
+			mux {
+				groups = "jtag1_grp";
+				function = "jtag1_r";
+			};
+		};
+
+		jtag2_acquire: jtag2_acquire {
+			mux {
+				groups = "jtag2_grp";
+				function = "jtag2_a";
+			};
+		};
+
+		jtag2_release: jtag2_release{
+			mux {
+				groups = "jtag2_grp";
+				function = "jtag2_r";
+			};
+		};
+
+		gpio2_acquire: gpio2_acquire {
+			mux {
+				pins = <127>;
+				function = "gpio0_a";
+			};
+		};
+
+		gpio3_release: gpio3_release {
+			mux {
+				pins = <128>;
+				function = "gpio0_r";
+			};
+		};
+
+		gpio5_release: gpio5_release {
+			mux {
+				pins = <130>;
+				function = "gpio0_r";
+			};
+		};
+
+		pwr_key: pwr-key {
+			mux {
+				pins = <147>;
+				function = "gpio0_a";
+			};
+		};
+
+		restart_key: restart-key {
+			mux {
+				pins = <148>;
+				function = "gpio0_a";
+			};
+		};
+
+		dbgi2c_acquire: dbgi2c_acquire {
+			mux {
+				groups = "dbgi2c_grp";
+				function = "dbgi2c_a";
+			};
+		};
+
+		dbgi2c_release: dbgi2c_release{
+			mux {
+				groups = "dbgi2c_grp";
+				function = "dbgi2c_r";
+			};
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts
new file mode 100644
index 000000000000..94892b74467f
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts
@@ -0,0 +1,57 @@
+#include "mango.dtsi"
+#include "mango-pcie-3rc-capricorn.dtsi"
+
+/ {
+	info {
+		file-name = "mango-sophgo-capricorn.dts";
+	};
+};
+
+&ethernet0 {
+	max-speed = <1000>;
+	eth-sophgo-config {
+		autoneg = "enable";
+	};
+};
+
+&soc {
+	gpio-poweroff {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio2_acquire>;
+
+		power {
+			label = "GPIO Key Power";
+			linux,code = <KEY_POWER>;
+			gpios = <&port0a 2 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+};
+
+&port0a {
+	compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0";
+
+	cpld_poweroff: cpld-poweroff {
+		compatible = "mango,cpld-poweroff";
+		gpios = <&port0a 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	cpld_reboot: cpld-reboot {
+		compatible = "mango,cpld-reboot";
+		gpios = <&port0a 5 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/ {
+	 board-info {
+		/* compatible MUST be sophgo,board-info */
+		compatible = "sophgo,board-info";
+		/* valid values are: full-function, xmr */
+		chip-package = "full-function";
+		/* valid values are: x4, x8 */
+		ddr-pcb-type = "x4";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts
new file mode 100644
index 000000000000..98761cbf42e8
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts
@@ -0,0 +1,58 @@
+#include "mango-2sockets.dtsi"
+#include "mango-top-intc2.dtsi"
+#include "mango-pcie-2rc.dtsi"
+
+/ {
+	info {
+		file-name = "mango-sophgo-pisces.dts";
+	};
+};
+
+&ethernet0 {
+	max-speed = <1000>;
+	eth-sophgo-config {
+		autoneg = "enable";
+	};
+};
+
+&soc {
+	gpio-poweroff {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio2_acquire>;
+
+		power {
+			label = "GPIO Key Power";
+			linux,code = <KEY_POWER>;
+			gpios = <&port0a 2 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+};
+
+&port0a {
+	compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0";
+
+	cpld_poweroff: cpld-poweroff {
+		compatible = "mango,cpld-poweroff";
+		gpios = <&port0a 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	cpld_reboot: cpld-reboot {
+		compatible = "mango,cpld-reboot";
+		gpios = <&port0a 5 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/ {
+	 board-info {
+		/* compatible MUST be sophgo,board-info */
+		compatible = "sophgo,board-info";
+		/* valid values are: full-function, xmr */
+		chip-package = "full-function";
+		/* valid values are: x4, x8 */
+		ddr-pcb-type = "x4";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts
new file mode 100644
index 000000000000..78495159bbb4
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts
@@ -0,0 +1,137 @@
+#include "mango.dtsi"
+#include "mango-pcie-3rc-v2.dtsi"
+
+/ {
+	info {
+		file-name = "mango-sophgo-x4evb.dts";
+	};
+};
+
+&i2c1 {
+	mcu: sg2042mcu@17 {
+		compatible = "sophgo,sg20xx-mcu";
+		reg = <0x17>;
+		#thermal-sensor-cells = <1>;
+	};
+
+	mango_srst: mango-reset@17 {
+		compatible = "mango,reset";
+		reg = <0x17>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_acquire>;
+};
+
+&tach0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan0_acquire>;
+};
+
+&tach1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan1_acquire>;
+};
+
+&ethernet0 {
+	max-speed = <1000>;
+	eth-sophgo-config {
+		autoneg = "enable";
+	};
+};
+
+&soc {
+	/delete-node/ flash-controller@7000180000;
+};
+
+/ {
+	pwmfan: pwm-fan {
+		compatible = "pwm-fan";
+		pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns
+		pwm-names = "pwm0","pwm1";
+		pwm_inuse = "pwm0";
+		#cooling-cells = <2>;
+		cooling-levels = <102 127 178 229 254>;  //total 255
+	};
+
+	thermal_zones: thermal-zones {
+		soc {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 0>;
+
+			trips {
+				soc_pwmfan_trip1: soc_pwmfan_trip@1 {
+					temperature = <40000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip2: soc_pwmfan_trip@2 {
+					temperature = <58000>; /* millicelsius */
+					hysteresis = <12000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip3: soc_pwmfan_trip@3 {
+					temperature = <70000>; /* millicelsius */
+					hysteresis = <10000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip4: soc_pwmfan_trip@4 {
+					temperature = <85000>; /* millicelsius */
+					hysteresis = <5000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&soc_pwmfan_trip1>;
+					cooling-device = <&pwmfan 0 1>;
+				};
+
+				map1 {
+					trip = <&soc_pwmfan_trip2>;
+					cooling-device = <&pwmfan 1 2>;
+				};
+
+				map2 {
+					trip = <&soc_pwmfan_trip3>;
+					cooling-device = <&pwmfan 2 3>;
+				};
+
+				map3 {
+					trip = <&soc_pwmfan_trip4>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+
+		};
+
+		board {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 1>;
+
+			trips {
+				board_pwmfan_trip1: board_pwmfan_trip@1 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map4 {
+					trip = <&board_pwmfan_trip1>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+		};
+	};
+
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts
new file mode 100644
index 000000000000..83e4f1411f2e
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts
@@ -0,0 +1,165 @@
+#include "mango.dtsi"
+#include "mango-pcie-3rc.dtsi"
+
+/ {
+	info {
+		file-name = "mango-sophgo-x8evb.dts";
+	};
+};
+
+&i2c1 {
+	mcu: sg2042mcu@17 {
+		compatible = "sophgo,sg20xx-mcu";
+		reg = <0x17>;
+		#thermal-sensor-cells = <1>;
+	};
+
+	mango_srst: mango-reset@17 {
+		compatible = "mango,reset";
+		reg = <0x17>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_acquire>;
+};
+
+&soc {
+	gpio-poweroff {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pwr_key>;
+
+		power {
+			label = "GPIO Key Power";
+			linux,code = <KEY_POWER>;
+			gpios = <&port0a 22 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+
+	gpio-restart {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&restart_key>;
+
+		restart {
+			label = "GPIO Key Restart";
+			linux,code = <KEY_RESTART>;
+			gpios = <&port0a 23 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+};
+
+&tach0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan0_acquire>;
+};
+
+&tach1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fan1_acquire>;
+};
+
+&ethernet0 {
+	max-speed = <1000>;
+	eth-sophgo-config {
+		autoneg = "enable";
+	};
+};
+
+/ {
+	pwmfan: pwm-fan {
+		compatible = "pwm-fan";
+		pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns
+		pwm-names = "pwm0","pwm1";
+		pwm_inuse = "pwm0";
+		#cooling-cells = <2>;
+		cooling-levels = <153 128 77 26 1>;  //total 255
+	};
+
+	thermal_zones: thermal-zones {
+		soc {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 0>;
+
+			trips {
+				soc_pwmfan_trip1: soc_pwmfan_trip@1 {
+					temperature = <40000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip2: soc_pwmfan_trip@2 {
+					temperature = <58000>; /* millicelsius */
+					hysteresis = <12000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip3: soc_pwmfan_trip@3 {
+					temperature = <70000>; /* millicelsius */
+					hysteresis = <10000>; /* millicelsius */
+					type = "active";
+				};
+
+				soc_pwmfan_trip4: soc_pwmfan_trip@4 {
+					temperature = <85000>; /* millicelsius */
+					hysteresis = <5000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&soc_pwmfan_trip1>;
+					cooling-device = <&pwmfan 0 1>;
+				};
+
+				map1 {
+					trip = <&soc_pwmfan_trip2>;
+					cooling-device = <&pwmfan 1 2>;
+				};
+
+				map2 {
+					trip = <&soc_pwmfan_trip3>;
+					cooling-device = <&pwmfan 2 3>;
+				};
+
+				map3 {
+					trip = <&soc_pwmfan_trip4>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+
+		};
+
+		board {
+			polling-delay-passive = <1000>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+			thermal-sensors = <&mcu 1>;
+
+			trips {
+				board_pwmfan_trip1: board_pwmfan_trip@1 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <8000>; /* millicelsius */
+					type = "active";
+				};
+			};
+
+			cooling-maps {
+				map4 {
+					trip = <&board_pwmfan_trip1>;
+					cooling-device = <&pwmfan 3 4>;
+				};
+			};
+		};
+	};
+
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi
new file mode 100644
index 000000000000..6d364cf6b3c5
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi
@@ -0,0 +1,62 @@
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	intc2: top_intc@f030010300 {
+		compatible = "sophgo,top-intc";
+		reg = <0xf0 0x300102E0 0x0 0x4>,
+		      <0xf0 0x30010300 0x0 0x4>,
+		      <0xf0 0x30010304 0x0 0x4>;
+		reg-names = "sta", "set", "clr";
+		reg-bitwidth = <32>;
+		top-intc-id = <1>;
+		interrupt-controller;
+		#interrupt-cells = <0x1>; // only applies to child node
+		for-msi;
+
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(288) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(289) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(290) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(291) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(292) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(293) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(294) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(295) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(296) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(297) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(298) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(299) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(300) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(301) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(302) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(303) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(304) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(305) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(306) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(307) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(308) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(309) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(310) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(311) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(312) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(313) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(314) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(315) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(316) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(317) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(318) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(319) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi0",  "msi1",  "msi2",  "msi3",
+				  "msi4",  "msi5",  "msi6",  "msi7",
+				  "msi8",  "msi9",  "msi10", "msi11",
+				  "msi12", "msi13", "msi14", "msi15",
+				  "msi16", "msi17", "msi18", "msi19",
+				  "msi20", "msi21", "msi22", "msi23",
+				  "msi24", "msi25", "msi26", "msi27",
+				  "msi28", "msi29", "msi30", "msi31";
+
+	};
+
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts b/arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts
new file mode 100644
index 000000000000..172421ffc196
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts
@@ -0,0 +1,63 @@
+#include "mango-2sockets.dtsi"
+#include "mango-top-intc2.dtsi"
+#include "mango-pcie-4rc-v2.dtsi"
+
+/ {
+	info {
+		file-name = "mango-yixin-s2110.dts";
+	};
+};
+
+&ethernet0 {
+	max-speed = <1000>;
+	eth-sophgo-config {
+		autoneg = "enable";
+	};
+};
+
+&soc {
+	gpio-poweroff {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio2_acquire>;
+
+		power {
+			label = "GPIO Key Power";
+			linux,code = <KEY_POWER>;
+			gpios = <&port0a 2 GPIO_ACTIVE_HIGH>;
+			linux,input-type = <1>;
+			debounce-interval = <100>;
+		};
+	};
+};
+
+&gpio0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&dbgi2c_release>;
+};
+
+&port0a {
+	compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0";
+
+	cpld_poweroff: cpld-poweroff {
+		compatible = "mango,cpld-poweroff";
+		gpios = <&port0a 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	cpld_reboot: cpld-reboot {
+		compatible = "mango,cpld-reboot";
+		gpios = <&port0a 29 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+/ {
+	 board-info {
+		/* compatible MUST be sophgo,board-info */
+		compatible = "sophgo,board-info";
+		/* valid values are: full-function, xmr */
+		chip-package = "full-function";
+		/* valid values are: x4, x8 */
+		ddr-pcb-type = "x8";
+	};
+};
diff --git a/arch/riscv/boot/dts/sophgo/mango.dtsi b/arch/riscv/boot/dts/sophgo/mango.dtsi
new file mode 100644
index 000000000000..8c1ba532531c
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/mango.dtsi
@@ -0,0 +1,941 @@
+/dts-v1/;
+#include <dt-bindings/clock/sophgo.h>
+#include <dt-bindings/clock/sophgo-mango-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/reset/sophgo-mango-resets.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "mango-cpus-socket0.dtsi"
+#include "mango-clock-socket0.dtsi"
+#include "mango-pinctrl.dtsi"
+
+#define SOC_PERIPHERAL_IRQ(nr)	(nr)
+
+/ {
+	model = "Sophgo Mango";
+	compatible = "sophgo,mango";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	dma-noncoherent;
+
+	distance-map {
+		compatible = "numa-distance-map-v1";
+		distance-matrix = <0 0 10>,
+				  <0 1 15>,
+				  <0 2 25>,
+				  <0 3 30>,
+				  <1 0 15>,
+				  <1 1 10>,
+				  <1 2 30>,
+				  <1 3 25>,
+				  <2 0 25>,
+				  <2 1 30>,
+				  <2 2 10>,
+				  <2 3 15>,
+				  <3 0 30>,
+				  <3 1 25>,
+				  <3 2 15>,
+				  <3 3 10>;
+	};
+
+	pmu {
+		compatible = "riscv,pmu";
+		riscv,event-to-mhpmevent =
+			<0x00003 0x00000000 0x00000010>,
+			<0x00004 0x00000000 0x00000011>,
+			<0x00005 0x00000000 0x00000007>,
+			<0x00006 0x00000000 0x00000006>,
+			<0x00008 0x00000000 0x00000027>,
+			<0x00009 0x00000000 0x00000028>,
+			<0x10000 0x00000000 0x0000000c>,
+			<0x10001 0x00000000 0x0000000d>,
+			<0x10002 0x00000000 0x0000000e>,
+			<0x10003 0x00000000 0x0000000f>,
+			<0x10008 0x00000000 0x00000001>,
+			<0x10009 0x00000000 0x00000002>,
+			<0x10010 0x00000000 0x00000010>,
+			<0x10011 0x00000000 0x00000011>,
+			<0x10012 0x00000000 0x00000012>,
+			<0x10013 0x00000000 0x00000013>,
+			<0x10019 0x00000000 0x00000004>,
+			<0x10021 0x00000000 0x00000003>,
+			<0x10030 0x00000000 0x0000001c>,
+			<0x10031 0x00000000 0x0000001b>;
+		riscv,event-to-mhpmcounters =
+			<0x00003 0x00003 0xfffffff8>,
+			<0x00004 0x00004 0xfffffff8>,
+			<0x00005 0x00005 0xfffffff8>,
+			<0x00006 0x00006 0xfffffff8>,
+			<0x00007 0x00007 0xfffffff8>,
+			<0x00008 0x00008 0xfffffff8>,
+			<0x00009 0x00009 0xfffffff8>,
+			<0x0000a 0x0000a 0xfffffff8>,
+			<0x10000 0x10000 0xfffffff8>,
+			<0x10001 0x10001 0xfffffff8>,
+			<0x10002 0x10002 0xfffffff8>,
+			<0x10003 0x10003 0xfffffff8>,
+			<0x10008 0x10008 0xfffffff8>,
+			<0x10009 0x10009 0xfffffff8>,
+			<0x10010 0x10010 0xfffffff8>,
+			<0x10011 0x10011 0xfffffff8>,
+			<0x10012 0x10012 0xfffffff8>,
+			<0x10013 0x10013 0xfffffff8>,
+			<0x10019 0x10019 0xfffffff8>,
+			<0x10021 0x10021 0xfffffff8>,
+			<0x10030 0x10030 0xfffffff8>,
+			<0x10031 0x10031 0xfffffff8>;
+		riscv,raw-event-to-mhpmcounters =
+			<0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>,
+			<0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>;
+	};
+
+	soc: soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		ranges;
+		dma-ranges = <0x0 0x0 0x0 0x0 0x1f 0x0>;
+
+		clint_mswi: clint-mswi@7094000000 {
+			compatible = "thead,c900-clint-mswi";
+			reg = <0x00000070 0x94000000 0x00000000 0x00004000>;
+			interrupts-extended = <
+				&cpu0_intc 3
+				&cpu1_intc 3
+				&cpu2_intc 3
+				&cpu3_intc 3
+				&cpu4_intc 3
+				&cpu5_intc 3
+				&cpu6_intc 3
+				&cpu7_intc 3
+				&cpu8_intc 3
+				&cpu9_intc 3
+				&cpu10_intc 3
+				&cpu11_intc 3
+				&cpu12_intc 3
+				&cpu13_intc 3
+				&cpu14_intc 3
+				&cpu15_intc 3
+				&cpu16_intc 3
+				&cpu17_intc 3
+				&cpu18_intc 3
+				&cpu19_intc 3
+				&cpu20_intc 3
+				&cpu21_intc 3
+				&cpu22_intc 3
+				&cpu23_intc 3
+				&cpu24_intc 3
+				&cpu25_intc 3
+				&cpu26_intc 3
+				&cpu27_intc 3
+				&cpu28_intc 3
+				&cpu29_intc 3
+				&cpu30_intc 3
+				&cpu31_intc 3
+				&cpu32_intc 3
+				&cpu33_intc 3
+				&cpu34_intc 3
+				&cpu35_intc 3
+				&cpu36_intc 3
+				&cpu37_intc 3
+				&cpu38_intc 3
+				&cpu39_intc 3
+				&cpu40_intc 3
+				&cpu41_intc 3
+				&cpu42_intc 3
+				&cpu43_intc 3
+				&cpu44_intc 3
+				&cpu45_intc 3
+				&cpu46_intc 3
+				&cpu47_intc 3
+				&cpu48_intc 3
+				&cpu49_intc 3
+				&cpu50_intc 3
+				&cpu51_intc 3
+				&cpu52_intc 3
+				&cpu53_intc 3
+				&cpu54_intc 3
+				&cpu55_intc 3
+				&cpu56_intc 3
+				&cpu57_intc 3
+				&cpu58_intc 3
+				&cpu59_intc 3
+				&cpu60_intc 3
+				&cpu61_intc 3
+				&cpu62_intc 3
+				&cpu63_intc 3
+				>;
+		};
+
+		clint_mtimer0: clint-mtimer@70ac000000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu0_intc 7
+				&cpu1_intc 7
+				&cpu2_intc 7
+				&cpu3_intc 7
+				>;
+		};
+
+		clint_mtimer1: clint-mtimer@70ac010000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu4_intc 7
+				&cpu5_intc 7
+				&cpu6_intc 7
+				&cpu7_intc 7
+				>;
+		};
+
+		clint_mtimer2: clint-mtimer@70ac020000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu8_intc 7
+				&cpu9_intc 7
+				&cpu10_intc 7
+				&cpu11_intc 7
+				>;
+		};
+
+		clint_mtimer3: clint-mtimer@70ac030000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu12_intc 7
+				&cpu13_intc 7
+				&cpu14_intc 7
+				&cpu15_intc 7
+				>;
+		};
+
+		clint_mtimer4: clint-mtimer@70ac040000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu16_intc 7
+				&cpu17_intc 7
+				&cpu18_intc 7
+				&cpu19_intc 7
+				>;
+		};
+
+		clint_mtimer5: clint-mtimer@70ac050000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu20_intc 7
+				&cpu21_intc 7
+				&cpu22_intc 7
+				&cpu23_intc 7
+				>;
+		};
+
+		clint_mtimer6: clint-mtimer@70ac060000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu24_intc 7
+				&cpu25_intc 7
+				&cpu26_intc 7
+				&cpu27_intc 7
+				>;
+		};
+
+		clint_mtimer7: clint-mtimer@70ac070000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu28_intc 7
+				&cpu29_intc 7
+				&cpu30_intc 7
+				&cpu31_intc 7
+				>;
+		};
+
+		clint_mtimer8: clint-mtimer@70ac080000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu32_intc 7
+				&cpu33_intc 7
+				&cpu34_intc 7
+				&cpu35_intc 7
+				>;
+		};
+
+		clint_mtimer9: clint-mtimer@70ac090000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu36_intc 7
+				&cpu37_intc 7
+				&cpu38_intc 7
+				&cpu39_intc 7
+				>;
+		};
+
+		clint_mtimer10: clint-mtimer@70ac0a0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu40_intc 7
+				&cpu41_intc 7
+				&cpu42_intc 7
+				&cpu43_intc 7
+				>;
+		};
+
+		clint_mtimer11: clint-mtimer@70ac0b0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu44_intc 7
+				&cpu45_intc 7
+				&cpu46_intc 7
+				&cpu47_intc 7
+				>;
+		};
+
+		clint_mtimer12: clint-mtimer@70ac0c0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu48_intc 7
+				&cpu49_intc 7
+				&cpu50_intc 7
+				&cpu51_intc 7
+				>;
+		};
+
+		clint_mtimer13: clint-mtimer@70ac0d0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu52_intc 7
+				&cpu53_intc 7
+				&cpu54_intc 7
+				&cpu55_intc 7
+				>;
+		};
+
+		clint_mtimer14: clint-mtimer@70ac0e0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu56_intc 7
+				&cpu57_intc 7
+				&cpu58_intc 7
+				&cpu59_intc 7
+				>;
+		};
+
+		clint_mtimer15: clint-mtimer@70ac0f0000 {
+			compatible = "thead,c900-clint-mtimer";
+			reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>;
+			interrupts-extended = <
+				&cpu60_intc 7
+				&cpu61_intc 7
+				&cpu62_intc 7
+				&cpu63_intc 7
+				>;
+		};
+
+		intc: interrupt-controller@7090000000 {
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			compatible = "thead,c900-plic";
+			interrupt-controller;
+			interrupts-extended = <
+				&cpu0_intc  11 &cpu0_intc  9
+				&cpu1_intc  11 &cpu1_intc  9
+				&cpu2_intc  11 &cpu2_intc  9
+				&cpu3_intc  11 &cpu3_intc  9
+				&cpu4_intc  11 &cpu4_intc  9
+				&cpu5_intc  11 &cpu5_intc  9
+				&cpu6_intc  11 &cpu6_intc  9
+				&cpu7_intc  11 &cpu7_intc  9
+				&cpu8_intc  11 &cpu8_intc  9
+				&cpu9_intc  11 &cpu9_intc  9
+				&cpu10_intc  11 &cpu10_intc  9
+				&cpu11_intc  11 &cpu11_intc  9
+				&cpu12_intc  11 &cpu12_intc  9
+				&cpu13_intc  11 &cpu13_intc  9
+				&cpu14_intc  11 &cpu14_intc  9
+				&cpu15_intc  11 &cpu15_intc  9
+				&cpu16_intc  11 &cpu16_intc  9
+				&cpu17_intc  11 &cpu17_intc  9
+				&cpu18_intc  11 &cpu18_intc  9
+				&cpu19_intc  11 &cpu19_intc  9
+				&cpu20_intc  11 &cpu20_intc  9
+				&cpu21_intc  11 &cpu21_intc  9
+				&cpu22_intc  11 &cpu22_intc  9
+				&cpu23_intc  11 &cpu23_intc  9
+				&cpu24_intc  11 &cpu24_intc  9
+				&cpu25_intc  11 &cpu25_intc  9
+				&cpu26_intc  11 &cpu26_intc  9
+				&cpu27_intc  11 &cpu27_intc  9
+				&cpu28_intc  11 &cpu28_intc  9
+				&cpu29_intc  11 &cpu29_intc  9
+				&cpu30_intc  11 &cpu30_intc  9
+				&cpu31_intc  11 &cpu31_intc  9
+				&cpu32_intc  11 &cpu32_intc  9
+				&cpu33_intc  11 &cpu33_intc  9
+				&cpu34_intc  11 &cpu34_intc  9
+				&cpu35_intc  11 &cpu35_intc  9
+				&cpu36_intc  11 &cpu36_intc  9
+				&cpu37_intc  11 &cpu37_intc  9
+				&cpu38_intc  11 &cpu38_intc  9
+				&cpu39_intc  11 &cpu39_intc  9
+				&cpu40_intc  11 &cpu40_intc  9
+				&cpu41_intc  11 &cpu41_intc  9
+				&cpu42_intc  11 &cpu42_intc  9
+				&cpu43_intc  11 &cpu43_intc  9
+				&cpu44_intc  11 &cpu44_intc  9
+				&cpu45_intc  11 &cpu45_intc  9
+				&cpu46_intc  11 &cpu46_intc  9
+				&cpu47_intc  11 &cpu47_intc  9
+				&cpu48_intc  11 &cpu48_intc  9
+				&cpu49_intc  11 &cpu49_intc  9
+				&cpu50_intc  11 &cpu50_intc  9
+				&cpu51_intc  11 &cpu51_intc  9
+				&cpu52_intc  11 &cpu52_intc  9
+				&cpu53_intc  11 &cpu53_intc  9
+				&cpu54_intc  11 &cpu54_intc  9
+				&cpu55_intc  11 &cpu55_intc  9
+				&cpu56_intc  11 &cpu56_intc  9
+				&cpu57_intc  11 &cpu57_intc  9
+				&cpu58_intc  11 &cpu58_intc  9
+				&cpu59_intc  11 &cpu59_intc  9
+				&cpu60_intc  11 &cpu60_intc  9
+				&cpu61_intc  11 &cpu61_intc  9
+				&cpu62_intc  11 &cpu62_intc  9
+				&cpu63_intc  11 &cpu63_intc  9
+				>;
+			reg = <0x00000070 0x90000000 0x00000000 0x04000000>;
+			reg-names = "control";
+			riscv,max-priority = <7>;
+			riscv,ndev = <224>;
+		};
+
+		timer0: dw-apb-timer0@7030003000 {
+			compatible = "snps,dw-apb-timer";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x70 0x30003000 0x0 0x14>;
+			clocks = <&div_clk GATE_CLK_TIMER1>,
+				 <&div_clk GATE_CLK_APB_TIMER>;
+			clock-names = "timer", "pclk";
+			clk-drv-rating = <300>;
+		};
+
+		timer1: dw-apb-timer1@7030003014 {
+			compatible = "snps,dw-apb-timer";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x70 0x30003014 0x0 0x10>;
+			clocks = <&div_clk GATE_CLK_TIMER2>,
+				 <&div_clk GATE_CLK_APB_TIMER>;
+			clock-names = "timer", "pclk";
+			clk-drv-rating = <300>;
+		};
+
+		top_misc: top_misc_ctrl@7030010000 {
+			compatible = "syscon";
+			reg = <0x70 0x30010000 0x0 0x8000>;
+		};
+
+		rst: reset-controller {
+			#reset-cells = <1>;
+			compatible = "bitmain,reset";
+			subctrl-syscon = <&top_misc>;
+			top_rst_offset = <0x3000>;
+			nr_resets = <RST_MAX_NUM>;
+		};
+
+		i2c0: i2c@7030005000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "snps,designware-i2c";
+			clocks = <&div_clk GATE_CLK_APB_I2C>;
+			clock-names = "clk_gate_apb_i2c";
+			reg = <0x70 0x30005000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000>;
+			resets = <&rst RST_I2C0>;
+			reset-names = "i2c0";
+		};
+
+		i2c1: i2c@7030006000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "snps,designware-i2c";
+			clocks = <&div_clk GATE_CLK_APB_I2C>;
+			clock-names = "clk_gate_apb_i2c";
+			reg = <0x70 0x30006000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(102) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000>;
+			resets = <&rst RST_I2C1>;
+			reset-names = "i2c1";
+		};
+
+		i2c2: i2c@7030007000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "snps,designware-i2c";
+			clocks = <&div_clk GATE_CLK_APB_I2C>;
+			clock-names = "clk_gate_apb_i2c";
+			reg = <0x70 0x30007000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(103) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000>;
+			resets = <&rst RST_I2C2>;
+			reset-names = "i2c2";
+		};
+
+		i2c3: i2c@7030008000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "snps,designware-i2c";
+			clocks = <&div_clk GATE_CLK_APB_I2C>;
+			clock-names = "clk_gate_apb_i2c";
+			reg = <0x70 0x30008000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(104) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000>;
+			resets = <&rst RST_I2C3>;
+			reset-names = "i2c3";
+		};
+
+		gpio0: gpio@7030009000 {
+			compatible = "snps,dw-apb-gpio";
+			reg = <0x70 0x30009000 0x0 0x400>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&div_clk GATE_CLK_APB_GPIO>,
+				 <&div_clk GATE_CLK_APB_GPIO_INTR>,
+				 <&div_clk GATE_CLK_GPIO_DB>;
+			clock-names = "base_clk", "intr_clk", "db_clk";
+
+			port0a: gpio-controller@0 {
+				compatible = "snps,dw-apb-gpio-port";
+				bank-name = "port0a";
+				gpio-controller;
+				#gpio-cells = <2>;
+				snps,nr-gpios = <32>;
+				reg = <0>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupt-parent = <&intc>;
+				interrupts = <SOC_PERIPHERAL_IRQ(96) IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
+		gpio1: gpio@703000a000 {
+			compatible = "snps,dw-apb-gpio";
+			reg = <0x70 0x3000a000 0x0 0x400>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&div_clk GATE_CLK_APB_GPIO>,
+				 <&div_clk GATE_CLK_APB_GPIO_INTR>,
+				 <&div_clk GATE_CLK_GPIO_DB>;
+			clock-names = "base_clk", "intr_clk", "db_clk";
+
+			port1a: gpio-controller@0 {
+				compatible = "snps,dw-apb-gpio-port";
+				bank-name = "port0a";
+				gpio-controller;
+				#gpio-cells = <2>;
+				snps,nr-gpios = <32>;
+				reg = <0>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupt-parent = <&intc>;
+				interrupts = <SOC_PERIPHERAL_IRQ(97) IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
+		gpio2: gpio@703000b000 {
+			compatible = "snps,dw-apb-gpio";
+			reg = <0x70 0x3000b000 0x0 0x400>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&div_clk GATE_CLK_APB_GPIO>,
+				 <&div_clk GATE_CLK_APB_GPIO_INTR>,
+				 <&div_clk GATE_CLK_GPIO_DB>;
+			clock-names = "base_clk", "intr_clk", "db_clk";
+
+			port2a: gpio-controller@0 {
+				compatible = "snps,dw-apb-gpio-port";
+				bank-name = "port0a";
+				gpio-controller;
+				#gpio-cells = <2>;
+				snps,nr-gpios = <32>;
+				reg = <0>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupt-parent = <&intc>;
+				interrupts = <SOC_PERIPHERAL_IRQ(98) IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
+		pwm: pwm@703000C000 {
+			compatible = "sophgo,sophgo-pwm";
+			reg = <0x70 0x3000C000 0x0 0x20>;
+			clocks = <&div_clk GATE_CLK_APB_PWM>;
+			clock-names = "clk_gate_apb_pwm";
+			#pwm-cells = <2>;
+			pwm-num = <2>;
+			no-polarity;
+		};
+
+		tach0: tach@703000C020 {
+			compatible = "sophgo,sophgo-tach";
+			reg = <0x70 0x3000C020 0x0 0x8>;
+		};
+
+		tach1: tach@703000C028 {
+			compatible = "sophgo,sophgo-tach";
+			reg = <0x70 0x3000C028 0x0 0x8>;
+		};
+
+		uart0: serial@7040000000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x00000070 0x40000000 0x00000000 0x00001000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(112) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <500000000>;
+			clocks = <&div_clk GATE_CLK_UART_500M>,
+				 <&div_clk GATE_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
+			reg-shift = <2>;
+			reg-io-width = <4>;
+		};
+
+		uart1: serial@7040001000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x00000070 0x40001000 0x00000000 0x00001000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(113) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <500000000>;
+			clocks = <&div_clk GATE_CLK_UART_500M>,
+				 <&div_clk GATE_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
+			reg-shift = <2>;
+			reg-io-width = <4>;
+		};
+
+		uart2: serial@7040002000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x00000070 0x40002000 0x00000000 0x00001000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(114) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <500000000>;
+			clocks = <&div_clk GATE_CLK_UART_500M>,
+				 <&div_clk GATE_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
+			reg-shift = <2>;
+			reg-io-width = <4>;
+		};
+
+		uart3: serial@7040003000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x00000070 0x40003000 0x00000000 0x00001000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(115) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <500000000>;
+			clocks = <&div_clk GATE_CLK_UART_500M>,
+				 <&div_clk GATE_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
+			reg-shift = <2>;
+			reg-io-width = <4>;
+		};
+
+		emmc: bm-emmc@704002A000 {
+			compatible = "bitmain,bm-emmc";
+			reg = <0x70 0x4002A000 0x0 0x1000>;
+			reg-names = "core_mem";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(134) IRQ_TYPE_LEVEL_HIGH>;
+			bus-width = <4>;
+			non-removable;
+			no-sdio;
+			no-sd;
+			resets = <&rst RST_EMMC>;
+			reset-names = "emmc";
+			clocks =
+				<&div_clk GATE_CLK_EMMC_100M>,
+				<&div_clk GATE_CLK_AXI_EMMC>,
+				<&div_clk GATE_CLK_100K_EMMC>;
+			clock-names =
+				"clk_gate_emmc",
+				"clk_gate_axi_emmc",
+				"clk_gate_100k_emmc";
+		};
+
+		sd: bm-sd@704002B000 {
+			compatible = "bitmain,bm-sd";
+			reg = <0x70 0x4002B000 0x0 0x1000>;
+			reg-names = "core_mem";
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(136) IRQ_TYPE_LEVEL_HIGH>;
+			bus-width = <4>;
+			no-sdio;
+			no-mmc;
+			resets = <&rst RST_SD>;
+			reset-names = "sdio";
+			clocks =
+				<&div_clk GATE_CLK_SD_100M>,
+				<&div_clk GATE_CLK_AXI_SD>,
+				<&div_clk GATE_CLK_100K_SD>;
+			clock-names =
+				"clk_gate_sd",
+				"clk_gate_axi_sd",
+				"clk_gate_100k_sd";
+		};
+
+		spifmc0: flash-controller@7000180000 {
+			compatible = "sophgo,spifmc";
+			reg = <0x70 0x00180000 0x0 0x1000000>;
+			reg-names = "memory";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(108) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000000>;
+			clocks = <&div_clk GATE_CLK_AHB_SF>;
+			flash@0 {
+				reg = <0>;
+				compatible = "jedec,spi-nor";
+			};
+		};
+
+		spifmc1: flash-controller@7002180000 {
+			compatible = "sophgo,spifmc";
+			reg = <0x70 0x02180000 0x0 0x1000000>;
+			reg-names = "memory";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(109) IRQ_TYPE_LEVEL_HIGH>;
+			clock-frequency = <100000000>;
+			clocks = <&div_clk GATE_CLK_AHB_SF>;
+			flash@0 {
+				reg = <0>;
+				compatible = "jedec,spi-nor";
+			};
+		};
+
+                spi0: spi@7040004000 {
+			compatible = "snps,dw-apb-ssi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x70 0x40004000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(110) IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&div_clk GATE_CLK_APB_SPI>,
+			          <&div_clk GATE_CLK_SYSDMA_AXI>;
+			clock-frequency = <250000000>;
+			resets = <&rst RST_SPI0>;
+			reset-names = "spi0";
+			num-cs = <2>;
+			status = "okay";
+                };
+
+                spi1: spi@7040005000 {
+			compatible = "snps,dw-apb-ssi";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x70 0x40005000 0x0 0x1000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(111) IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&div_clk GATE_CLK_APB_SPI>,
+			           <&div_clk GATE_CLK_SYSDMA_AXI>;
+			clock-frequency = <250000000>;
+			resets = <&rst RST_SPI1>;
+			reset-names = "spi1";
+			num-cs = <2>;
+			status = "okay";
+                };
+
+		stmmac_axi_setup: stmmac-axi-config {
+			snps,wr_osr_lmt = <1>;
+			snps,rd_osr_lmt = <2>;
+			snps,blen = <4 8 16 0 0 0 0>;
+		};
+
+		mtl_rx_setup: rx-queues-config {
+			snps,rx-queues-to-use = <8>;
+			queue0 {};
+			queue1 {};
+			queue2 {};
+			queue3 {};
+			queue4 {};
+			queue5 {};
+			queue6 {};
+			queue7 {};
+		};
+
+		mtl_tx_setup: tx-queues-config {
+			snps,tx-queues-to-use = <8>;
+			queue0 {};
+			queue1 {};
+			queue2 {};
+			queue3 {};
+			queue4 {};
+			queue5 {};
+			queue6 {};
+			queue7 {};
+		};
+
+		ethernet0: ethernet@7040026000 {
+			compatible = "bitmain,ethernet";
+			reg = <0x70 0x40026000 0x0 0x4000>;
+			interrupt-parent = <&intc>;
+			interrupts = <SOC_PERIPHERAL_IRQ(132) IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref";
+			clocks = <&div_clk DIV_CLK_FPLL_TX_ETH0>,
+				   <&div_clk GATE_CLK_TX_ETH0>,
+				   <&div_clk GATE_CLK_AXI_ETH0>,
+				   <&div_clk GATE_CLK_PTP_REF_I_ETH0>,
+				   <&div_clk GATE_CLK_REF_ETH0>;
+
+			/* no hash filter and perfect filter support */
+			snps,multicast-filter-bins = <0>;
+			snps,perfect-filter-entries = <1>;
+
+			snps,txpbl = <32>;
+			snps,rxpbl = <32>;
+			snps,aal;
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,mtl-rx-config = <&mtl_rx_setup>;
+			snps,mtl-tx-config = <&mtl_tx_setup>;
+
+			phy-mode = "rgmii-txid";
+			phy-reset-gpios = <&port0a 27 0>;
+			phy-handle = <&phy0>;
+			mdio {
+				#address-cells = <0x1>;
+				#size-cells = <0x0>;
+				compatible = "snps,dwmac-mdio";
+				phy0: phy@0 {
+					compatible = "ethernet-phy-ieee802.3-c22";
+					device_type = "ethernet-phy";
+					reg = <0x0>;
+				};
+			};
+		};
+	};
+
+	intc1: top_intc@7030010300 {
+		compatible = "sophgo,top-intc";
+		reg = <0x70 0x300102E0 0x0 0x4>,
+		      <0x70 0x30010300 0x0 0x4>,
+		      <0x70 0x30010304 0x0 0x4>;
+		reg-names = "sta", "set", "clr";
+		reg-bitwidth = <32>;
+		top_intc_id = <0>;
+		interrupt-controller;
+		#interrupt-cells = <0x1>; // only applies to child node
+		for-msi;
+
+		interrupt-parent = <&intc>;
+		interrupts = <SOC_PERIPHERAL_IRQ(64) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(65) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(66) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(67) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(68) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(69) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(70) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(71) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(72) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(73) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(74) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(75) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(76) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(77) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(78) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(79) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(80) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(81) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(82) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(83) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(84) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(85) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(86) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(87) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(88) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(89) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(90) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(91) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(92) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(93) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(94) IRQ_TYPE_LEVEL_HIGH>,
+			     <SOC_PERIPHERAL_IRQ(95) IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "msi0",  "msi1",  "msi2",  "msi3",
+				  "msi4",  "msi5",  "msi6",  "msi7",
+				  "msi8",  "msi9",  "msi10", "msi11",
+				  "msi12", "msi13", "msi14", "msi15",
+				  "msi16", "msi17", "msi18", "msi19",
+				  "msi20", "msi21", "msi22", "msi23",
+				  "msi24", "msi25", "msi26", "msi27",
+				  "msi28", "msi29", "msi30", "msi31";
+
+	};
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen: chosen {
+		bootargs = "console=ttyS0,115200 earlycon maxcpus=1";
+		stdout-path = "serial0";
+	};
+};
diff --git a/arch/riscv/configs/sophgo_mango_fedora_defconfig b/arch/riscv/configs/sophgo_mango_fedora_defconfig
new file mode 100644
index 000000000000..4ba5d33e8f14
--- /dev/null
+++ b/arch/riscv/configs/sophgo_mango_fedora_defconfig
@@ -0,0 +1,3544 @@
+CONFIG_UAPI_HEADER_TEST=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_WATCH_QUEUE=y
+CONFIG_USELIB=y
+CONFIG_NO_HZ_FULL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_JIT=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BPF_PRELOAD=y
+CONFIG_BPF_LSM=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_PSI=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKHEADERS=m
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+CONFIG_PRINTK_INDEX=y
+CONFIG_NUMA_BALANCING=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_RDMA=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_MISC=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_SCHED_AUTOGROUP=y
+# CONFIG_INITRAMFS_PRESERVE_MTIME is not set
+CONFIG_EXPERT=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_PC104=y
+CONFIG_PROFILING=y
+CONFIG_SOC_MICROCHIP_POLARFIRE=y
+CONFIG_SOC_SIFIVE=y
+CONFIG_SOC_STARFIVE=y
+CONFIG_SOC_VIRT=y
+CONFIG_ARCH_SOPHGO=y
+CONFIG_ERRATA_THEAD=y
+CONFIG_SMP=y
+CONFIG_SCHED_CLUSTER=y
+CONFIG_NR_CPUS=128
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=3
+CONFIG_VECTOR=y
+CONFIG_HZ_100=y
+CONFIG_RISCV_BOOT_SPINWAIT=y
+CONFIG_KEXEC=y
+CONFIG_KEXEC_FILE=y
+CONFIG_CRASH_DUMP=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_CPU_IDLE=y
+CONFIG_JUMP_LABEL=y
+# CONFIG_STACKPROTECTOR_STRONG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_UNLOAD_TAINT_TRACKING=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_MODULE_COMPRESS_GZIP=y
+CONFIG_MODPROBE_PATH="/usr/sbin/modprobe"
+CONFIG_BLK_DEV_ZONED=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_BLK_WBT=y
+CONFIG_BLK_CGROUP_IOLATENCY=y
+CONFIG_BLK_CGROUP_FC_APPID=y
+CONFIG_BLK_CGROUP_IOCOST=y
+CONFIG_BLK_CGROUP_IOPRIO=y
+CONFIG_BLK_SED_OPAL=y
+CONFIG_BLK_INLINE_ENCRYPTION=y
+CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_AIX_PARTITION=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_IOSCHED_BFQ=y
+CONFIG_BFQ_GROUP_IOSCHED=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_FLAT_OLD=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_MISC=y
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=y
+CONFIG_ZSMALLOC=y
+# CONFIG_SLAB_MERGE_DEFAULT is not set
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SPARSEMEM_VMEMMAP is not set
+CONFIG_KSM=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_CMA_SYSFS=y
+CONFIG_IDLE_PAGE_TRACKING=y
+CONFIG_USERFAULTFD=y
+CONFIG_DAMON=y
+CONFIG_DAMON_VADDR=y
+CONFIG_DAMON_PADDR=y
+CONFIG_DAMON_SYSFS=y
+CONFIG_DAMON_DBGFS=y
+CONFIG_DAMON_RECLAIM=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=y
+CONFIG_TLS=m
+CONFIG_TLS_DEVICE=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_INTERFACE=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_SMC=m
+CONFIG_SMC_DIAG=m
+CONFIG_XDP_SOCKETS=y
+CONFIG_XDP_SOCKETS_DIAG=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU_IP_TUNNELS=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_ESP_OFFLOAD=m
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_UDP_DIAG=y
+CONFIG_INET_RAW_DIAG=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_NV=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_BBR=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_ESPINTCP=y
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_IPV6_SEG6_LWTUNNEL=y
+CONFIG_IPV6_SEG6_HMAC=y
+CONFIG_IPV6_RPL_LWTUNNEL=y
+CONFIG_IPV6_IOAM6_LWTUNNEL=y
+CONFIG_MPTCP=y
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_XFRM=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NFT_REJECT_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NF_FLOW_TABLE_PROCFS=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_IPMAC=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_FO=m
+CONFIG_IP_VS_OVF=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_MH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_TWOS=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_BPFILTER=y
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+CONFIG_RDS=m
+CONFIG_RDS_RDMA=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_BR2684=m
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_BRIDGE_MRP=y
+CONFIG_BRIDGE_CFM=y
+CONFIG_NET_DSA=m
+CONFIG_NET_DSA_TAG_GSWIP=m
+CONFIG_NET_DSA_TAG_KSZ=m
+CONFIG_NET_DSA_TAG_OCELOT=m
+CONFIG_NET_DSA_TAG_OCELOT_8021Q=m
+CONFIG_NET_DSA_TAG_SJA1105=m
+CONFIG_NET_DSA_TAG_TRAILER=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_DEBUGFS=y
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_CBS=m
+CONFIG_NET_SCH_ETF=m
+CONFIG_NET_SCH_TAPRIO=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_SCH_ETS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_CANID=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_EMATCH_IPT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_SAMPLE=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_MPLS=m
+CONFIG_NET_ACT_VLAN=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+CONFIG_NET_ACT_CTINFO=m
+CONFIG_NET_ACT_SKBMOD=m
+CONFIG_NET_ACT_IFE=m
+CONFIG_NET_ACT_TUNNEL_KEY=m
+CONFIG_NET_ACT_CT=m
+CONFIG_NET_ACT_GATE=m
+CONFIG_NET_IFE_SKBMARK=m
+CONFIG_NET_IFE_SKBPRIO=m
+CONFIG_NET_IFE_SKBTCINDEX=m
+CONFIG_NET_TC_SKB_EXT=y
+CONFIG_DCB=y
+CONFIG_BATMAN_ADV=m
+CONFIG_BATMAN_ADV_NC=y
+CONFIG_BATMAN_ADV_TRACING=y
+CONFIG_OPENVSWITCH=m
+CONFIG_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
+CONFIG_NETLINK_DIAG=y
+CONFIG_MPLS_ROUTING=m
+CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_NCSI=y
+CONFIG_NCSI_OEM_CMD_GET_MAC=y
+CONFIG_NCSI_OEM_CMD_KEEP_PHY=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_BPF_STREAM_PARSER=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NET_DROP_MONITOR=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HS=y
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_LEDS=y
+CONFIG_BT_MSFTEXT=y
+# CONFIG_BT_DEBUGFS is not set
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y
+CONFIG_BT_HCIBTUSB_MTK=y
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_NOKIA=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_HCIUART_INTEL=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIUART_AG6XX=y
+CONFIG_BT_HCIUART_MRVL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_BT_MTKSDIO=m
+CONFIG_BT_MTKUART=m
+CONFIG_BT_VIRTIO=m
+CONFIG_AF_RXRPC_IPV6=y
+CONFIG_AF_RXRPC_DEBUG=y
+CONFIG_RXKAD=y
+CONFIG_AF_KCM=m
+CONFIG_MCTP=y
+CONFIG_CFG80211=m
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_GPIO=m
+CONFIG_NET_9P=m
+CONFIG_NET_9P_VIRTIO=m
+CONFIG_NET_9P_RDMA=m
+CONFIG_CEPH_LIB_PRETTYDEBUG=y
+CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
+CONFIG_NFC=m
+CONFIG_NFC_DIGITAL=m
+CONFIG_NFC_NCI=m
+CONFIG_NFC_NCI_SPI=m
+CONFIG_NFC_HCI=m
+CONFIG_NFC_SHDLC=y
+CONFIG_NFC_TRF7970A=m
+CONFIG_NFC_SIM=m
+CONFIG_NFC_PORT100=m
+CONFIG_NFC_PN544_I2C=m
+CONFIG_NFC_PN533_USB=m
+CONFIG_NFC_PN533_I2C=m
+CONFIG_NFC_PN532_UART=m
+CONFIG_NFC_MICROREAD_I2C=m
+CONFIG_NFC_MRVL_USB=m
+CONFIG_NFC_ST21NFCA_I2C=m
+CONFIG_NFC_NXP_NCI=m
+CONFIG_NFC_NXP_NCI_I2C=m
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEAER_INJECT=m
+CONFIG_PCIE_ECRC=y
+CONFIG_PCIE_DPC=y
+CONFIG_PCIE_PTM=y
+CONFIG_PCI_STUB=y
+CONFIG_PCI_PF_STUB=m
+CONFIG_PCI_PRI=y
+CONFIG_PCI_PASID=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_SHPC=y
+CONFIG_PCI_FTPCI100=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCIE_XILINX=y
+CONFIG_PCIE_MICROCHIP_HOST=y
+CONFIG_PCIE_DW_PLAT_HOST=y
+CONFIG_PCIE_DW_PLAT_EP=y
+CONFIG_PCIE_FU740=y
+CONFIG_PCIE_CADENCE_PLAT_HOST=y
+CONFIG_PCIE_CADENCE_PLAT_EP=y
+CONFIG_PCIE_CADENCE_SOPHGO=y
+CONFIG_PCI_J721E_HOST=y
+CONFIG_PCI_J721E_EP=y
+CONFIG_PCI_ENDPOINT=y
+CONFIG_PCI_ENDPOINT_CONFIGFS=y
+CONFIG_PCI_SW_SWITCHTEC=m
+CONFIG_CXL_BUS=y
+CONFIG_CXL_MEM=m
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA is not set
+CONFIG_YENTA=m
+CONFIG_RAPIDIO=m
+CONFIG_RAPIDIO_TSI721=m
+CONFIG_RAPIDIO_DMA_ENGINE=y
+CONFIG_RAPIDIO_ENUM_BASIC=m
+CONFIG_RAPIDIO_CHMAN=m
+CONFIG_RAPIDIO_MPORT_CDEV=m
+CONFIG_RAPIDIO_CPS_XX=m
+CONFIG_RAPIDIO_CPS_GEN2=m
+CONFIG_RAPIDIO_RXS_GEN3=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DEVTMPFS_SAFE=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_FW_LOADER_COMPRESS_ZSTD=y
+CONFIG_DEBUG_DEVRES=y
+CONFIG_MHI_BUS_PCI_GENERIC=m
+CONFIG_CONNECTOR=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_SYSFB_SIMPLEFB=y
+# CONFIG_EFI_VARS_PSTORE is not set
+CONFIG_EFI_TEST=m
+CONFIG_RESET_ATTACK_MITIGATION=y
+CONFIG_EFI_COCO_SECRET=y
+CONFIG_GNSS=m
+CONFIG_GNSS_MTK_SERIAL=m
+CONFIG_GNSS_SIRF_SERIAL=m
+CONFIG_GNSS_UBX_SERIAL=m
+CONFIG_GNSS_USB=m
+CONFIG_MTD=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_CFI=m
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_MCHP48L640=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_RAW_NAND=m
+CONFIG_MTD_NAND_CADENCE=m
+CONFIG_MTD_NAND_NANDSIM=m
+CONFIG_MTD_NAND_ECC_MXIC=y
+CONFIG_MTD_SPI_NOR=m
+CONFIG_SPI_SOPHGO_SPIFMC=m
+CONFIG_MTD_UBI=m
+CONFIG_OF_OVERLAY=y
+CONFIG_BLK_DEV_NULL_BLK=m
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_VIRTIO_BLK=m
+CONFIG_BLK_DEV_RBD=m
+CONFIG_BLK_DEV_UBLK=m
+CONFIG_BLK_DEV_RNBD_CLIENT=m
+CONFIG_BLK_DEV_RNBD_SERVER=m
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+CONFIG_NVME_VERBOSE_ERRORS=y
+CONFIG_NVME_HWMON=y
+CONFIG_NVME_RDMA=m
+CONFIG_NVME_FC=m
+CONFIG_NVME_TCP=m
+CONFIG_NVME_AUTH=y
+CONFIG_NVME_TARGET=m
+CONFIG_NVME_TARGET_PASSTHRU=y
+CONFIG_NVME_TARGET_LOOP=m
+CONFIG_NVME_TARGET_RDMA=m
+CONFIG_NVME_TARGET_FC=m
+CONFIG_NVME_TARGET_FCLOOP=m
+CONFIG_NVME_TARGET_TCP=m
+CONFIG_NVME_TARGET_AUTH=y
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_APDS9802ALS=m
+CONFIG_ISL29003=m
+CONFIG_ISL29020=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_SRAM=y
+CONFIG_DW_XDATA_PCIE=m
+CONFIG_HISI_HIKEY_USB=m
+CONFIG_VCPU_STALL_DETECTOR=m
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_EEPROM_MAX6875=m
+CONFIG_EEPROM_IDT_89HPESX=m
+CONFIG_EEPROM_EE1004=m
+CONFIG_SENSORS_LIS3_I2C=m
+CONFIG_ECHO=m
+CONFIG_BCM_VK=m
+CONFIG_BCM_VK_TTY=y
+CONFIG_MISC_ALCOR_PCI=m
+CONFIG_MISC_RTSX_PCI=m
+CONFIG_MISC_RTSX_USB=m
+CONFIG_UACCE=m
+CONFIG_PVPANIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_ENCLOSURE=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=4
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=4
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVSAS_TASKLET=y
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_MPI3MR=m
+CONFIG_SCSI_SMARTPQI=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_BUSLOGIC=m
+CONFIG_SCSI_FLASHPOINT=y
+CONFIG_SCSI_MYRB=m
+CONFIG_SCSI_MYRS=m
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_FCOE=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_FDOMAIN_PCI=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_IPR=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_TCM_QLA2XXX=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_QEDI=m
+CONFIG_QEDF=m
+CONFIG_SCSI_EFCT=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_VIRTIO=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_MOBILE_LPM_POLICY=3
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_AHCI_DWC=m
+CONFIG_SATA_INIC162X=m
+CONFIG_SATA_ACARD_AHCI=m
+CONFIG_SATA_SIL24=m
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_PIIX=y
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_SIL=m
+CONFIG_SATA_SIS=m
+CONFIG_SATA_SVW=m
+CONFIG_SATA_ULI=m
+CONFIG_SATA_VIA=m
+CONFIG_SATA_VITESSE=m
+CONFIG_PATA_ALI=m
+CONFIG_PATA_AMD=m
+CONFIG_PATA_ARTOP=m
+CONFIG_PATA_ATP867X=m
+CONFIG_PATA_CMD64X=m
+CONFIG_PATA_EFAR=m
+CONFIG_PATA_HPT366=m
+CONFIG_PATA_HPT37X=m
+CONFIG_PATA_HPT3X2N=m
+CONFIG_PATA_HPT3X3=m
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_IT821X=m
+CONFIG_PATA_JMICRON=m
+CONFIG_PATA_MARVELL=m
+CONFIG_PATA_NETCELL=m
+CONFIG_PATA_NINJA32=m
+CONFIG_PATA_NS87415=m
+CONFIG_PATA_OPTIDMA=m
+CONFIG_PATA_PDC2027X=m
+CONFIG_PATA_PDC_OLD=m
+CONFIG_PATA_SERVERWORKS=m
+CONFIG_PATA_SIL680=m
+CONFIG_PATA_VIA=m
+CONFIG_PATA_WINBOND=m
+CONFIG_PATA_CMD640_PCI=m
+CONFIG_PATA_NS87410=m
+CONFIG_PATA_OPTI=m
+CONFIG_PATA_OF_PLATFORM=m
+CONFIG_ATA_GENERIC=m
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BCACHE=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING=y
+CONFIG_DM_UNSTRIPED=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_WRITECACHE=m
+CONFIG_DM_ERA=m
+CONFIG_DM_CLONE=m
+CONFIG_DM_MIRROR=y
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_MULTIPATH_HST=m
+CONFIG_DM_MULTIPATH_IOA=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_DUST=m
+CONFIG_DM_INIT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_FLAKEY=m
+CONFIG_DM_VERITY=m
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_DM_SWITCH=m
+CONFIG_DM_LOG_WRITES=m
+CONFIG_DM_INTEGRITY=m
+CONFIG_DM_ZONED=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_TCM_USER2=m
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_TCM_FC=m
+CONFIG_ISCSI_TARGET=m
+CONFIG_ISCSI_TARGET_CXGB4=m
+CONFIG_SBP_TARGET=m
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+CONFIG_FUSION_LOGGING=y
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_OHCI=m
+CONFIG_FIREWIRE_SBP2=m
+CONFIG_FIREWIRE_NET=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_EQUALIZER=m
+CONFIG_NET_FC=y
+CONFIG_IFB=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN=m
+CONFIG_IPVTAP=m
+CONFIG_VXLAN=m
+CONFIG_GENEVE=m
+CONFIG_BAREUDP=m
+CONFIG_GTP=m
+CONFIG_AMT=m
+CONFIG_MACSEC=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_RIONET=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+CONFIG_NLMON=m
+CONFIG_NET_VRF=m
+CONFIG_VSOCKMON=m
+CONFIG_MHI_NET=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_ENI=m
+CONFIG_ATM_NICSTAR=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_SOLOS=m
+CONFIG_B53_SPI_DRIVER=m
+CONFIG_B53_MDIO_DRIVER=m
+CONFIG_B53_MMAP_DRIVER=m
+CONFIG_B53_SRAB_DRIVER=m
+CONFIG_B53_SERDES=m
+CONFIG_NET_DSA_BCM_SF2=m
+CONFIG_NET_DSA_LOOP=m
+CONFIG_NET_DSA_HIRSCHMANN_HELLCREEK=m
+CONFIG_NET_DSA_MT7530=m
+CONFIG_NET_DSA_MV88E6XXX=m
+CONFIG_NET_DSA_MV88E6XXX_PTP=y
+CONFIG_NET_DSA_QCA8K=m
+CONFIG_NET_DSA_XRS700X_I2C=m
+CONFIG_NET_DSA_XRS700X_MDIO=m
+CONFIG_NET_DSA_REALTEK=m
+# CONFIG_NET_DSA_REALTEK_MDIO is not set
+# CONFIG_NET_DSA_REALTEK_SMI is not set
+CONFIG_NET_DSA_REALTEK_RTL8365MB=m
+CONFIG_NET_DSA_REALTEK_RTL8366RB=m
+CONFIG_NET_DSA_SMSC_LAN9303_I2C=m
+CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ET131X=m
+# CONFIG_NET_VENDOR_ALACRITECH is not set
+CONFIG_ACENIC=m
+CONFIG_ALTERA_TSE=m
+CONFIG_AMD8111_ETH=m
+CONFIG_PCNET32=m
+CONFIG_AQTION=m
+CONFIG_SPI_AX88796C=m
+CONFIG_SPI_AX88796C_COMPRESSION=y
+CONFIG_ATL2=m
+CONFIG_ATL1=m
+CONFIG_ATL1E=m
+CONFIG_ATL1C=m
+CONFIG_ALX=m
+CONFIG_B44=m
+CONFIG_BCMGENET=m
+CONFIG_TIGON3=m
+CONFIG_BNX2X=m
+CONFIG_BNXT=m
+CONFIG_BNXT_DCB=y
+CONFIG_MACB=m
+CONFIG_MACB_PCI=m
+# CONFIG_NET_VENDOR_CAVIUM is not set
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T4_DCB=y
+CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_IPSEC_INLINE=m
+CONFIG_CHELSIO_TLS_DEVICE=m
+CONFIG_ENIC=m
+# CONFIG_NET_VENDOR_CORTINA is not set
+CONFIG_DM9051=m
+CONFIG_DNET=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+CONFIG_TULIP_MMIO=y
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_ULI526X=m
+CONFIG_PCMCIA_XIRCOM=m
+CONFIG_DL2K=m
+CONFIG_SUNDANCE=m
+# CONFIG_BE2NET_HWMON is not set
+CONFIG_TSNEP=m
+# CONFIG_NET_VENDOR_EZCHIP is not set
+CONFIG_FUN_ETH=m
+# CONFIG_NET_VENDOR_HUAWEI is not set
+# CONFIG_NET_VENDOR_I825XX is not set
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_IGB=m
+CONFIG_IGBVF=m
+CONFIG_IXGB=m
+CONFIG_IXGBE=m
+CONFIG_IXGBE_DCB=y
+CONFIG_IXGBEVF=m
+CONFIG_I40E=m
+CONFIG_I40EVF=m
+CONFIG_ICE=m
+CONFIG_FM10K=m
+CONFIG_IGC=m
+CONFIG_NGBE=m
+CONFIG_TXGBE=m
+CONFIG_JME=m
+CONFIG_ADIN1110=m
+CONFIG_LITEX_LITEETH=y
+CONFIG_MVMDIO=m
+CONFIG_SKGE=m
+CONFIG_SKGE_GENESIS=y
+CONFIG_SKY2=m
+CONFIG_OCTEON_EP=m
+CONFIG_PRESTERA=m
+CONFIG_MLX4_EN=m
+CONFIG_MLX5_CORE=m
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_CORE_IPOIB=y
+CONFIG_MLX5_EN_IPSEC=y
+CONFIG_MLX5_EN_TLS=y
+CONFIG_MLX5_SF=y
+CONFIG_MLXSW_CORE=m
+CONFIG_KSZ884X_PCI=m
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_MICROSEMI is not set
+CONFIG_MYRI10GE=m
+CONFIG_FEALNX=m
+# CONFIG_NET_VENDOR_NI is not set
+CONFIG_NATSEMI=m
+CONFIG_NS83820=m
+CONFIG_S2IO=m
+CONFIG_NFP=m
+# CONFIG_NFP_APP_ABM_NIC is not set
+CONFIG_NE2K_PCI=m
+CONFIG_FORCEDETH=m
+CONFIG_ETHOC=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_IONIC=m
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_NETXEN_NIC=m
+CONFIG_QED=m
+CONFIG_QEDE=m
+CONFIG_BNA=m
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+CONFIG_R6040=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_8129=y
+CONFIG_R8169=m
+# CONFIG_NET_VENDOR_RENESAS is not set
+CONFIG_ROCKER=m
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_SC92031=m
+CONFIG_SIS900=m
+CONFIG_SIS190=m
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
+CONFIG_EPIC100=m
+CONFIG_SMSC911X=m
+CONFIG_SMSC9420=m
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_DWMAC_DWC_QOS_ETH=y
+CONFIG_STMMAC_PCI=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_CASSINI=m
+CONFIG_NIU=m
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+CONFIG_TEHUTI=m
+CONFIG_TLAN=m
+CONFIG_MSE102X=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5300=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_XILINX_EMACLITE=m
+CONFIG_XILINX_LL_TEMAC=m
+CONFIG_FDDI=m
+CONFIG_LED_TRIGGER_PHY=y
+CONFIG_SFP=m
+CONFIG_AMD_PHY=m
+CONFIG_ADIN_PHY=m
+CONFIG_AQUANTIA_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_BCM54140_PHY=m
+CONFIG_BCM87XX_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_CORTINA_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_INTEL_XWAY_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_MARVELL_10G_PHY=m
+CONFIG_MARVELL_88X2222_PHY=m
+CONFIG_MAXLINEAR_GPHY=m
+CONFIG_MICREL_PHY=m
+CONFIG_MICROSEMI_PHY=m
+CONFIG_MOTORCOMM_PHY=m
+CONFIG_NATIONAL_PHY=m
+CONFIG_NXP_C45_TJA11XX_PHY=m
+CONFIG_AT803X_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=y
+CONFIG_STE10XP=m
+CONFIG_TERANETICS_PHY=m
+CONFIG_DP83822_PHY=m
+CONFIG_DP83848_PHY=m
+CONFIG_DP83869_PHY=m
+CONFIG_VITESSE_PHY=m
+CONFIG_XILINX_GMII2RGMII=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_VXCAN=m
+CONFIG_CAN_CAN327=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_CTUCANFD_PCI=m
+CONFIG_CAN_CTUCANFD_PLATFORM=m
+CONFIG_CAN_IFI_CANFD=m
+CONFIG_CAN_M_CAN=m
+CONFIG_CAN_M_CAN_PCI=m
+CONFIG_CAN_PEAK_PCIEFD=m
+CONFIG_CAN_HI311X=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_8DEV_USB=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_ESD_USB=m
+CONFIG_CAN_GS_USB=m
+CONFIG_CAN_KVASER_USB=m
+CONFIG_CAN_MCBA_USB=m
+CONFIG_CAN_PEAK_USB=m
+CONFIG_MCTP_SERIAL=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_MDIO_MVUSB=m
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_CH9200=m
+CONFIG_USB_NET_AQC111=m
+# CONFIG_WLAN_VENDOR_ADMTEK is not set
+CONFIG_ATH5K=m
+CONFIG_ATH5K_DEBUG=y
+CONFIG_ATH9K=m
+CONFIG_ATH9K_AHB=y
+CONFIG_ATH9K_DEBUGFS=y
+CONFIG_ATH9K_PCI_NO_EEPROM=m
+CONFIG_ATH9K_HTC=m
+CONFIG_CARL9170=m
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_USB=m
+CONFIG_ATH6KL_DEBUG=y
+CONFIG_AR5523=m
+CONFIG_WIL6210=m
+CONFIG_ATH10K=m
+CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K_SDIO=m
+CONFIG_ATH10K_USB=m
+CONFIG_ATH10K_DEBUGFS=y
+CONFIG_WCN36XX=m
+CONFIG_ATH11K=m
+CONFIG_ATH11K_PCI=m
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+CONFIG_B43=m
+CONFIG_B43_SDIO=y
+CONFIG_B43LEGACY=m
+# CONFIG_B43LEGACY_DEBUG is not set
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMFMAC_PCIE=y
+# CONFIG_WLAN_VENDOR_CISCO is not set
+CONFIG_IWL4965=m
+CONFIG_IWL3945=m
+CONFIG_IWLEGACY_DEBUG=y
+CONFIG_IWLEGACY_DEBUGFS=y
+CONFIG_IWLWIFI=m
+CONFIG_IWLDVM=m
+CONFIG_IWLMVM=m
+CONFIG_IWLWIFI_DEBUG=y
+CONFIG_IWLWIFI_DEBUGFS=y
+# CONFIG_IWLWIFI_DEVICE_TRACING is not set
+CONFIG_HERMES=m
+CONFIG_HERMES_PRISM=y
+CONFIG_PLX_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ORINOCO_USB=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_P54_PCI=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_MESH=y
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MWIFIEX_PCIE=m
+CONFIG_MWIFIEX_USB=m
+CONFIG_MWL8K=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x0E=m
+CONFIG_MT76x2E=m
+CONFIG_MT76x2U=m
+CONFIG_MT7603E=m
+CONFIG_MT7615E=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+CONFIG_MT7921E=m
+CONFIG_MT7921S=m
+CONFIG_MT7921U=m
+# CONFIG_WLAN_VENDOR_PURELIFI is not set
+CONFIG_RT2X00=m
+CONFIG_RT2400PCI=m
+CONFIG_RT2500PCI=m
+CONFIG_RT61PCI=m
+CONFIG_RT2800PCI=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RT2X00_LIB_DEBUGFS=y
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8192CU=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTL8XXXU=m
+CONFIG_RTL8XXXU_UNTESTED=y
+CONFIG_RTW88=m
+CONFIG_RTW88_8822BE=m
+CONFIG_RTW88_8822CE=m
+CONFIG_RTW88_8723DE=m
+CONFIG_RTW88_8821CE=m
+CONFIG_RTW89=m
+CONFIG_RTW89_8852AE=m
+CONFIG_RTW89_8852CE=m
+CONFIG_RSI_91X=m
+# CONFIG_WLAN_VENDOR_SILABS is not set
+CONFIG_CW1200=m
+CONFIG_CW1200_WLAN_SDIO=m
+CONFIG_CW1200_WLAN_SPI=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX=m
+CONFIG_WL18XX=m
+CONFIG_WLCORE_SPI=m
+CONFIG_WLCORE_SDIO=m
+CONFIG_ZD1211RW=m
+CONFIG_QTNFMAC_PCIE=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_VIRT_WIFI=m
+CONFIG_WAN=y
+CONFIG_IEEE802154_FAKELB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_IEEE802154_ATUSB=m
+CONFIG_IEEE802154_ADF7242=m
+CONFIG_IEEE802154_CA8210=m
+CONFIG_IEEE802154_MCR20A=m
+CONFIG_WWAN=y
+CONFIG_MHI_WWAN_CTRL=m
+CONFIG_MHI_WWAN_MBIM=m
+CONFIG_RPMSG_WWAN_CTRL=m
+CONFIG_MTK_T7XX=m
+CONFIG_USB4_NET=m
+CONFIG_NETDEVSIM=m
+CONFIG_ISDN=y
+CONFIG_INPUT_SPARSEKMAP=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_QT1050=m
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_TM2_TOUCHKEY=m
+CONFIG_KEYBOARD_CYPRESS_SF=m
+# CONFIG_MOUSE_PS2 is not set
+CONFIG_MOUSE_APPLETOUCH=m
+CONFIG_MOUSE_BCM5974=m
+CONFIG_MOUSE_CYAPA=m
+CONFIG_MOUSE_ELAN_I2C=m
+CONFIG_MOUSE_ELAN_I2C_SMBUS=y
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_MOUSE_SYNAPTICS_I2C=m
+CONFIG_MOUSE_SYNAPTICS_USB=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADC=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_IFORCE_232=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_PXRC=m
+CONFIG_JOYSTICK_QWIIC=m
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=m
+CONFIG_TABLET_USB_AIPTEK=m
+CONFIG_TABLET_USB_HANWANG=m
+CONFIG_TABLET_USB_KBTAB=m
+CONFIG_TABLET_USB_PEGASUS=m
+CONFIG_TABLET_SERIAL_WACOM4=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_AUO_PIXCIR=m
+CONFIG_TOUCHSCREEN_CY8CTMA140=m
+CONFIG_TOUCHSCREEN_EETI=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_HYCON_HY46XX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_ILITEK=m
+CONFIG_TOUCHSCREEN_ELAN=m
+CONFIG_TOUCHSCREEN_WACOM_I2C=m
+CONFIG_TOUCHSCREEN_MCS5000=m
+CONFIG_TOUCHSCREEN_MMS114=m
+CONFIG_TOUCHSCREEN_MSG2638=m
+CONFIG_TOUCHSCREEN_IMAGIS=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_PIXCIR=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_TSC2007=m
+CONFIG_TOUCHSCREEN_TSC2007_IIO=y
+CONFIG_TOUCHSCREEN_RM_TS=m
+CONFIG_TOUCHSCREEN_SILEAD=m
+CONFIG_TOUCHSCREEN_SIS_I2C=m
+CONFIG_TOUCHSCREEN_ST1232=m
+CONFIG_TOUCHSCREEN_ZET6223=m
+CONFIG_TOUCHSCREEN_ZFORCE=m
+CONFIG_TOUCHSCREEN_IQS5XX=m
+CONFIG_TOUCHSCREEN_ZINITIX=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_E3X0_BUTTON=m
+CONFIG_INPUT_MAX77650_ONKEY=m
+CONFIG_INPUT_GPIO_VIBRA=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_KXTJ9=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_REGULATOR_HAPTIC=m
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_PWM_BEEPER=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_DA9063_ONKEY=m
+CONFIG_INPUT_IQS269A=m
+CONFIG_INPUT_IQS626A=m
+CONFIG_INPUT_IQS7222=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_INPUT_CMA3000_I2C=m
+CONFIG_RMI4_I2C=m
+CONFIG_RMI4_SPI=m
+CONFIG_RMI4_SMB=m
+CONFIG_RMI4_F34=y
+CONFIG_RMI4_F3A=y
+CONFIG_RMI4_F55=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_RAW=m
+CONFIG_SERIO_ALTERA_PS2=m
+CONFIG_SERIO_ARC_PS2=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
+CONFIG_SERIAL_8250_FINTEK=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXAR=m
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_KGDB_NMI=y
+CONFIG_SERIAL_MAX3100=m
+CONFIG_SERIAL_MAX310X=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_SC16IS7XX=m
+# CONFIG_SERIAL_SC16IS7XX_I2C is not set
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_LITEUART=y
+CONFIG_SERIAL_LITEUART_CONSOLE=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SYNCLINK_GT=m
+CONFIG_N_HDLC=m
+CONFIG_N_GSM=m
+CONFIG_NOZOMI=m
+CONFIG_NULL_TTY=m
+CONFIG_RPMSG_TTY=m
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=m
+CONFIG_VIRTIO_CONSOLE=m
+CONFIG_IPMI_HANDLER=y
+CONFIG_IPMI_DEVICE_INTERFACE=y
+CONFIG_IPMI_SI=y
+CONFIG_IPMI_SSIF=m
+CONFIG_IPMI_IPMB=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HW_RANDOM_XIPHERA=m
+CONFIG_TCG_TIS=y
+CONFIG_TCG_TIS_SPI=m
+CONFIG_TCG_TIS_SPI_CR50=y
+CONFIG_TCG_TIS_I2C=m
+CONFIG_TCG_TIS_I2C_CR50=m
+CONFIG_TCG_TIS_I2C_ATMEL=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
+CONFIG_TCG_TIS_I2C_NUVOTON=m
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_VTPM_PROXY=m
+CONFIG_XILLYBUS=m
+CONFIG_XILLYBUS_PCIE=m
+CONFIG_XILLYUSB=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_LTC4306=m
+CONFIG_I2C_MUX_MLXCPLD=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_NVIDIA_GPU=m
+CONFIG_I2C_DESIGNWARE_SLAVE=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_DESIGNWARE_PCI=m
+CONFIG_I2C_OCORES=y
+CONFIG_I2C_PCA_PLATFORM=m
+CONFIG_I2C_SIMTEC=m
+CONFIG_I2C_DIOLAN_U2C=m
+CONFIG_I2C_DLN2=m
+CONFIG_I2C_CP2615=m
+CONFIG_I2C_PCI1XXXX=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_I2C_VIRTIO=m
+CONFIG_I2C_STUB=m
+CONFIG_I2C_SLAVE_EEPROM=m
+CONFIG_SPI=y
+CONFIG_SPI_ALTERA_DFL=m
+CONFIG_SPI_DESIGNWARE=m
+CONFIG_SPI_DW_DMA=y
+CONFIG_SPI_DW_PCI=m
+CONFIG_SPI_DW_MMIO=m
+CONFIG_SPI_DLN2=m
+CONFIG_SPI_MICROCHIP_CORE=m
+CONFIG_SPI_SIFIVE=y
+CONFIG_SPI_AMD=y
+CONFIG_SPI_MUX=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SLAVE=y
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_DP83640_PHY=m
+CONFIG_PTP_1588_CLOCK_IDT82P33=m
+CONFIG_PTP_1588_CLOCK_IDTCM=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_CADENCE=m
+CONFIG_GPIO_DWAPB=m
+CONFIG_GPIO_EXAR=m
+CONFIG_GPIO_GENERIC_PLATFORM=m
+CONFIG_GPIO_SIFIVE=y
+CONFIG_GPIO_SYSCON=m
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA9570=m
+CONFIG_GPIO_BD9571MWV=m
+CONFIG_GPIO_DLN2=m
+CONFIG_GPIO_MAX77650=m
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_PCI_IDIO_16=m
+CONFIG_GPIO_AGGREGATOR=m
+CONFIG_GPIO_VIRTIO=m
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2405=m
+CONFIG_W1_SLAVE_DS2408=m
+# CONFIG_W1_SLAVE_DS2408_READBACK is not set
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2805=m
+CONFIG_W1_SLAVE_DS2430=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_LTC2952=y
+CONFIG_POWER_RESET_REGULATOR=y
+CONFIG_POWER_RESET_RESTART=y
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_BATTERY_CW2015=m
+CONFIG_BATTERY_SAMSUNG_SDI=y
+CONFIG_CHARGER_LT3651=m
+CONFIG_CHARGER_LTC4162L=m
+CONFIG_CHARGER_MAX77650=m
+CONFIG_CHARGER_MAX77976=m
+CONFIG_CHARGER_BQ2515X=m
+CONFIG_CHARGER_BQ256XX=m
+CONFIG_CHARGER_SMB347=m
+CONFIG_BATTERY_RT5033=m
+CONFIG_CHARGER_UCS1002=m
+CONFIG_CHARGER_BD99954=m
+CONFIG_BATTERY_UG3105=m
+CONFIG_SENSORS_AD7314=m
+CONFIG_SENSORS_AD7414=m
+CONFIG_SENSORS_AD7418=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_ADT7310=m
+CONFIG_SENSORS_ADT7410=m
+CONFIG_SENSORS_ADT7411=m
+CONFIG_SENSORS_ADT7462=m
+CONFIG_SENSORS_ADT7470=m
+CONFIG_SENSORS_ADT7475=m
+CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m
+CONFIG_SENSORS_ASC7621=m
+CONFIG_SENSORS_AXI_FAN_CONTROL=m
+CONFIG_SENSORS_ATXP1=m
+CONFIG_SENSORS_CORSAIR_CPRO=m
+CONFIG_SENSORS_CORSAIR_PSU=m
+CONFIG_SENSORS_DRIVETEMP=m
+CONFIG_SENSORS_DS620=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_F75375S=m
+CONFIG_SENSORS_FTSTEUTATES=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_G760A=m
+CONFIG_SENSORS_G762=m
+CONFIG_SENSORS_IBMAEM=m
+CONFIG_SENSORS_IBMPEX=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_POWR1220=m
+CONFIG_SENSORS_LINEAGE=m
+CONFIG_SENSORS_LTC2945=m
+CONFIG_SENSORS_LTC2947_I2C=m
+CONFIG_SENSORS_LTC2947_SPI=m
+CONFIG_SENSORS_LTC2990=m
+CONFIG_SENSORS_LTC4151=m
+CONFIG_SENSORS_LTC4215=m
+CONFIG_SENSORS_LTC4222=m
+CONFIG_SENSORS_LTC4245=m
+CONFIG_SENSORS_LTC4260=m
+CONFIG_SENSORS_LTC4261=m
+CONFIG_SENSORS_MAX1111=m
+CONFIG_SENSORS_MAX16065=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_MAX1668=m
+CONFIG_SENSORS_MAX197=m
+CONFIG_SENSORS_MAX31722=m
+CONFIG_SENSORS_MAX6620=m
+CONFIG_SENSORS_MAX6639=m
+CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_MAX6697=m
+CONFIG_SENSORS_MAX31790=m
+CONFIG_SENSORS_MCP3021=m
+CONFIG_SENSORS_TC654=m
+CONFIG_SENSORS_MR75203=m
+CONFIG_SENSORS_ADCXX=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM70=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_LM95234=m
+CONFIG_SENSORS_LM95241=m
+CONFIG_SENSORS_LM95245=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_NTC_THERMISTOR=m
+CONFIG_SENSORS_NCT6683=m
+CONFIG_SENSORS_NCT6775_I2C=m
+CONFIG_SENSORS_NCT7802=m
+CONFIG_SENSORS_NCT7904=m
+CONFIG_SENSORS_NPCM7XX=m
+CONFIG_SENSORS_NZXT_KRAKEN2=m
+CONFIG_SENSORS_NZXT_SMART2=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_PMBUS=m
+CONFIG_SENSORS_ADM1266=m
+CONFIG_SENSORS_ADM1275=m
+CONFIG_SENSORS_BEL_PFE=m
+CONFIG_SENSORS_BPA_RS600=m
+CONFIG_SENSORS_DELTA_AHE50DC_FAN=m
+CONFIG_SENSORS_FSP_3Y=m
+CONFIG_SENSORS_DPS920AB=m
+CONFIG_SENSORS_LM25066=m
+CONFIG_SENSORS_LM25066_REGULATOR=y
+CONFIG_SENSORS_LT7182S=m
+CONFIG_SENSORS_LTC2978=m
+CONFIG_SENSORS_LTC3815=m
+CONFIG_SENSORS_MAX16064=m
+CONFIG_SENSORS_MAX20751=m
+CONFIG_SENSORS_MAX34440=m
+CONFIG_SENSORS_MAX8688=m
+CONFIG_SENSORS_MP2888=m
+CONFIG_SENSORS_MP2975=m
+CONFIG_SENSORS_MP5023=m
+CONFIG_SENSORS_PIM4328=m
+CONFIG_SENSORS_PLI1209BC=m
+CONFIG_SENSORS_PLI1209BC_REGULATOR=y
+CONFIG_SENSORS_PM6764TR=m
+CONFIG_SENSORS_Q54SJ108A2=m
+CONFIG_SENSORS_TPS40422=m
+CONFIG_SENSORS_TPS53679=m
+CONFIG_SENSORS_UCD9000=m
+CONFIG_SENSORS_UCD9200=m
+CONFIG_SENSORS_XDPE152=m
+CONFIG_SENSORS_ZL6100=m
+CONFIG_SENSORS_PWM_FAN=y
+CONFIG_SENSORS_SBTSI=m
+CONFIG_SENSORS_SHT15=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_DME1737=m
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC6W201=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_SMSC47M192=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SCH5627=m
+CONFIG_SENSORS_SCH5636=m
+CONFIG_SENSORS_ADC128D818=m
+CONFIG_SENSORS_ADS7828=m
+CONFIG_SENSORS_ADS7871=m
+CONFIG_SENSORS_AMC6821=m
+CONFIG_SENSORS_INA209=m
+CONFIG_SENSORS_INA2XX=m
+CONFIG_SENSORS_INA238=m
+CONFIG_SENSORS_INA3221=m
+CONFIG_SENSORS_TC74=m
+CONFIG_SENSORS_THMC50=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_SENSORS_TMP103=m
+CONFIG_SENSORS_TMP108=m
+CONFIG_SENSORS_TMP401=m
+CONFIG_SENSORS_TMP421=m
+CONFIG_SENSORS_TMP464=m
+CONFIG_SENSORS_TMP513=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83773G=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83795=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83L786NG=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_SENSORS_INTEL_M10_BMC_HWMON=m
+CONFIG_THERMAL_NETLINK=y
+CONFIG_THERMAL_STATISTICS=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_DA9063_WATCHDOG=m
+CONFIG_MAX77620_WATCHDOG=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_USBPCWATCHDOG=m
+CONFIG_SSB_DRIVER_GPIO=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_MFD_BD9571MWV=m
+CONFIG_MFD_DA9063=m
+CONFIG_MFD_DLN2=m
+CONFIG_MFD_MAX77650=m
+CONFIG_MFD_MAX77714=m
+CONFIG_MFD_RT4831=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_VX855=m
+CONFIG_MFD_INTEL_M10_BMC=m
+CONFIG_MFD_RSMU_I2C=m
+CONFIG_MFD_RSMU_SPI=m
+CONFIG_REGULATOR_BD9571MWV=m
+CONFIG_REGULATOR_DA9063=m
+CONFIG_REGULATOR_MAX77650=m
+CONFIG_REGULATOR_MAX8893=m
+CONFIG_REGULATOR_MP5416=m
+CONFIG_REGULATOR_MP886X=m
+CONFIG_REGULATOR_PWM=y
+CONFIG_REGULATOR_RT4801=m
+CONFIG_REGULATOR_RT4831=m
+CONFIG_REGULATOR_RT5190A=m
+CONFIG_REGULATOR_RT5759=m
+CONFIG_REGULATOR_RT6160=m
+CONFIG_REGULATOR_RT6245=m
+CONFIG_REGULATOR_RTQ2134=m
+CONFIG_REGULATOR_RTMV20=m
+CONFIG_REGULATOR_RTQ6752=m
+CONFIG_REGULATOR_TPS6286X=m
+CONFIG_REGULATOR_VCTRL=m
+CONFIG_RC_CORE=y
+CONFIG_BPF_LIRC_MODE2=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=m
+CONFIG_RC_DECODERS=y
+CONFIG_IR_IMON_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_RCMM_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_HIX5HD2=m
+CONFIG_IR_IGORPLUGUSB=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_IMON=m
+CONFIG_IR_IMON_RAW=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_SERIAL=m
+CONFIG_IR_SERIAL_TRANSMITTER=y
+CONFIG_IR_SPI=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_TOY=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_RC_XBOX_DVD=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_CEC_SUPPORT=y
+CONFIG_CEC_CH7322=m
+CONFIG_USB_PULSE8_CEC=m
+CONFIG_USB_RAINSHADOW_CEC=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_SUPPORT_FILTER=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_RADIO_SUPPORT=y
+CONFIG_MEDIA_PLATFORM_SUPPORT=y
+CONFIG_VIDEO_FIXED_MINOR_RANGES=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_GSPCA=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_PWC=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_DVB_AS102=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_ZD1301=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_CXUSB_ANALOG=y
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_MEDIA_PCI_SUPPORT=y
+CONFIG_VIDEO_SOLO6X10=m
+CONFIG_VIDEO_TW686X=m
+CONFIG_VIDEO_IVTV=m
+CONFIG_VIDEO_FB_IVTV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_CX18=m
+CONFIG_VIDEO_CX18_ALSA=m
+CONFIG_VIDEO_CX23885=m
+CONFIG_MEDIA_ALTERA_CI=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_ALSA=m
+CONFIG_VIDEO_CX88_BLACKBIRD=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+CONFIG_VIDEO_SAA7134_DVB=m
+CONFIG_VIDEO_SAA7134_GO7007=m
+CONFIG_VIDEO_SAA7164=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_DDBRIDGE=m
+CONFIG_DVB_DM1105=m
+CONFIG_MANTIS_CORE=m
+CONFIG_DVB_MANTIS=m
+CONFIG_DVB_HOPPER=m
+CONFIG_DVB_NETUP_UNIDVB=m
+CONFIG_DVB_NGENE=m
+CONFIG_DVB_PLUTO2=m
+CONFIG_DVB_PT1=m
+CONFIG_DVB_SMIPCIE=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_RADIO_SI4713=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_WL1273=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_USB_MR800=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_CADENCE_CSI2RX=m
+CONFIG_VIDEO_CADENCE_CSI2TX=m
+CONFIG_SMS_SDIO_DRV=m
+CONFIG_DVB_FIREDTV=m
+CONFIG_VIDEO_AR0521=m
+CONFIG_VIDEO_HI556=m
+CONFIG_VIDEO_HI846=m
+CONFIG_VIDEO_HI847=m
+CONFIG_VIDEO_IMX208=m
+CONFIG_VIDEO_IMX214=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX258=m
+CONFIG_VIDEO_IMX274=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX319=m
+CONFIG_VIDEO_IMX334=m
+CONFIG_VIDEO_IMX335=m
+CONFIG_VIDEO_IMX355=m
+CONFIG_VIDEO_IMX412=m
+CONFIG_VIDEO_MT9M001=m
+CONFIG_VIDEO_MT9M032=m
+CONFIG_VIDEO_MT9P031=m
+CONFIG_VIDEO_MT9T001=m
+CONFIG_VIDEO_MT9T112=m
+CONFIG_VIDEO_MT9V032=m
+CONFIG_VIDEO_MT9V111=m
+CONFIG_VIDEO_NOON010PC30=m
+CONFIG_VIDEO_OG01A1B=m
+CONFIG_VIDEO_OV02A10=m
+CONFIG_VIDEO_OV08D10=m
+CONFIG_VIDEO_OV13858=m
+CONFIG_VIDEO_OV13B10=m
+CONFIG_VIDEO_OV2659=m
+CONFIG_VIDEO_OV2680=m
+CONFIG_VIDEO_OV2685=m
+CONFIG_VIDEO_OV5640=m
+CONFIG_VIDEO_OV5645=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV5648=m
+CONFIG_VIDEO_OV5670=m
+CONFIG_VIDEO_OV5675=m
+CONFIG_VIDEO_OV5693=m
+CONFIG_VIDEO_OV5695=m
+CONFIG_VIDEO_OV6650=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV772X=m
+CONFIG_VIDEO_OV7740=m
+CONFIG_VIDEO_OV8856=m
+CONFIG_VIDEO_OV8865=m
+CONFIG_VIDEO_OV9282=m
+CONFIG_VIDEO_OV9640=m
+CONFIG_VIDEO_OV9650=m
+CONFIG_VIDEO_RDACM20=m
+CONFIG_VIDEO_RJ54N1=m
+CONFIG_VIDEO_S5C73M3=m
+CONFIG_VIDEO_S5K4ECGX=m
+CONFIG_VIDEO_S5K5BAF=m
+CONFIG_VIDEO_S5K6A3=m
+CONFIG_VIDEO_S5K6AA=m
+CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_VS6624=m
+CONFIG_VIDEO_CCS=m
+CONFIG_VIDEO_ET8EK8=m
+CONFIG_VIDEO_M5MOLS=m
+CONFIG_VIDEO_AD5820=m
+CONFIG_VIDEO_AK7375=m
+CONFIG_VIDEO_DW9714=m
+CONFIG_VIDEO_DW9768=m
+CONFIG_VIDEO_DW9807_VCM=m
+CONFIG_VIDEO_ADP1653=m
+CONFIG_VIDEO_LM3560=m
+CONFIG_VIDEO_LM3646=m
+CONFIG_CXD2880_SPI_DRV=m
+CONFIG_VIDEO_GS1662=m
+CONFIG_DRM=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_DP_AUX_CHARDEV=y
+CONFIG_DRM_DP_CEC=y
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_RADEON_USERPTR=y
+CONFIG_DRM_AMDGPU=m
+CONFIG_DRM_AMDGPU_SI=y
+CONFIG_DRM_AMDGPU_CIK=y
+CONFIG_DRM_AMDGPU_USERPTR=y
+CONFIG_DRM_AMD_ACP=y
+CONFIG_DRM_AMD_DC_HDCP=y
+CONFIG_DRM_AMD_DC_SI=y
+CONFIG_DEBUG_KERNEL_DC=y
+CONFIG_DRM_NOUVEAU=m
+# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set
+CONFIG_DRM_VGEM=m
+CONFIG_DRM_VKMS=m
+CONFIG_DRM_UDL=m
+CONFIG_DRM_AST=m
+CONFIG_DRM_MGAG200=m
+CONFIG_DRM_QXL=m
+CONFIG_DRM_VIRTIO_GPU=m
+CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0=m
+CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m
+CONFIG_DRM_PANEL_DSI_CM=m
+CONFIG_DRM_PANEL_ELIDA_KD35T133=m
+CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02=m
+CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D=m
+CONFIG_DRM_PANEL_INNOLUX_EJ030NA=m
+CONFIG_DRM_PANEL_JDI_R63452=m
+CONFIG_DRM_PANEL_NOVATEK_NT35510=m
+CONFIG_DRM_PANEL_NOVATEK_NT35560=m
+CONFIG_DRM_PANEL_NOVATEK_NT35950=m
+CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m
+CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m
+CONFIG_DRM_PANEL_RONBO_RB070D30=m
+CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=m
+CONFIG_DRM_PANEL_SAMSUNG_DB7430=m
+CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m
+CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01=m
+CONFIG_DRM_PANEL_SEIKO_43WVF1G=m
+CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521=m
+CONFIG_DRM_PANEL_VISIONOX_RM69299=m
+CONFIG_DRM_PANEL_WIDECHIPS_WS2401=m
+CONFIG_DRM_CHIPONE_ICN6211=m
+CONFIG_DRM_CHRONTEL_CH7033=m
+CONFIG_DRM_DISPLAY_CONNECTOR=m
+CONFIG_DRM_ITE_IT6505=m
+CONFIG_DRM_LONTIUM_LT8912B=m
+CONFIG_DRM_LONTIUM_LT9611UXC=m
+CONFIG_DRM_PARADE_PS8640=m
+CONFIG_DRM_SII9234=m
+CONFIG_DRM_SIMPLE_BRIDGE=m
+CONFIG_DRM_TOSHIBA_TC358762=m
+CONFIG_DRM_TOSHIBA_TC358764=m
+CONFIG_DRM_TOSHIBA_TC358768=m
+CONFIG_DRM_TOSHIBA_TC358775=m
+CONFIG_DRM_TI_DLPC3433=m
+CONFIG_DRM_TI_TFP410=m
+CONFIG_DRM_TI_SN65DSI86=m
+CONFIG_DRM_TI_TPD12S015=m
+CONFIG_DRM_ANALOGIX_ANX6345=m
+CONFIG_DRM_ANALOGIX_ANX78XX=m
+CONFIG_DRM_ANALOGIX_ANX7625=m
+CONFIG_DRM_ETNAVIV=m
+CONFIG_DRM_BOCHS=m
+CONFIG_DRM_CIRRUS_QEMU=m
+CONFIG_DRM_GM12U320=m
+CONFIG_DRM_PANEL_MIPI_DBI=m
+CONFIG_DRM_SIMPLEDRM=y
+CONFIG_TINYDRM_HX8357D=m
+CONFIG_TINYDRM_ILI9163=m
+CONFIG_TINYDRM_ILI9225=m
+CONFIG_TINYDRM_ILI9341=m
+CONFIG_TINYDRM_ILI9486=m
+CONFIG_TINYDRM_MI0283QT=m
+CONFIG_TINYDRM_REPAPER=m
+CONFIG_TINYDRM_ST7586=m
+CONFIG_TINYDRM_ST7735R=m
+CONFIG_DRM_GUD=m
+CONFIG_DRM_SSD130X=m
+CONFIG_DRM_SSD130X_I2C=m
+CONFIG_DRM_SSD130X_SPI=m
+CONFIG_DRM_SMI=m
+CONFIG_DRM_SMI_HDMI=y
+CONFIG_DRM_SMI_PRIME=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_ASILIANT=y
+CONFIG_FB_IMSTT=y
+CONFIG_FB_EFI=y
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+CONFIG_FB_RADEON=y
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_SSD1307=m
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_PLATFORM=m
+CONFIG_BACKLIGHT_KTD253=m
+CONFIG_BACKLIGHT_PWM=m
+CONFIG_BACKLIGHT_RT4831=m
+CONFIG_BACKLIGHT_LP855X=m
+CONFIG_BACKLIGHT_ARCXCNN=m
+CONFIG_BACKLIGHT_LED=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_HRTIMER=m
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_SEQUENCER_OSS=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_SERIAL_GENERIC=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_OXYGEN=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CTXFI=m
+CONFIG_SND_DARLA20=m
+CONFIG_SND_GINA20=m
+CONFIG_SND_LAYLA20=m
+CONFIG_SND_DARLA24=m
+CONFIG_SND_GINA24=m
+CONFIG_SND_LAYLA24=m
+CONFIG_SND_MONA=m
+CONFIG_SND_MIA=m
+CONFIG_SND_ECHO3G=m
+CONFIG_SND_INDIGO=m
+CONFIG_SND_INDIGOIO=m
+CONFIG_SND_INDIGODJ=m
+CONFIG_SND_INDIGOIOX=m
+CONFIG_SND_INDIGODJX=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_LOLA=m
+CONFIG_SND_LX6464ES=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RIPTIDE=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_VIRTUOSO=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_INPUT_BEEP=y
+CONFIG_SND_HDA_INPUT_BEEP_MODE=0
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=m
+CONFIG_SND_HDA_CODEC_ANALOG=m
+CONFIG_SND_HDA_CODEC_SIGMATEL=m
+CONFIG_SND_HDA_CODEC_VIA=m
+CONFIG_SND_HDA_CODEC_HDMI=m
+CONFIG_SND_HDA_CODEC_CIRRUS=m
+CONFIG_SND_HDA_CODEC_CS8409=m
+CONFIG_SND_HDA_CODEC_CONEXANT=m
+CONFIG_SND_HDA_CODEC_CA0110=m
+CONFIG_SND_HDA_CODEC_CA0132=m
+CONFIG_SND_HDA_CODEC_CMEDIA=m
+CONFIG_SND_HDA_CODEC_SI3054=m
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=1
+CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM=y
+CONFIG_SND_HDA_PREALLOC_SIZE=2048
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_BCD2000=m
+CONFIG_SND_USB_POD=m
+CONFIG_SND_USB_PODHD=m
+CONFIG_SND_USB_TONEPORT=m
+CONFIG_SND_USB_VARIAX=m
+CONFIG_SND_DICE=m
+CONFIG_SND_OXFW=m
+CONFIG_SND_ISIGHT=m
+CONFIG_SND_FIREWORKS=m
+CONFIG_SND_BEBOB=m
+CONFIG_SND_FIREWIRE_DIGI00X=m
+CONFIG_SND_FIREWIRE_TASCAM=m
+CONFIG_SND_FIREWIRE_MOTU=m
+CONFIG_SND_FIREFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_ADI=m
+CONFIG_SND_SOC_ADI_AXI_I2S=m
+CONFIG_SND_SOC_ADI_AXI_SPDIF=m
+CONFIG_SND_SOC_SOF_TOPLEVEL=y
+CONFIG_SND_SOC_SOF_PCI=m
+CONFIG_SND_SOC_AC97_CODEC=m
+CONFIG_SND_SOC_ADAU1761_I2C=m
+CONFIG_SND_SOC_ADAU1761_SPI=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_ADAU7118_HW=m
+CONFIG_SND_SOC_ADAU7118_I2C=m
+CONFIG_SND_SOC_AK5558=m
+CONFIG_SND_SOC_AW8738=m
+CONFIG_SND_SOC_BD28623=m
+CONFIG_SND_SOC_BT_SCO=m
+CONFIG_SND_SOC_CS35L34=m
+CONFIG_SND_SOC_CS35L35=m
+CONFIG_SND_SOC_CS35L36=m
+CONFIG_SND_SOC_CS35L45_SPI=m
+CONFIG_SND_SOC_CS35L45_I2C=m
+CONFIG_SND_SOC_CS42L42=m
+CONFIG_SND_SOC_CS4234=m
+CONFIG_SND_SOC_CS43130=m
+CONFIG_SND_SOC_CX2072X=m
+CONFIG_SND_SOC_DA7213=m
+CONFIG_SND_SOC_DMIC=m
+CONFIG_SND_SOC_ES7134=m
+CONFIG_SND_SOC_ES8328_I2C=m
+CONFIG_SND_SOC_ES8328_SPI=m
+CONFIG_SND_SOC_HDA=m
+CONFIG_SND_SOC_MAX98088=m
+CONFIG_SND_SOC_MAX9867=m
+CONFIG_SND_SOC_MAX98927=m
+CONFIG_SND_SOC_MAX98520=m
+CONFIG_SND_SOC_MAX98373_I2C=m
+CONFIG_SND_SOC_MAX98390=m
+CONFIG_SND_SOC_MAX98396=m
+CONFIG_SND_SOC_PCM1789_I2C=m
+CONFIG_SND_SOC_PCM186X_I2C=m
+CONFIG_SND_SOC_PCM186X_SPI=m
+CONFIG_SND_SOC_PCM3060_I2C=m
+CONFIG_SND_SOC_PCM3060_SPI=m
+CONFIG_SND_SOC_RT5640=m
+CONFIG_SND_SOC_RT5659=m
+CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m
+CONFIG_SND_SOC_SIMPLE_MUX=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_TAS2562=m
+CONFIG_SND_SOC_TAS2764=m
+CONFIG_SND_SOC_TAS2770=m
+CONFIG_SND_SOC_TAS2780=m
+CONFIG_SND_SOC_TAS5805M=m
+CONFIG_SND_SOC_TAS6424=m
+CONFIG_SND_SOC_TDA7419=m
+CONFIG_SND_SOC_TLV320ADC3XXX=m
+CONFIG_SND_SOC_TLV320AIC32X4_I2C=m
+CONFIG_SND_SOC_TLV320AIC32X4_SPI=m
+CONFIG_SND_SOC_TLV320ADCX140=m
+CONFIG_SND_SOC_TSCS42XX=m
+CONFIG_SND_SOC_WM8524=m
+CONFIG_SND_SOC_WM8731_I2C=m
+CONFIG_SND_SOC_WM8731_SPI=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8940=m
+CONFIG_SND_SOC_ZL38060=m
+CONFIG_SND_SOC_MAX9759=m
+CONFIG_SND_SOC_NAU8824=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_AUDIO_GRAPH_CARD2=m
+CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE=m
+CONFIG_SND_VIRTIO=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACCUTOUCH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=m
+CONFIG_HID_APPLEIR=m
+CONFIG_HID_AUREAL=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CORSAIR=m
+CONFIG_HID_COUGAR=m
+CONFIG_HID_MACALLY=m
+CONFIG_HID_PRODIKEYS=m
+CONFIG_HID_CMEDIA=m
+CONFIG_HID_CP2112=m
+CONFIG_HID_CREATIVE_SB0540=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELAN=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_FT260=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_GFRM=m
+CONFIG_HID_GLORIOUS=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HOLTEK_FF=y
+CONFIG_HID_VIVALDI=m
+CONFIG_HID_GT683R=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_VIEWSONIC=m
+CONFIG_HID_XIAOMI=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_ICADE=m
+CONFIG_HID_ITE=m
+CONFIG_HID_JABRA=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LENOVO=m
+CONFIG_HID_LETSKETCH=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MALTRON=m
+CONFIG_HID_MAYFLASH=m
+CONFIG_HID_MEGAWORLD_FF=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NINTENDO=m
+CONFIG_NINTENDO_FF=y
+CONFIG_HID_NTI=m
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PENMOUNT=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PLANTRONICS=m
+CONFIG_HID_PLAYSTATION=m
+CONFIG_PLAYSTATION_FF=y
+CONFIG_HID_RAZER=m
+CONFIG_HID_PRIMAX=m
+CONFIG_HID_RETRODE=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAITEK=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SEMITEK=m
+CONFIG_HID_SIGMAMICRO=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_STEELSERIES=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_RMI=m
+CONFIG_HID_GREENASIA=m
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_TOPRE=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_UDRAW_PS3=m
+CONFIG_HID_U2FZERO=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_ZEROPLUS_FF=y
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_SENSOR_HUB=m
+CONFIG_HID_ALPS=m
+CONFIG_HID_MCP2221=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_I2C_HID_OF_ELAN=m
+CONFIG_USB_LED_TRIG=y
+CONFIG_USB_ULPI_BUS=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_LEDS_TRIGGER_USBPORT=m
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DBGCAP=y
+CONFIG_USB_XHCI_PCI_RENESAS=y
+CONFIG_USB_XHCI_PLATFORM=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=m
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=m
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_HCD_ISO=y
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USB_DWC2=m
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F8153X=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_UPD78F0730=m
+CONFIG_USB_SERIAL_XR=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_APPLE_MFI_FASTCHARGE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_HUB_USB251XB=m
+CONFIG_USB_HSIC_USB3503=m
+CONFIG_USB_HSIC_USB4604=m
+CONFIG_USB_CHAOSKEY=m
+CONFIG_USB_ONBOARD_HUB=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_NOP_USB_XCEIV=m
+CONFIG_TYPEC=m
+CONFIG_TYPEC_TCPM=m
+CONFIG_TYPEC_TCPCI=m
+CONFIG_TYPEC_TCPCI_MAXIM=m
+CONFIG_TYPEC_FUSB302=m
+CONFIG_TYPEC_UCSI=m
+CONFIG_UCSI_CCG=m
+CONFIG_UCSI_STM32G0=m
+CONFIG_TYPEC_TPS6598X=m
+CONFIG_TYPEC_RT1719=m
+CONFIG_TYPEC_HD3SS3220=m
+CONFIG_TYPEC_STUSB160X=m
+CONFIG_TYPEC_WUSB3801=m
+CONFIG_TYPEC_MUX_FSA4480=m
+CONFIG_TYPEC_MUX_PI3USB30532=m
+CONFIG_TYPEC_DP_ALTMODE=m
+CONFIG_TYPEC_NVIDIA_ALTMODE=m
+CONFIG_USB_ROLE_SWITCH=y
+CONFIG_MMC=y
+CONFIG_PWRSEQ_SD8787=m
+CONFIG_PWRSEQ_SIMPLE=m
+CONFIG_SDIO_UART=m
+CONFIG_MMC_CRYPTO=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_CADENCE=m
+CONFIG_MMC_SDHCI_SOPHGO=y
+CONFIG_MMC_ALCOR=m
+CONFIG_MMC_TIFM_SD=m
+CONFIG_MMC_SPI=y
+CONFIG_MMC_CB710=m
+CONFIG_MMC_VIA_SDMMC=m
+CONFIG_MMC_DW=m
+CONFIG_MMC_DW_PCI=m
+CONFIG_MMC_VUB300=m
+CONFIG_MMC_USHC=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
+CONFIG_MMC_CQHCI=y
+CONFIG_MMC_HSQ=m
+CONFIG_MMC_SDHCI_XENON=m
+CONFIG_MMC_LITEX=y
+CONFIG_MEMSTICK=m
+CONFIG_MSPRO_BLOCK=m
+CONFIG_MEMSTICK_TIFM_MS=m
+CONFIG_MEMSTICK_JMICRON_38X=m
+CONFIG_MEMSTICK_R592=m
+CONFIG_MEMSTICK_REALTEK_PCI=m
+CONFIG_MEMSTICK_REALTEK_USB=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+CONFIG_LEDS_CLASS_MULTICOLOR=m
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
+CONFIG_LEDS_AN30259A=m
+CONFIG_LEDS_CR0014114=m
+CONFIG_LEDS_LM3530=m
+CONFIG_LEDS_LM3532=m
+CONFIG_LEDS_LM3692X=m
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_LP3952=m
+CONFIG_LEDS_LP50XX=m
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+CONFIG_LEDS_LT3593=m
+CONFIG_LEDS_MAX77650=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_BLINKM=m
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_MLXREG=m
+CONFIG_LEDS_USER=m
+CONFIG_LEDS_AS3645A=m
+CONFIG_LEDS_LM3601X=m
+CONFIG_LEDS_PWM_MULTICOLOR=m
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_MTD=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_ACTIVITY=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_PATTERN=m
+CONFIG_LEDS_TRIGGER_TTY=m
+CONFIG_ACCESSIBILITY=y
+CONFIG_A11Y_BRAILLE_CONSOLE=y
+CONFIG_SPEAKUP=m
+CONFIG_SPEAKUP_SYNTH_ACNTSA=m
+CONFIG_SPEAKUP_SYNTH_APOLLO=m
+CONFIG_SPEAKUP_SYNTH_AUDPTR=m
+CONFIG_SPEAKUP_SYNTH_BNS=m
+CONFIG_SPEAKUP_SYNTH_DECTLK=m
+CONFIG_SPEAKUP_SYNTH_LTLK=m
+CONFIG_SPEAKUP_SYNTH_SOFT=m
+CONFIG_SPEAKUP_SYNTH_SPKOUT=m
+CONFIG_SPEAKUP_SYNTH_TXPRT=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_CXGB4=m
+CONFIG_INFINIBAND_EFA=m
+CONFIG_INFINIBAND_ERDMA=m
+CONFIG_INFINIBAND_IRDMA=m
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_MLX5_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QEDR=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_INFINIBAND_IPOIB_CM=y
+CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
+CONFIG_INFINIBAND_SRP=m
+CONFIG_INFINIBAND_SRPT=m
+CONFIG_INFINIBAND_ISER=m
+CONFIG_INFINIBAND_ISERT=m
+CONFIG_INFINIBAND_RTRS_CLIENT=m
+CONFIG_INFINIBAND_RTRS_SERVER=m
+CONFIG_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_ABEOZ9=m
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1374_WDT=y
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_MAX77686=m
+CONFIG_RTC_DRV_NCT3018Y=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_ISL12026=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_M41T80_WDT=y
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8010=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_RV3032=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1343=m
+CONFIG_RTC_DRV_DS1347=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_MAX6916=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_MCP795=m
+CONFIG_RTC_DRV_DS3232=m
+# CONFIG_RTC_DRV_DS3232_HWMON is not set
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_RTC_DRV_DS1286=m
+CONFIG_RTC_DRV_DS1511=m
+CONFIG_RTC_DRV_DS1553=m
+CONFIG_RTC_DRV_DS1685_FAMILY=m
+CONFIG_RTC_DRV_DS1742=m
+CONFIG_RTC_DRV_DS2404=m
+CONFIG_RTC_DRV_DA9063=m
+CONFIG_RTC_DRV_STK17TA8=m
+CONFIG_RTC_DRV_M48T35=m
+CONFIG_RTC_DRV_M48T59=m
+CONFIG_RTC_DRV_MSM6242=m
+CONFIG_RTC_DRV_BQ4802=m
+CONFIG_RTC_DRV_RP5C01=m
+CONFIG_RTC_DRV_V3020=m
+CONFIG_RTC_DRV_R7301=m
+CONFIG_RTC_DRV_ASTBMC=y
+CONFIG_DMADEVICES=y
+CONFIG_ALTERA_MSGDMA=m
+CONFIG_DW_DMAC=m
+CONFIG_DW_DMAC_PCI=m
+CONFIG_DW_EDMA_PCIE=m
+CONFIG_SF_PDMA=y
+CONFIG_ASYNC_TX_DMA=y
+CONFIG_SW_SYNC=y
+CONFIG_UDMABUF=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_SYSFS_STATS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_AUXDISPLAY=y
+CONFIG_HD44780=m
+CONFIG_HT16K33=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_UIO_DFL=m
+CONFIG_VFIO=m
+CONFIG_VFIO_PCI=m
+CONFIG_MLX5_VFIO_PCI=m
+CONFIG_VFIO_MDEV=m
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_VDPA=m
+CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=m
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VDPA=m
+CONFIG_VDPA_SIM=m
+CONFIG_VDPA_SIM_NET=m
+CONFIG_VDPA_SIM_BLOCK=m
+CONFIG_VDPA_USER=m
+CONFIG_IFCVF=m
+CONFIG_MLX5_VDPA_NET=m
+CONFIG_VP_VDPA=m
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_SCSI=m
+CONFIG_VHOST_VSOCK=m
+CONFIG_VHOST_VDPA=m
+CONFIG_STAGING=y
+CONFIG_RTLLIB=m
+CONFIG_RTL8192E=m
+CONFIG_RTL8723BS=m
+CONFIG_R8712U=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_QLGE=m
+CONFIG_VME_BUS=y
+CONFIG_COMMON_CLK_SI544=m
+CONFIG_COMMON_CLK_AXI_CLKGEN=m
+CONFIG_COMMON_CLK_PWM=m
+CONFIG_COMMON_CLK_RS9_PCIE=m
+CONFIG_COMMON_CLK_FIXED_MMIO=y
+CONFIG_XILINX_VCU=m
+CONFIG_HWSPINLOCK=y
+CONFIG_MAILBOX=y
+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
+CONFIG_REMOTEPROC=y
+CONFIG_RPMSG_CHAR=m
+CONFIG_RPMSG_CTRL=m
+CONFIG_RPMSG_VIRTIO=m
+CONFIG_LITEX_SOC_CONTROLLER=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m
+CONFIG_DEVFREQ_GOV_PERFORMANCE=m
+CONFIG_DEVFREQ_GOV_POWERSAVE=m
+CONFIG_DEVFREQ_GOV_USERSPACE=m
+CONFIG_DEVFREQ_GOV_PASSIVE=m
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_EXTCON_USBC_TUSB320=m
+CONFIG_MEMORY=y
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER_DMAENGINE=m
+CONFIG_IIO_BUFFER_HW_CONSUMER=m
+CONFIG_IIO_SW_DEVICE=m
+CONFIG_IIO_SW_TRIGGER=m
+CONFIG_IIO_TRIGGERED_EVENT=m
+CONFIG_ADXL313_I2C=m
+CONFIG_ADXL313_SPI=m
+CONFIG_ADXL355_I2C=m
+CONFIG_ADXL355_SPI=m
+CONFIG_ADXL367_SPI=m
+CONFIG_ADXL367_I2C=m
+CONFIG_ADXL372_SPI=m
+CONFIG_ADXL372_I2C=m
+CONFIG_BMC150_ACCEL=m
+CONFIG_DA280=m
+CONFIG_DA311=m
+CONFIG_DMARD10=m
+CONFIG_HID_SENSOR_ACCEL_3D=m
+CONFIG_IIO_ST_ACCEL_3AXIS=m
+CONFIG_KXCJK1013=m
+CONFIG_MMA7660=m
+CONFIG_MXC4005=m
+CONFIG_MXC6255=m
+CONFIG_SCA3300=m
+CONFIG_AD7124=m
+CONFIG_AD7292=m
+CONFIG_AD7766=m
+CONFIG_AD7949=m
+CONFIG_DLN2_ADC=m
+CONFIG_ENVELOPE_DETECTOR=m
+CONFIG_MAX1241=m
+CONFIG_MAX1363=m
+CONFIG_MCP3911=m
+CONFIG_TI_ADC128S052=m
+CONFIG_TI_ADS1015=m
+CONFIG_TI_ADS8344=m
+CONFIG_TI_ADS131E08=m
+CONFIG_TI_TSC2046=m
+CONFIG_AD74413R=m
+CONFIG_IIO_RESCALE=m
+CONFIG_HMC425=m
+CONFIG_BME680=m
+CONFIG_PMS7003=m
+CONFIG_SCD30_CORE=m
+CONFIG_SCD30_I2C=m
+CONFIG_SCD30_SERIAL=m
+CONFIG_AD3552R=m
+CONFIG_LTC2688=m
+CONFIG_AD5766=m
+CONFIG_AD5770R=m
+CONFIG_AD7293=m
+CONFIG_DPOT_DAC=m
+CONFIG_LTC1660=m
+CONFIG_TI_DAC7311=m
+CONFIG_ADXRS290=m
+CONFIG_FXAS21002C=m
+CONFIG_HID_SENSOR_GYRO_3D=m
+CONFIG_MPU3050_I2C=m
+CONFIG_IIO_ST_GYRO_3AXIS=m
+CONFIG_MAX30100=m
+CONFIG_DHT11=m
+CONFIG_HDC2010=m
+CONFIG_HID_SENSOR_HUMIDITY=m
+CONFIG_HTS221=m
+CONFIG_ADIS16475=m
+CONFIG_FXOS8700_I2C=m
+CONFIG_FXOS8700_SPI=m
+CONFIG_INV_ICM42600_I2C=m
+CONFIG_INV_ICM42600_SPI=m
+CONFIG_IIO_ST_LSM6DSX=m
+CONFIG_ADUX1020=m
+CONFIG_AL3010=m
+CONFIG_BH1750=m
+CONFIG_CM32181=m
+CONFIG_CM3605=m
+CONFIG_GP2AP002=m
+CONFIG_HID_SENSOR_ALS=m
+CONFIG_RPR0521=m
+CONFIG_LTR501=m
+CONFIG_LV0104CS=m
+CONFIG_MAX44009=m
+CONFIG_OPT3001=m
+CONFIG_PA12203001=m
+CONFIG_STK3310=m
+CONFIG_ST_UVIS25=m
+CONFIG_TSL2772=m
+CONFIG_VCNL4035=m
+CONFIG_VEML6030=m
+CONFIG_VL6180=m
+CONFIG_ZOPT2201=m
+CONFIG_HID_SENSOR_MAGNETOMETER_3D=m
+CONFIG_IIO_ST_MAGN_3AXIS=m
+CONFIG_SENSORS_RM3100_I2C=m
+CONFIG_SENSORS_RM3100_SPI=m
+CONFIG_IIO_MUX=m
+CONFIG_HID_SENSOR_INCLINOMETER_3D=m
+CONFIG_HID_SENSOR_DEVICE_ROTATION=m
+CONFIG_IIO_INTERRUPT_TRIGGER=m
+CONFIG_IIO_TIGHTLOOP_TRIGGER=m
+CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m
+CONFIG_AD5110=m
+CONFIG_AD5272=m
+CONFIG_MCP4018=m
+CONFIG_MCP41010=m
+CONFIG_LMP91000=m
+CONFIG_ABP060MG=m
+CONFIG_BMP280=m
+CONFIG_ICP10100=m
+CONFIG_MPL115_I2C=m
+CONFIG_MB1232=m
+CONFIG_SX9310=m
+CONFIG_SX9324=m
+CONFIG_SX9360=m
+CONFIG_VCNL3020=m
+CONFIG_VL53L0X_I2C=m
+CONFIG_LTC2983=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_HID_SENSOR_TEMP=m
+CONFIG_MLX90614=m
+CONFIG_MLX90632=m
+CONFIG_TMP117=m
+CONFIG_MAX31856=m
+CONFIG_MAX31865=m
+CONFIG_PWM=y
+CONFIG_PWM_DWC=m
+CONFIG_PWM_SIFIVE=y
+CONFIG_PWM_STMPE=y
+CONFIG_RESET_TI_TPS380X=m
+CONFIG_PHY_CADENCE_TORRENT=m
+CONFIG_PHY_CADENCE_DPHY_RX=m
+CONFIG_PHY_CADENCE_SIERRA=m
+CONFIG_PHY_CADENCE_SALVO=m
+CONFIG_POWERCAP=y
+CONFIG_DTPM=y
+CONFIG_USB4=y
+CONFIG_DAX=y
+CONFIG_DEV_DAX=m
+CONFIG_NVMEM_RMEM=m
+CONFIG_FPGA=m
+CONFIG_ALTERA_PR_IP_CORE=m
+CONFIG_ALTERA_PR_IP_CORE_PLAT=m
+CONFIG_FPGA_MGR_ALTERA_PS_SPI=m
+CONFIG_FPGA_MGR_ALTERA_CVP=m
+CONFIG_FPGA_MGR_XILINX_SPI=m
+CONFIG_FPGA_MGR_ICE40_SPI=m
+CONFIG_FPGA_MGR_MACHXO2_SPI=m
+CONFIG_XILINX_PR_DECOUPLER=m
+CONFIG_OF_FPGA_REGION=m
+CONFIG_FPGA_DFL=m
+CONFIG_FPGA_DFL_FME=m
+CONFIG_FPGA_DFL_FME_MGR=m
+CONFIG_FPGA_DFL_FME_BRIDGE=m
+CONFIG_FPGA_DFL_FME_REGION=m
+CONFIG_FPGA_DFL_AFU=m
+CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000=m
+CONFIG_FPGA_DFL_PCI=m
+CONFIG_FPGA_M10_BMC_SEC_UPDATE=m
+CONFIG_MUX_ADG792A=m
+CONFIG_MUX_GPIO=m
+CONFIG_MUX_MMIO=m
+CONFIG_INTERCONNECT=y
+CONFIG_VALIDATE_FS_PARSER=y
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_DEBUG=y
+CONFIG_JBD2_DEBUG=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_ONLINE_SCRUB=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+# CONFIG_OCFS2_FS_STATS is not set
+# CONFIG_OCFS2_DEBUG_MASKLOG is not set
+CONFIG_BTRFS_FS=y
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=m
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_F2FS_FS_COMPRESSION=y
+CONFIG_F2FS_UNFAIR_RWSEM=y
+CONFIG_ZONEFS_FS=m
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
+CONFIG_FS_VERITY=y
+CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_VIRTIO_FS=m
+CONFIG_OVERLAY_FS=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_NTFS3_FS=m
+CONFIG_NTFS3_64BIT_CLUSTER=y
+CONFIG_NTFS3_LZX_XPRESS=y
+CONFIG_NTFS3_FS_POSIX_ACL=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_VMCORE_DEVICE_DUMP=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
+CONFIG_HUGETLBFS=y
+CONFIG_EFIVAR_FS=y
+CONFIG_ORANGEFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ECRYPT_FS=m
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_UBIFS_FS=m
+CONFIG_UBIFS_ATIME_SUPPORT=y
+CONFIG_UBIFS_FS_AUTHENTICATION=y
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZSTD=y
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_PSTORE=y
+CONFIG_PSTORE_LZO_COMPRESS=m
+CONFIG_PSTORE_LZ4_COMPRESS=m
+CONFIG_PSTORE_LZ4HC_COMPRESS=m
+CONFIG_PSTORE_842_COMPRESS=y
+CONFIG_PSTORE_ZSTD_COMPRESS=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_PMSG=y
+CONFIG_PSTORE_RAM=m
+CONFIG_PSTORE_BLK=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_EROFS_FS=m
+CONFIG_EROFS_FS_ZIP_LZMA=y
+CONFIG_NFS_FS=m
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFS_V4_2_READ_PLUS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_BLOCKLAYOUT=y
+CONFIG_NFSD_SCSILAYOUT=y
+CONFIG_NFSD_FLEXFILELAYOUT=y
+CONFIG_NFSD_V4_2_INTER_SSC=y
+CONFIG_NFSD_V4_SECURITY_LABEL=y
+CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_CEPH_FS=m
+CONFIG_CEPH_FSCACHE=y
+CONFIG_CEPH_FS_POSIX_ACL=y
+CONFIG_CEPH_FS_SECURITY_LABEL=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_SWN_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_SMB_SERVER=m
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+CONFIG_AFS_DEBUG=y
+CONFIG_AFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FSCACHE=y
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_9P_FS_SECURITY=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_MAC_ROMAN=m
+CONFIG_NLS_MAC_CELTIC=m
+CONFIG_NLS_MAC_CENTEURO=m
+CONFIG_NLS_MAC_CROATIAN=m
+CONFIG_NLS_MAC_CYRILLIC=m
+CONFIG_NLS_MAC_GAELIC=m
+CONFIG_NLS_MAC_GREEK=m
+CONFIG_NLS_MAC_ICELAND=m
+CONFIG_NLS_MAC_INUIT=m
+CONFIG_NLS_MAC_ROMANIAN=m
+CONFIG_NLS_MAC_TURKISH=m
+CONFIG_DLM=m
+CONFIG_DLM_DEBUG=y
+CONFIG_UNICODE=y
+CONFIG_KEYS_REQUEST_CACHE=y
+CONFIG_PERSISTENT_KEYRINGS=y
+CONFIG_BIG_KEYS=y
+CONFIG_TRUSTED_KEYS=y
+CONFIG_KEY_DH_OPERATIONS=y
+CONFIG_KEY_NOTIFICATIONS=y
+CONFIG_SECURITY_DMESG_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_INFINIBAND=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_LSM_MMAP_MIN_ADDR=65535
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_SMACK_NETFILTER=y
+CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_YAMA=y
+CONFIG_SECURITY_SAFESETID=y
+CONFIG_SECURITY_LOCKDOWN_LSM=y
+CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
+CONFIG_SECURITY_LANDLOCK=y
+CONFIG_INTEGRITY_SIGNATURE=y
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
+CONFIG_INTEGRITY_PLATFORM_KEYRING=y
+CONFIG_IMA=y
+CONFIG_IMA_KEXEC=y
+CONFIG_IMA_DEFAULT_HASH_SHA256=y
+CONFIG_IMA_WRITE_POLICY=y
+CONFIG_IMA_APPRAISE=y
+CONFIG_IMA_ARCH_POLICY=y
+CONFIG_IMA_APPRAISE_MODSIG=y
+# CONFIG_IMA_TRUSTED_KEYRING is not set
+CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY=y
+CONFIG_EVM=y
+CONFIG_EVM_EXTRA_SMACK_XATTRS=y
+CONFIG_EVM_ADD_XATTRS=y
+CONFIG_LSM="lockdown,yama,integrity,selinux,bpf,landlock"
+CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
+CONFIG_CRYPTO_FIPS=y
+CONFIG_CRYPTO_USER=m
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_ECDH=y
+CONFIG_CRYPTO_ECDSA=y
+CONFIG_CRYPTO_ECRDSA=m
+CONFIG_CRYPTO_CURVE25519=m
+CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_CFB=y
+CONFIG_CRYPTO_HCTR2=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=y
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=y
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_DRBG_HASH=y
+CONFIG_CRYPTO_DRBG_CTR=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRYPTO_USER_API_RNG=y
+CONFIG_CRYPTO_USER_API_AEAD=y
+# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set
+CONFIG_CRYPTO_STATS=y
+CONFIG_CRYPTO_DEV_ATMEL_ECC=m
+CONFIG_CRYPTO_DEV_ATMEL_SHA204A=m
+CONFIG_CRYPTO_DEV_QAT_DH895xCC=m
+CONFIG_CRYPTO_DEV_QAT_C3XXX=m
+CONFIG_CRYPTO_DEV_QAT_C62X=m
+CONFIG_CRYPTO_DEV_QAT_4XXX=m
+CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m
+CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m
+CONFIG_CRYPTO_DEV_QAT_C62XVF=m
+CONFIG_CRYPTO_DEV_CHELSIO=m
+CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
+CONFIG_SIGNED_PE_FILE_VERIFICATION=y
+CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
+CONFIG_SECONDARY_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+CONFIG_SYSTEM_REVOCATION_LIST=y
+CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE=y
+# CONFIG_RAID6_PQ_BENCHMARK is not set
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y
+CONFIG_CRC4=m
+CONFIG_DMA_RESTRICTED_POOL=y
+CONFIG_DMA_PERNUMA_CMA=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_FONT_6x10=y
+CONFIG_FONT_TER16x32=y
+CONFIG_FONT_6x8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_CONSOLE_LOGLEVEL_QUIET=3
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_DEBUG_MISC is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_HEADERS_INSTALL=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0
+CONFIG_KGDB=y
+CONFIG_KGDB_TESTS=y
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_POISONING=y
+CONFIG_DEBUG_RODATA_TEST=y
+CONFIG_DEBUG_WX=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_KFENCE=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_LOCK_TORTURE_TEST=m
+CONFIG_BUG_ON_DATA_CORRUPTION=y
+CONFIG_RCU_TORTURE_TEST=m
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_TRACE is not set
+CONFIG_LATENCYTOP=y
+CONFIG_BOOTTIME_TRACING=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_HWLAT_TRACER=y
+CONFIG_TIMERLAT_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_SYNTH_EVENTS=y
+CONFIG_RING_BUFFER_BENCHMARK=m
+CONFIG_TRACE_EVAL_MAP_FILE=y
+CONFIG_IO_STRICT_DEVMEM=y
+CONFIG_KUNIT=m
+CONFIG_KUNIT_ALL_TESTS=m
+CONFIG_FUNCTION_ERROR_INJECTION=y
+# CONFIG_TEST_LIST_SORT is not set
+CONFIG_ATOMIC64_SELFTEST=y
+CONFIG_ASYNC_RAID6_TEST=m
+CONFIG_TEST_KSTRTOX=y
+CONFIG_TEST_VMALLOC=m
+CONFIG_TEST_BPF=m
+CONFIG_LINEAR_RANGES_TEST=m
diff --git a/arch/riscv/configs/sophgo_mango_normal_defconfig b/arch/riscv/configs/sophgo_mango_normal_defconfig
new file mode 100644
index 000000000000..bd24d72ef690
--- /dev/null
+++ b/arch/riscv/configs/sophgo_mango_normal_defconfig
@@ -0,0 +1,188 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_DEFAULT_HOSTNAME="mango"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=13
+CONFIG_NUMA_BALANCING=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPUSETS=y
+# CONFIG_PROC_PID_CPUSET is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_MISC=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+# CONFIG_SYSFS_SYSCALL is not set
+CONFIG_PERF_EVENTS=y
+CONFIG_ARCH_SOPHGO=y
+CONFIG_ERRATA_THEAD=y
+CONFIG_SMP=y
+CONFIG_SCHED_CLUSTER=y
+CONFIG_NR_CPUS=128
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=3
+CONFIG_HZ_100=y
+CONFIG_KEXEC=y
+CONFIG_KEXEC_FILE=y
+# CONFIG_STACKPROTECTOR is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
+# CONFIG_SWAP is not set
+# CONFIG_SPARSEMEM_VMEMMAP is not set
+CONFIG_PAGE_REPORTING=y
+CONFIG_KSM=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_CADENCE_PLAT_HOST=y
+CONFIG_PCIE_CADENCE_SOPHGO=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+CONFIG_NVME_VERBOSE_ERRORS=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_NETDEVICES=y
+CONFIG_ETHOC=y
+CONFIG_R8169=y
+CONFIG_STMMAC_ETH=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_LEGACY_PTY_COUNT=10
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+# CONFIG_PTP_1588_CLOCK is not set
+CONFIG_PINCTRL=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_DWAPB=y
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_PWM_FAN=y
+CONFIG_THERMAL=y
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_DRM_AMDGPU=y
+CONFIG_DRM_SMI=y
+CONFIG_DRM_SMI_HDMI=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_RADEON=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DBGCAP=y
+CONFIG_USB_XHCI_PLATFORM=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC2=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_SOPHGO=y
+CONFIG_RTC_CLASS=y
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_PWM=y
+CONFIG_PWM_SIFIVE=y
+CONFIG_GENERIC_PHY=y
+CONFIG_RAS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_EFIVAR_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_SECURITYFS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_VM_PGTABLE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_DEBUG_TIMEKEEPING=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_RWSEMS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_PLIST=y
+CONFIG_DEBUG_SG=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_EQS_DEBUG=y
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_MEMTEST=y
diff --git a/arch/riscv/configs/sophgo_mango_ubuntu_defconfig b/arch/riscv/configs/sophgo_mango_ubuntu_defconfig
new file mode 100644
index 000000000000..b2537d65aed5
--- /dev/null
+++ b/arch/riscv/configs/sophgo_mango_ubuntu_defconfig
@@ -0,0 +1,5174 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_WATCH_QUEUE=y
+CONFIG_USELIB=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_JIT=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BPF_LSM=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_PSI=y
+CONFIG_IKHEADERS=m
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_NUMA_BALANCING=y
+CONFIG_MEMCG=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_RDMA=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_HUGETLB=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_MISC=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_EXPERT=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PC104=y
+CONFIG_PROFILING=y
+CONFIG_SOC_MICROCHIP_POLARFIRE=y
+CONFIG_SOC_SIFIVE=y
+CONFIG_SOC_STARFIVE=y
+CONFIG_SOC_VIRT=y
+CONFIG_ARCH_SOPHGO=y
+CONFIG_ERRATA_THEAD=y
+CONFIG_SMP=y
+CONFIG_SCHED_CLUSTER=y
+CONFIG_NR_CPUS=128
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=3
+# CONFIG_RISCV_ISA_SVPBMT is not set
+CONFIG_VECTOR=y
+CONFIG_KEXEC=y
+CONFIG_KEXEC_FILE=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_IDLE_GOV_TEO=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=m
+CONFIG_JUMP_LABEL=y
+# CONFIG_VMAP_STACK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_BLK_DEV_ZONED=y
+CONFIG_BLK_DEV_THROTTLING=y
+CONFIG_BLK_WBT=y
+CONFIG_BLK_CGROUP_FC_APPID=y
+CONFIG_BLK_CGROUP_IOCOST=y
+CONFIG_BLK_CGROUP_IOPRIO=y
+CONFIG_BLK_SED_OPAL=y
+CONFIG_BLK_INLINE_ENCRYPTION=y
+CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_AIX_PARTITION=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_CMDLINE_PARTITION=y
+CONFIG_MQ_IOSCHED_KYBER=m
+CONFIG_IOSCHED_BFQ=m
+CONFIG_BFQ_GROUP_IOSCHED=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_FLAT_OLD=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_MISC=m
+CONFIG_ZSWAP=y
+CONFIG_Z3FOLD=m
+CONFIG_ZSMALLOC=y
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SPARSEMEM_VMEMMAP is not set
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
+CONFIG_CMA=y
+CONFIG_CMA_SYSFS=y
+CONFIG_CMA_AREAS=7
+CONFIG_IDLE_PAGE_TRACKING=y
+CONFIG_ANON_VMA_NAME=y
+CONFIG_USERFAULTFD=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=m
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=m
+CONFIG_TLS=m
+CONFIG_TLS_DEVICE=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_INTERFACE=m
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=m
+CONFIG_SMC=m
+CONFIG_SMC_DIAG=m
+CONFIG_XDP_SOCKETS=y
+CONFIG_XDP_SOCKETS_DIAG=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_FOU_IP_TUNNELS=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_ESP_OFFLOAD=m
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_UDP_DIAG=m
+CONFIG_INET_RAW_DIAG=m
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_NV=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_BBR=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_ESPINTCP=y
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_IPV6_ILA=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_IPV6_SEG6_LWTUNNEL=y
+CONFIG_IPV6_SEG6_HMAC=y
+CONFIG_IPV6_IOAM6_LWTUNNEL=y
+CONFIG_MPTCP=y
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+CONFIG_BRIDGE_NETFILTER=m
+CONFIG_NETFILTER_NETLINK_HOOK=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_CT_NETLINK_TIMEOUT=m
+CONFIG_NF_CT_NETLINK_HELPER=m
+CONFIG_NETFILTER_NETLINK_GLUE_CT=y
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_OBJREF=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_XFRM=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+CONFIG_NFT_REJECT_NETDEV=m
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+CONFIG_NETFILTER_XT_SET=m
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_IPMAC=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_FO=m
+CONFIG_IP_VS_OVF=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_MH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_PE_SIP=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NFT_BRIDGE_META=m
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_BPFILTER=y
+CONFIG_IP_DCCP=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+CONFIG_RDS=m
+CONFIG_RDS_RDMA=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_TIPC_MEDIA_IB=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_BRIDGE_MRP=y
+CONFIG_BRIDGE_CFM=y
+CONFIG_NET_DSA=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_LLC2=m
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_PHONET=m
+CONFIG_6LOWPAN=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_MAC802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_CBS=m
+CONFIG_NET_SCH_ETF=m
+CONFIG_NET_SCH_TAPRIO=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_SKBPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+CONFIG_NET_SCH_FQ_PIE=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+CONFIG_NET_SCH_ETS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_CANID=m
+CONFIG_NET_EMATCH_IPSET=m
+CONFIG_NET_EMATCH_IPT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_SAMPLE=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_MPLS=m
+CONFIG_NET_ACT_VLAN=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+CONFIG_NET_ACT_CTINFO=m
+CONFIG_NET_ACT_SKBMOD=m
+CONFIG_NET_ACT_TUNNEL_KEY=m
+CONFIG_NET_ACT_CT=m
+CONFIG_NET_ACT_GATE=m
+CONFIG_NET_TC_SKB_EXT=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_BATMAN_ADV=m
+# CONFIG_BATMAN_ADV_BATMAN_V is not set
+CONFIG_BATMAN_ADV_NC=y
+CONFIG_OPENVSWITCH=m
+CONFIG_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
+CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS_ROUTING=m
+CONFIG_MPLS_IPTUNNEL=m
+CONFIG_HSR=m
+CONFIG_QRTR_SMD=m
+CONFIG_QRTR_TUN=m
+CONFIG_NET_NCSI=y
+CONFIG_NCSI_OEM_CMD_GET_MAC=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_BPF_STREAM_PARSER=y
+CONFIG_NET_PKTGEN=m
+CONFIG_NET_DROP_MONITOR=y
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+CONFIG_BAYCOM_SER_FDX=m
+CONFIG_BAYCOM_SER_HDX=m
+CONFIG_BAYCOM_PAR=m
+CONFIG_YAM=m
+CONFIG_CAN=m
+CONFIG_CAN_J1939=m
+CONFIG_CAN_ISOTP=m
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HS=y
+CONFIG_BT_6LOWPAN=m
+CONFIG_BT_LEDS=y
+CONFIG_BT_MSFTEXT=y
+CONFIG_BT_AOSPEXT=y
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y
+CONFIG_BT_HCIBTUSB_MTK=y
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIUART_INTEL=y
+CONFIG_BT_HCIUART_BCM=y
+CONFIG_BT_HCIUART_RTL=y
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIUART_AG6XX=y
+CONFIG_BT_HCIUART_MRVL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
+CONFIG_BT_MTKSDIO=m
+CONFIG_BT_MTKUART=m
+CONFIG_BT_VIRTIO=m
+CONFIG_AF_RXRPC_IPV6=y
+CONFIG_RXKAD=y
+CONFIG_AF_KCM=m
+CONFIG_MCTP=y
+CONFIG_CFG80211=m
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_MESSAGE_TRACING=y
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_GPIO=m
+CONFIG_NET_9P=m
+CONFIG_NET_9P_VIRTIO=m
+CONFIG_NET_9P_RDMA=m
+CONFIG_CAIF=m
+CONFIG_CAIF_USB=m
+CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
+CONFIG_NFC=m
+CONFIG_NFC_DIGITAL=m
+CONFIG_NFC_NCI=m
+CONFIG_NFC_NCI_SPI=m
+CONFIG_NFC_NCI_UART=m
+CONFIG_NFC_HCI=m
+CONFIG_NFC_SHDLC=y
+CONFIG_NFC_TRF7970A=m
+CONFIG_NFC_SIM=m
+CONFIG_NFC_PORT100=m
+CONFIG_NFC_VIRTUAL_NCI=m
+CONFIG_NFC_FDP=m
+CONFIG_NFC_FDP_I2C=m
+CONFIG_NFC_PN544_I2C=m
+CONFIG_NFC_PN533_USB=m
+CONFIG_NFC_PN533_I2C=m
+CONFIG_NFC_PN532_UART=m
+CONFIG_NFC_MICROREAD_I2C=m
+CONFIG_NFC_MRVL_USB=m
+CONFIG_NFC_MRVL_UART=m
+CONFIG_NFC_MRVL_I2C=m
+CONFIG_NFC_MRVL_SPI=m
+CONFIG_NFC_ST21NFCA_I2C=m
+CONFIG_NFC_ST_NCI_I2C=m
+CONFIG_NFC_ST_NCI_SPI=m
+CONFIG_NFC_NXP_NCI=m
+CONFIG_NFC_NXP_NCI_I2C=m
+CONFIG_NFC_S3FWRN5_I2C=m
+CONFIG_NFC_S3FWRN82_UART=m
+CONFIG_NFC_ST95HF=m
+CONFIG_NET_IFE=m
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_PCIEAER=y
+CONFIG_PCIE_DPC=y
+CONFIG_PCIE_PTM=y
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCI_STUB=m
+CONFIG_PCI_PF_STUB=m
+CONFIG_PCI_IOV=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_PASID=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_SHPC=y
+CONFIG_PCI_FTPCI100=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_PCIE_XILINX=y
+CONFIG_PCIE_MICROCHIP_HOST=y
+CONFIG_PCIE_DW_PLAT_HOST=y
+CONFIG_PCIE_DW_PLAT_EP=y
+CONFIG_PCIE_FU740=y
+CONFIG_PCIE_CADENCE_PLAT_HOST=y
+CONFIG_PCIE_CADENCE_PLAT_EP=y
+CONFIG_PCIE_CADENCE_SOPHGO=y
+CONFIG_PCI_J721E_HOST=y
+CONFIG_PCI_J721E_EP=y
+CONFIG_PCI_ENDPOINT=y
+CONFIG_PCI_ENDPOINT_CONFIGFS=y
+CONFIG_PCI_EPF_NTB=m
+CONFIG_CXL_BUS=m
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_TSI721=m
+CONFIG_RAPIDIO_DMA_ENGINE=y
+CONFIG_RAPIDIO_ENUM_BASIC=m
+CONFIG_RAPIDIO_CHMAN=m
+CONFIG_RAPIDIO_MPORT_CDEV=m
+CONFIG_RAPIDIO_CPS_XX=m
+CONFIG_RAPIDIO_CPS_GEN2=m
+CONFIG_RAPIDIO_RXS_GEN3=m
+CONFIG_UEVENT_HELPER=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DEVTMPFS_SAFE=y
+CONFIG_FW_LOADER_COMPRESS=y
+CONFIG_FW_LOADER_COMPRESS_ZSTD=y
+CONFIG_MOXTET=m
+CONFIG_MHI_BUS_PCI_GENERIC=m
+CONFIG_MHI_BUS_EP=m
+CONFIG_CONNECTOR=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_EFI_VARS_PSTORE=m
+CONFIG_EFI_BOOTLOADER_CONTROL=m
+CONFIG_EFI_CAPSULE_LOADER=m
+CONFIG_EFI_TEST=m
+CONFIG_RESET_ATTACK_MITIGATION=y
+CONFIG_EFI_COCO_SECRET=y
+CONFIG_GNSS=m
+CONFIG_GNSS_MTK_SERIAL=m
+CONFIG_GNSS_SIRF_SERIAL=m
+CONFIG_GNSS_UBX_SERIAL=m
+CONFIG_GNSS_USB=m
+CONFIG_MTD=m
+CONFIG_MTD_AR7_PARTS=m
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_BLOCK=m
+CONFIG_MTD_BLOCK_RO=m
+CONFIG_FTL=m
+CONFIG_NFTL=m
+CONFIG_NFTL_RW=y
+CONFIG_INFTL=m
+CONFIG_RFD_FTL=m
+CONFIG_SSFDC=m
+CONFIG_SM_FTL=m
+CONFIG_MTD_OOPS=m
+CONFIG_MTD_PSTORE=m
+CONFIG_MTD_SWAP=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_ROM=m
+CONFIG_MTD_ABSENT=m
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_PHYSMAP_GPIO_ADDR=y
+CONFIG_MTD_PCI=m
+CONFIG_MTD_INTEL_VR_NOR=m
+CONFIG_MTD_PLATRAM=m
+CONFIG_MTD_PMC551=m
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_DATAFLASH_OTP=y
+CONFIG_MTD_MCHP23K256=m
+CONFIG_MTD_MCHP48L640=m
+CONFIG_MTD_SST25L=m
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTD_BLOCK2MTD=m
+CONFIG_MTD_ONENAND=m
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_GENERIC=m
+CONFIG_MTD_ONENAND_2X_PROGRAM=y
+CONFIG_MTD_RAW_NAND=m
+CONFIG_MTD_NAND_DENALI_PCI=m
+CONFIG_MTD_NAND_DENALI_DT=m
+CONFIG_MTD_NAND_CAFE=m
+CONFIG_MTD_NAND_MXIC=m
+CONFIG_MTD_NAND_GPIO=m
+CONFIG_MTD_NAND_PLATFORM=m
+CONFIG_MTD_NAND_CADENCE=m
+CONFIG_MTD_NAND_ARASAN=m
+CONFIG_MTD_NAND_INTEL_LGM=m
+CONFIG_MTD_NAND_NANDSIM=m
+CONFIG_MTD_NAND_RICOH=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+CONFIG_MTD_SPI_NAND=m
+CONFIG_MTD_NAND_ECC_SW_BCH=y
+CONFIG_MTD_LPDDR=m
+CONFIG_MTD_SPI_NOR=m
+CONFIG_SPI_SOPHGO_SPIFMC=m
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_FASTMAP=y
+CONFIG_MTD_UBI_GLUEBI=m
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_HYPERBUS=m
+CONFIG_OF_OVERLAY=y
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_SERIAL=m
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_AX88796=m
+CONFIG_PARPORT_1284=y
+CONFIG_BLK_DEV_NULL_BLK=m
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPATC8=y
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
+CONFIG_ZRAM=m
+CONFIG_ZRAM_WRITEBACK=y
+CONFIG_ZRAM_MEMORY_TRACKING=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_DRBD=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_ATA_OVER_ETH=m
+CONFIG_VIRTIO_BLK=m
+CONFIG_BLK_DEV_RBD=m
+CONFIG_BLK_DEV_RNBD_CLIENT=m
+CONFIG_BLK_DEV_RNBD_SERVER=m
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+CONFIG_NVME_HWMON=y
+CONFIG_NVME_RDMA=m
+CONFIG_NVME_FC=m
+CONFIG_NVME_TCP=m
+CONFIG_NVME_TARGET=m
+CONFIG_NVME_TARGET_PASSTHRU=y
+CONFIG_NVME_TARGET_LOOP=m
+CONFIG_NVME_TARGET_RDMA=m
+CONFIG_NVME_TARGET_FC=m
+CONFIG_NVME_TARGET_TCP=m
+CONFIG_AD525X_DPOT=m
+CONFIG_AD525X_DPOT_I2C=m
+CONFIG_AD525X_DPOT_SPI=m
+CONFIG_DUMMY_IRQ=m
+CONFIG_PHANTOM=m
+CONFIG_ICS932S401=m
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_HI6421V600_IRQ=m
+CONFIG_HP_ILO=m
+CONFIG_APDS9802ALS=m
+CONFIG_ISL29003=m
+CONFIG_ISL29020=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_HMC6352=m
+CONFIG_DS1682=m
+CONFIG_LATTICE_ECP3_CONFIG=m
+CONFIG_SRAM=y
+CONFIG_DW_XDATA_PCIE=m
+CONFIG_OPEN_DICE=m
+CONFIG_C2PORT=m
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_AT25=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_EEPROM_MAX6875=m
+CONFIG_EEPROM_93XX46=m
+CONFIG_EEPROM_IDT_89HPESX=m
+CONFIG_EEPROM_EE1004=m
+CONFIG_TI_ST=m
+CONFIG_SENSORS_LIS3_SPI=m
+CONFIG_SENSORS_LIS3_I2C=m
+CONFIG_GENWQE=m
+CONFIG_ECHO=m
+CONFIG_BCM_VK=m
+CONFIG_BCM_VK_TTY=y
+CONFIG_MISC_ALCOR_PCI=m
+CONFIG_MISC_RTSX_PCI=m
+CONFIG_MISC_RTSX_USB=m
+CONFIG_UACCE=m
+CONFIG_PVPANIC=y
+CONFIG_PVPANIC_MMIO=m
+CONFIG_PVPANIC_PCI=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_ENCLOSURE=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_SCSI_AIC79XX=m
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_MPI3MR=m
+CONFIG_SCSI_SMARTPQI=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_MYRB=m
+CONFIG_SCSI_MYRS=m
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_FCOE=m
+CONFIG_SCSI_SNIC=m
+CONFIG_SCSI_DMX3191D=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_IPR=m
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_TCM_QLA2XXX=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_QEDI=m
+CONFIG_QEDF=m
+CONFIG_SCSI_EFCT=m
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_VIRTIO=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_MOBILE_LPM_POLICY=3
+CONFIG_SATA_AHCI_PLATFORM=m
+CONFIG_AHCI_CEVA=m
+CONFIG_AHCI_QORIQ=m
+CONFIG_SATA_INIC162X=m
+CONFIG_SATA_ACARD_AHCI=m
+CONFIG_SATA_SIL24=m
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_PIIX=m
+CONFIG_SATA_DWC=m
+CONFIG_SATA_DWC_OLD_DMA=y
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_SIL=m
+CONFIG_SATA_SIS=m
+CONFIG_SATA_SVW=m
+CONFIG_SATA_ULI=m
+CONFIG_SATA_VIA=m
+CONFIG_SATA_VITESSE=m
+CONFIG_PATA_ALI=m
+CONFIG_PATA_AMD=m
+CONFIG_PATA_ARTOP=m
+CONFIG_PATA_ATIIXP=m
+CONFIG_PATA_ATP867X=m
+CONFIG_PATA_CMD64X=m
+CONFIG_PATA_CYPRESS=m
+CONFIG_PATA_EFAR=m
+CONFIG_PATA_HPT366=m
+CONFIG_PATA_HPT37X=m
+CONFIG_PATA_HPT3X2N=m
+CONFIG_PATA_HPT3X3=m
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_IT821X=m
+CONFIG_PATA_JMICRON=m
+CONFIG_PATA_MARVELL=m
+CONFIG_PATA_NETCELL=m
+CONFIG_PATA_NINJA32=m
+CONFIG_PATA_NS87415=m
+CONFIG_PATA_OLDPIIX=m
+CONFIG_PATA_OPTIDMA=m
+CONFIG_PATA_PDC2027X=m
+CONFIG_PATA_PDC_OLD=m
+CONFIG_PATA_RADISYS=m
+CONFIG_PATA_RDC=m
+CONFIG_PATA_SCH=m
+CONFIG_PATA_SERVERWORKS=m
+CONFIG_PATA_SIL680=m
+CONFIG_PATA_TOSHIBA=m
+CONFIG_PATA_TRIFLEX=m
+CONFIG_PATA_VIA=m
+CONFIG_PATA_WINBOND=m
+CONFIG_PATA_CMD640_PCI=m
+CONFIG_PATA_MPIIX=m
+CONFIG_PATA_NS87410=m
+CONFIG_PATA_OPTI=m
+CONFIG_PATA_OF_PLATFORM=m
+CONFIG_PATA_RZ1000=m
+CONFIG_ATA_GENERIC=m
+CONFIG_PATA_LEGACY=m
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_MD_CLUSTER=m
+CONFIG_BCACHE=m
+CONFIG_BCACHE_ASYNC_REGISTRATION=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_UNSTRIPED=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_THIN_PROVISIONING=m
+CONFIG_DM_CACHE=m
+CONFIG_DM_WRITECACHE=m
+CONFIG_DM_ERA=m
+CONFIG_DM_CLONE=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_MULTIPATH_HST=m
+CONFIG_DM_MULTIPATH_IOA=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_INIT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_FLAKEY=m
+CONFIG_DM_VERITY=m
+CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
+CONFIG_DM_SWITCH=m
+CONFIG_DM_LOG_WRITES=m
+CONFIG_DM_INTEGRITY=m
+CONFIG_DM_ZONED=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_TCM_USER2=m
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_TCM_FC=m
+CONFIG_ISCSI_TARGET=m
+CONFIG_ISCSI_TARGET_CXGB4=m
+CONFIG_SBP_TARGET=m
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_CTL=m
+CONFIG_FUSION_LAN=m
+CONFIG_FUSION_LOGGING=y
+CONFIG_FIREWIRE=m
+CONFIG_FIREWIRE_OHCI=m
+CONFIG_FIREWIRE_SBP2=m
+CONFIG_FIREWIRE_NET=m
+CONFIG_FIREWIRE_NOSY=m
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+CONFIG_EQUALIZER=m
+CONFIG_NET_FC=y
+CONFIG_IFB=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN=m
+CONFIG_IPVTAP=m
+CONFIG_VXLAN=m
+CONFIG_GENEVE=m
+CONFIG_BAREUDP=m
+CONFIG_GTP=m
+CONFIG_AMT=m
+CONFIG_MACSEC=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NTB_NETDEV=m
+CONFIG_RIONET=m
+CONFIG_TUN=y
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+CONFIG_NLMON=m
+CONFIG_NET_VRF=m
+CONFIG_VSOCKMON=m
+CONFIG_MHI_NET=m
+CONFIG_ARCNET=m
+CONFIG_ARCNET_1201=m
+CONFIG_ARCNET_1051=m
+CONFIG_ARCNET_RAW=m
+CONFIG_ARCNET_CAP=m
+CONFIG_ARCNET_COM90xx=m
+CONFIG_ARCNET_COM90xxIO=m
+CONFIG_ARCNET_RIM_I=m
+CONFIG_ARCNET_COM20020=m
+CONFIG_ARCNET_COM20020_PCI=m
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+CONFIG_ATM_NICSTAR=m
+CONFIG_ATM_IDT77252=m
+CONFIG_ATM_IA=m
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+CONFIG_ATM_SOLOS=m
+CONFIG_CAIF_DRIVERS=y
+CONFIG_CAIF_TTY=m
+CONFIG_CAIF_VIRTIO=m
+CONFIG_B53_SPI_DRIVER=m
+CONFIG_B53_MDIO_DRIVER=m
+CONFIG_B53_MMAP_DRIVER=m
+CONFIG_B53_SRAB_DRIVER=m
+CONFIG_B53_SERDES=m
+CONFIG_NET_DSA_BCM_SF2=m
+CONFIG_NET_DSA_HIRSCHMANN_HELLCREEK=m
+CONFIG_NET_DSA_LANTIQ_GSWIP=m
+CONFIG_NET_DSA_MT7530=m
+CONFIG_NET_DSA_MV88E6060=m
+CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON=m
+CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C=m
+CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI=m
+CONFIG_NET_DSA_MV88E6XXX=m
+CONFIG_NET_DSA_MV88E6XXX_PTP=y
+CONFIG_NET_DSA_MSCC_SEVILLE=m
+CONFIG_NET_DSA_AR9331=m
+CONFIG_NET_DSA_QCA8K=m
+CONFIG_NET_DSA_SJA1105=m
+CONFIG_NET_DSA_SJA1105_PTP=y
+CONFIG_NET_DSA_SJA1105_TAS=y
+CONFIG_NET_DSA_SJA1105_VL=y
+CONFIG_NET_DSA_XRS700X_I2C=m
+CONFIG_NET_DSA_XRS700X_MDIO=m
+CONFIG_NET_DSA_REALTEK=m
+CONFIG_NET_DSA_REALTEK_RTL8365MB=m
+CONFIG_NET_DSA_REALTEK_RTL8366RB=m
+CONFIG_NET_DSA_SMSC_LAN9303_I2C=m
+CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m
+CONFIG_NET_DSA_VITESSE_VSC73XX_SPI=m
+CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM=m
+CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
+CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ET131X=m
+CONFIG_SLICOSS=m
+CONFIG_ACENIC=m
+CONFIG_ALTERA_TSE=m
+CONFIG_ENA_ETHERNET=m
+CONFIG_AMD8111_ETH=m
+CONFIG_PCNET32=m
+CONFIG_AQTION=m
+CONFIG_SPI_AX88796C=m
+CONFIG_ATL2=m
+CONFIG_ATL1=m
+CONFIG_ATL1E=m
+CONFIG_ATL1C=m
+CONFIG_ALX=m
+CONFIG_B44=m
+CONFIG_BCMGENET=m
+CONFIG_TIGON3=m
+CONFIG_BNX2X=m
+CONFIG_SYSTEMPORT=m
+CONFIG_BNXT=m
+CONFIG_BNXT_DCB=y
+CONFIG_MACB=m
+CONFIG_MACB_PCI=m
+CONFIG_THUNDER_NIC_PF=m
+CONFIG_THUNDER_NIC_VF=m
+CONFIG_LIQUIDIO=m
+CONFIG_LIQUIDIO_VF=m
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T4_DCB=y
+CONFIG_CHELSIO_T4_FCOE=y
+CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_IPSEC_INLINE=m
+CONFIG_CHELSIO_TLS_DEVICE=m
+CONFIG_ENIC=m
+CONFIG_GEMINI_ETHERNET=m
+CONFIG_DM9051=m
+CONFIG_DNET=m
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=m
+CONFIG_TULIP=m
+CONFIG_WINBOND_840=m
+CONFIG_DM9102=m
+CONFIG_ULI526X=m
+CONFIG_DL2K=m
+CONFIG_SUNDANCE=m
+CONFIG_TSNEP=m
+CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=m
+CONFIG_FUN_ETH=m
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_IGB=m
+CONFIG_IGBVF=m
+CONFIG_IXGB=m
+CONFIG_IXGBE=m
+CONFIG_IXGBE_DCB=y
+CONFIG_IXGBEVF=m
+CONFIG_I40E=m
+CONFIG_I40E_DCB=y
+CONFIG_I40EVF=m
+CONFIG_ICE=m
+CONFIG_FM10K=m
+CONFIG_IGC=m
+CONFIG_TXGBE=m
+CONFIG_JME=m
+CONFIG_ADIN1110=m
+CONFIG_LITEX_LITEETH=m
+CONFIG_MVMDIO=m
+CONFIG_SKGE=m
+CONFIG_SKGE_GENESIS=y
+CONFIG_SKY2=m
+CONFIG_OCTEON_EP=m
+CONFIG_PRESTERA=m
+CONFIG_MLX4_EN=m
+CONFIG_MLX5_CORE=m
+CONFIG_MLX5_FPGA=y
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_CORE_IPOIB=y
+CONFIG_MLX5_EN_IPSEC=y
+CONFIG_MLX5_EN_TLS=y
+CONFIG_MLX5_SF=y
+CONFIG_MLXSW_CORE=m
+CONFIG_KS8842=m
+CONFIG_KS8851=m
+CONFIG_KS8851_MLL=m
+CONFIG_KSZ884X_PCI=m
+CONFIG_ENC28J60=m
+CONFIG_ENCX24J600=m
+CONFIG_LAN743X=m
+CONFIG_LAN966X_SWITCH=m
+CONFIG_MSCC_OCELOT_SWITCH=m
+CONFIG_MYRI10GE=m
+CONFIG_FEALNX=m
+CONFIG_NI_XGE_MANAGEMENT_ENET=m
+CONFIG_NATSEMI=m
+CONFIG_NS83820=m
+CONFIG_S2IO=m
+CONFIG_NFP=m
+CONFIG_NE2K_PCI=m
+CONFIG_FORCEDETH=m
+CONFIG_ETHOC=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_IONIC=m
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_NETXEN_NIC=m
+CONFIG_QED=m
+CONFIG_QEDE=m
+CONFIG_BNA=m
+CONFIG_QCA7000_SPI=m
+CONFIG_QCA7000_UART=m
+CONFIG_QCOM_EMAC=m
+CONFIG_RMNET=m
+CONFIG_R6040=m
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_8139TOO_8129=y
+CONFIG_R8169=m
+CONFIG_ROCKER=m
+CONFIG_SXGBE_ETH=m
+CONFIG_SC92031=m
+CONFIG_SIS900=m
+CONFIG_SIS190=m
+CONFIG_SFC=m
+CONFIG_SFC_FALCON=m
+CONFIG_SFC_SIENA=m
+CONFIG_SFC_SIENA_SRIOV=y
+CONFIG_EPIC100=m
+CONFIG_SMSC911X=m
+CONFIG_SMSC9420=m
+CONFIG_STMMAC_ETH=y
+CONFIG_DWMAC_DWC_QOS_ETH=m
+CONFIG_DWMAC_LOONGSON=m
+CONFIG_STMMAC_PCI=m
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNGEM=m
+CONFIG_CASSINI=m
+CONFIG_NIU=m
+CONFIG_DWC_XLGMAC=m
+CONFIG_DWC_XLGMAC_PCI=m
+CONFIG_TEHUTI=m
+CONFIG_TLAN=m
+CONFIG_MSE102X=m
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+CONFIG_VIA_VELOCITY=m
+CONFIG_WIZNET_W5100=m
+CONFIG_WIZNET_W5300=m
+CONFIG_WIZNET_W5100_SPI=m
+CONFIG_XILINX_EMACLITE=m
+CONFIG_XILINX_AXI_EMAC=m
+CONFIG_XILINX_LL_TEMAC=m
+CONFIG_FDDI=y
+CONFIG_DEFXX=m
+CONFIG_SKFP=m
+CONFIG_LED_TRIGGER_PHY=y
+CONFIG_SFP=m
+CONFIG_AMD_PHY=m
+CONFIG_ADIN_PHY=m
+CONFIG_ADIN1100_PHY=m
+CONFIG_AQUANTIA_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_BCM54140_PHY=m
+CONFIG_BCM84881_PHY=m
+CONFIG_BCM87XX_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_CORTINA_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_INTEL_XWAY_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_MARVELL_10G_PHY=m
+CONFIG_MARVELL_88X2222_PHY=m
+CONFIG_MAXLINEAR_GPHY=m
+CONFIG_MICROCHIP_T1_PHY=m
+CONFIG_MICROSEMI_PHY=m
+CONFIG_MOTORCOMM_PHY=m
+CONFIG_NATIONAL_PHY=m
+CONFIG_NXP_C45_TJA11XX_PHY=m
+CONFIG_NXP_TJA11XX_PHY=m
+CONFIG_AT803X_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_RENESAS_PHY=m
+CONFIG_ROCKCHIP_PHY=m
+CONFIG_STE10XP=m
+CONFIG_TERANETICS_PHY=m
+CONFIG_DP83822_PHY=m
+CONFIG_DP83TC811_PHY=m
+CONFIG_DP83848_PHY=m
+CONFIG_DP83867_PHY=m
+CONFIG_DP83869_PHY=m
+CONFIG_DP83TD510_PHY=m
+CONFIG_XILINX_GMII2RGMII=m
+CONFIG_MICREL_KS8995MA=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_VXCAN=m
+CONFIG_CAN_FLEXCAN=m
+CONFIG_CAN_GRCAN=m
+CONFIG_CAN_JANZ_ICAN3=m
+CONFIG_CAN_KVASER_PCIEFD=m
+CONFIG_CAN_SLCAN=m
+CONFIG_CAN_C_CAN=m
+CONFIG_CAN_C_CAN_PLATFORM=m
+CONFIG_CAN_C_CAN_PCI=m
+CONFIG_CAN_CC770=m
+CONFIG_CAN_CC770_ISA=m
+CONFIG_CAN_CC770_PLATFORM=m
+CONFIG_CAN_CTUCANFD_PCI=m
+CONFIG_CAN_CTUCANFD_PLATFORM=m
+CONFIG_CAN_IFI_CANFD=m
+CONFIG_CAN_M_CAN=m
+CONFIG_CAN_M_CAN_PCI=m
+CONFIG_CAN_M_CAN_PLATFORM=m
+CONFIG_CAN_M_CAN_TCAN4X5X=m
+CONFIG_CAN_PEAK_PCIEFD=m
+CONFIG_CAN_SJA1000=m
+CONFIG_CAN_EMS_PCI=m
+CONFIG_CAN_F81601=m
+CONFIG_CAN_KVASER_PCI=m
+CONFIG_CAN_PEAK_PCI=m
+CONFIG_CAN_PLX_PCI=m
+CONFIG_CAN_SJA1000_ISA=m
+CONFIG_CAN_SJA1000_PLATFORM=m
+CONFIG_CAN_SOFTING=m
+CONFIG_CAN_HI311X=m
+CONFIG_CAN_MCP251X=m
+CONFIG_CAN_MCP251XFD=m
+CONFIG_CAN_8DEV_USB=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_ETAS_ES58X=m
+CONFIG_CAN_GS_USB=m
+CONFIG_CAN_KVASER_USB=m
+CONFIG_CAN_MCBA_USB=m
+CONFIG_CAN_PEAK_USB=m
+CONFIG_CAN_UCAN=m
+CONFIG_MCTP_SERIAL=m
+CONFIG_MDIO_GPIO=m
+CONFIG_MDIO_HISI_FEMAC=m
+CONFIG_MDIO_MVUSB=m
+CONFIG_MDIO_OCTEON=m
+CONFIG_MDIO_IPQ4019=m
+CONFIG_MDIO_IPQ8064=m
+CONFIG_MDIO_BUS_MUX_GPIO=m
+CONFIG_MDIO_BUS_MUX_MULTIPLEXER=m
+CONFIG_MDIO_BUS_MUX_MMIOREG=m
+CONFIG_PLIP=m
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOATM=m
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_NET_DRIVERS=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_KALMIA=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_CDC_PHONET=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+CONFIG_USB_NET_CH9200=m
+CONFIG_USB_NET_AQC111=m
+CONFIG_ADM8211=m
+CONFIG_ATH5K=m
+CONFIG_ATH9K=m
+CONFIG_ATH9K_AHB=y
+CONFIG_ATH9K_DEBUGFS=y
+CONFIG_ATH9K_STATION_STATISTICS=y
+CONFIG_ATH9K_CHANNEL_CONTEXT=y
+CONFIG_ATH9K_PCI_NO_EEPROM=m
+CONFIG_ATH9K_HTC=m
+CONFIG_ATH9K_HTC_DEBUGFS=y
+CONFIG_ATH9K_HWRNG=y
+CONFIG_ATH9K_COMMON_SPECTRAL=y
+CONFIG_CARL9170=m
+CONFIG_CARL9170_HWRNG=y
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_USB=m
+CONFIG_AR5523=m
+CONFIG_WIL6210=m
+CONFIG_WIL6210_TRACING=y
+CONFIG_ATH10K=m
+CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K_AHB=y
+CONFIG_ATH10K_SDIO=m
+CONFIG_ATH10K_USB=m
+CONFIG_ATH10K_DEBUGFS=y
+CONFIG_ATH10K_SPECTRAL=y
+CONFIG_ATH10K_TRACING=y
+CONFIG_WCN36XX=m
+CONFIG_ATH11K=m
+CONFIG_ATH11K_PCI=m
+CONFIG_ATH11K_DEBUGFS=y
+CONFIG_ATH11K_TRACING=y
+CONFIG_ATH11K_SPECTRAL=y
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+CONFIG_AT76C50X_USB=m
+CONFIG_B43=m
+CONFIG_B43LEGACY=m
+# CONFIG_B43LEGACY_DEBUG is not set
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMFMAC_PCIE=y
+CONFIG_BRCM_TRACING=y
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW2200_PROMISCUOUS=y
+CONFIG_IPW2200_QOS=y
+CONFIG_IWL4965=m
+CONFIG_IWL3945=m
+CONFIG_IWLEGACY_DEBUGFS=y
+CONFIG_IWLWIFI=m
+CONFIG_IWLDVM=m
+CONFIG_IWLMVM=m
+CONFIG_IWLWIFI_DEBUGFS=y
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_ORINOCO_USB=m
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+CONFIG_P54_PCI=m
+CONFIG_P54_SPI=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_LIBERTAS_MESH=y
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MWIFIEX_PCIE=m
+CONFIG_MWIFIEX_USB=m
+CONFIG_MWL8K=m
+CONFIG_MT7601U=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x0E=m
+CONFIG_MT76x2E=m
+CONFIG_MT76x2U=m
+CONFIG_MT7603E=m
+CONFIG_MT7615E=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+CONFIG_MT7921E=m
+CONFIG_MT7921S=m
+CONFIG_MT7921U=m
+CONFIG_WILC1000_SDIO=m
+CONFIG_WILC1000_SPI=m
+CONFIG_WILC1000_HW_OOB_INTR=y
+CONFIG_PLFXLC=m
+CONFIG_RT2X00=m
+CONFIG_RT2400PCI=m
+CONFIG_RT2500PCI=m
+CONFIG_RT61PCI=m
+CONFIG_RT2800PCI=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8192CU=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTL8XXXU=m
+CONFIG_RTL8XXXU_UNTESTED=y
+CONFIG_RTW88=m
+CONFIG_RTW88_8822BE=m
+CONFIG_RTW88_8822CE=m
+CONFIG_RTW88_8723DE=m
+CONFIG_RTW88_8821CE=m
+CONFIG_RTW88_DEBUG=y
+CONFIG_RTW88_DEBUGFS=y
+CONFIG_RTW89=m
+CONFIG_RTW89_8852AE=m
+CONFIG_RTW89_8852CE=m
+CONFIG_RTW89_DEBUGMSG=y
+CONFIG_RTW89_DEBUGFS=y
+CONFIG_RSI_91X=m
+# CONFIG_RSI_DEBUGFS is not set
+CONFIG_WFX=m
+CONFIG_CW1200=m
+CONFIG_CW1200_WLAN_SDIO=m
+CONFIG_CW1200_WLAN_SPI=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX=m
+CONFIG_WL18XX=m
+CONFIG_WLCORE_SPI=m
+CONFIG_WLCORE_SDIO=m
+CONFIG_USB_ZD1201=m
+CONFIG_ZD1211RW=m
+CONFIG_QTNFMAC_PCIE=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_VIRT_WIFI=m
+CONFIG_WAN=y
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=m
+CONFIG_HDLC_RAW_ETH=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_X25=m
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300TOO=m
+CONFIG_FARSYNC=m
+CONFIG_LAPBETHER=m
+CONFIG_IEEE802154_FAKELB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_IEEE802154_ATUSB=m
+CONFIG_IEEE802154_ADF7242=m
+CONFIG_IEEE802154_CA8210=m
+CONFIG_IEEE802154_CA8210_DEBUGFS=y
+CONFIG_IEEE802154_MCR20A=m
+CONFIG_IEEE802154_HWSIM=m
+CONFIG_WWAN=m
+CONFIG_WWAN_HWSIM=m
+CONFIG_MHI_WWAN_CTRL=m
+CONFIG_MHI_WWAN_MBIM=m
+CONFIG_RPMSG_WWAN_CTRL=m
+CONFIG_MTK_T7XX=m
+CONFIG_VMXNET3=m
+CONFIG_USB4_NET=m
+CONFIG_NETDEVSIM=m
+CONFIG_ISDN=y
+CONFIG_MISDN=m
+CONFIG_MISDN_DSP=m
+CONFIG_MISDN_L1OIP=m
+CONFIG_MISDN_HFCPCI=m
+CONFIG_MISDN_HFCMULTI=m
+CONFIG_MISDN_HFCUSB=m
+CONFIG_MISDN_AVMFRITZ=m
+CONFIG_MISDN_SPEEDFAX=m
+CONFIG_MISDN_INFINEON=m
+CONFIG_MISDN_W6692=m
+CONFIG_MISDN_NETJET=m
+CONFIG_INPUT_LEDS=m
+CONFIG_INPUT_SPARSEKMAP=m
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_ADC=m
+CONFIG_KEYBOARD_ADP5520=m
+CONFIG_KEYBOARD_ADP5588=m
+CONFIG_KEYBOARD_ADP5589=m
+CONFIG_KEYBOARD_QT1050=m
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_QT2160=m
+CONFIG_KEYBOARD_DLINK_DIR685=m
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_GPIO_POLLED=m
+CONFIG_KEYBOARD_TCA6416=m
+CONFIG_KEYBOARD_TCA8418=m
+CONFIG_KEYBOARD_MATRIX=m
+CONFIG_KEYBOARD_LM8323=m
+CONFIG_KEYBOARD_LM8333=m
+CONFIG_KEYBOARD_MAX7359=m
+CONFIG_KEYBOARD_MCS=m
+CONFIG_KEYBOARD_MPR121=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_KEYBOARD_OPENCORES=m
+CONFIG_KEYBOARD_SAMSUNG=m
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=m
+CONFIG_KEYBOARD_STOWAWAY=m
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_STMPE=m
+CONFIG_KEYBOARD_IQS62X=m
+CONFIG_KEYBOARD_OMAP4=m
+CONFIG_KEYBOARD_TC3589X=m
+CONFIG_KEYBOARD_TM2_TOUCHKEY=m
+CONFIG_KEYBOARD_TWL4030=m
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_CAP11XX=m
+CONFIG_KEYBOARD_BCM=m
+CONFIG_KEYBOARD_MTK_PMIC=m
+CONFIG_KEYBOARD_CYPRESS_SF=m
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_PS2_TOUCHKIT=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_MOUSE_APPLETOUCH=m
+CONFIG_MOUSE_BCM5974=m
+CONFIG_MOUSE_CYAPA=m
+CONFIG_MOUSE_ELAN_I2C=m
+CONFIG_MOUSE_ELAN_I2C_SMBUS=y
+CONFIG_MOUSE_VSXXXAA=m
+CONFIG_MOUSE_GPIO=m
+CONFIG_MOUSE_SYNAPTICS_I2C=m
+CONFIG_MOUSE_SYNAPTICS_USB=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_ANALOG=m
+CONFIG_JOYSTICK_A3D=m
+CONFIG_JOYSTICK_ADC=m
+CONFIG_JOYSTICK_ADI=m
+CONFIG_JOYSTICK_COBRA=m
+CONFIG_JOYSTICK_GF2K=m
+CONFIG_JOYSTICK_GRIP=m
+CONFIG_JOYSTICK_GRIP_MP=m
+CONFIG_JOYSTICK_GUILLEMOT=m
+CONFIG_JOYSTICK_INTERACT=m
+CONFIG_JOYSTICK_SIDEWINDER=m
+CONFIG_JOYSTICK_TMDC=m
+CONFIG_JOYSTICK_IFORCE=m
+CONFIG_JOYSTICK_IFORCE_USB=m
+CONFIG_JOYSTICK_IFORCE_232=m
+CONFIG_JOYSTICK_WARRIOR=m
+CONFIG_JOYSTICK_MAGELLAN=m
+CONFIG_JOYSTICK_SPACEORB=m
+CONFIG_JOYSTICK_SPACEBALL=m
+CONFIG_JOYSTICK_STINGER=m
+CONFIG_JOYSTICK_TWIDJOY=m
+CONFIG_JOYSTICK_ZHENHUA=m
+CONFIG_JOYSTICK_DB9=m
+CONFIG_JOYSTICK_GAMECON=m
+CONFIG_JOYSTICK_TURBOGRAFX=m
+CONFIG_JOYSTICK_AS5011=m
+CONFIG_JOYSTICK_JOYDUMP=m
+CONFIG_JOYSTICK_XPAD=m
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_JOYSTICK_WALKERA0701=m
+CONFIG_JOYSTICK_PSXPAD_SPI=m
+CONFIG_JOYSTICK_PSXPAD_SPI_FF=y
+CONFIG_JOYSTICK_PXRC=m
+CONFIG_JOYSTICK_QWIIC=m
+CONFIG_JOYSTICK_FSIA6B=m
+CONFIG_JOYSTICK_SENSEHAT=m
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=m
+CONFIG_TABLET_USB_AIPTEK=m
+CONFIG_TABLET_USB_HANWANG=m
+CONFIG_TABLET_USB_KBTAB=m
+CONFIG_TABLET_USB_PEGASUS=m
+CONFIG_TABLET_SERIAL_WACOM4=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_88PM860X=m
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_AD7877=m
+CONFIG_TOUCHSCREEN_AD7879=m
+CONFIG_TOUCHSCREEN_AD7879_I2C=m
+CONFIG_TOUCHSCREEN_AD7879_SPI=m
+CONFIG_TOUCHSCREEN_ADC=m
+CONFIG_TOUCHSCREEN_AR1021_I2C=m
+CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+CONFIG_TOUCHSCREEN_ATMEL_MXT_T37=y
+CONFIG_TOUCHSCREEN_AUO_PIXCIR=m
+CONFIG_TOUCHSCREEN_BU21013=m
+CONFIG_TOUCHSCREEN_BU21029=m
+CONFIG_TOUCHSCREEN_CHIPONE_ICN8318=m
+CONFIG_TOUCHSCREEN_CY8CTMA140=m
+CONFIG_TOUCHSCREEN_CY8CTMG110=m
+CONFIG_TOUCHSCREEN_CYTTSP_CORE=m
+CONFIG_TOUCHSCREEN_CYTTSP_I2C=m
+CONFIG_TOUCHSCREEN_CYTTSP_SPI=m
+CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m
+CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m
+CONFIG_TOUCHSCREEN_CYTTSP4_SPI=m
+CONFIG_TOUCHSCREEN_DA9034=m
+CONFIG_TOUCHSCREEN_DA9052=m
+CONFIG_TOUCHSCREEN_DYNAPRO=m
+CONFIG_TOUCHSCREEN_HAMPSHIRE=m
+CONFIG_TOUCHSCREEN_EETI=m
+CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m
+CONFIG_TOUCHSCREEN_EXC3000=m
+CONFIG_TOUCHSCREEN_FUJITSU=m
+CONFIG_TOUCHSCREEN_GOODIX=m
+CONFIG_TOUCHSCREEN_HIDEEP=m
+CONFIG_TOUCHSCREEN_HYCON_HY46XX=m
+CONFIG_TOUCHSCREEN_ILI210X=m
+CONFIG_TOUCHSCREEN_ILITEK=m
+CONFIG_TOUCHSCREEN_S6SY761=m
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_EKTF2127=m
+CONFIG_TOUCHSCREEN_ELAN=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_WACOM_W8001=m
+CONFIG_TOUCHSCREEN_WACOM_I2C=m
+CONFIG_TOUCHSCREEN_MAX11801=m
+CONFIG_TOUCHSCREEN_MCS5000=m
+CONFIG_TOUCHSCREEN_MMS114=m
+CONFIG_TOUCHSCREEN_MELFAS_MIP4=m
+CONFIG_TOUCHSCREEN_MSG2638=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_IMAGIS=m
+CONFIG_TOUCHSCREEN_IMX6UL_TSC=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m
+CONFIG_TOUCHSCREEN_UCB1400=m
+CONFIG_TOUCHSCREEN_PIXCIR=m
+CONFIG_TOUCHSCREEN_WDT87XX_I2C=m
+CONFIG_TOUCHSCREEN_WM831X=m
+CONFIG_TOUCHSCREEN_WM97XX=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_MC13783=m
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_TOUCHSCREEN_TSC_SERIO=m
+CONFIG_TOUCHSCREEN_TSC2004=m
+CONFIG_TOUCHSCREEN_TSC2005=m
+CONFIG_TOUCHSCREEN_TSC2007=m
+CONFIG_TOUCHSCREEN_TSC2007_IIO=y
+CONFIG_TOUCHSCREEN_PCAP=m
+CONFIG_TOUCHSCREEN_RM_TS=m
+CONFIG_TOUCHSCREEN_SILEAD=m
+CONFIG_TOUCHSCREEN_SIS_I2C=m
+CONFIG_TOUCHSCREEN_ST1232=m
+CONFIG_TOUCHSCREEN_STMFTS=m
+CONFIG_TOUCHSCREEN_STMPE=m
+CONFIG_TOUCHSCREEN_SUR40=m
+CONFIG_TOUCHSCREEN_SURFACE3_SPI=m
+CONFIG_TOUCHSCREEN_SX8654=m
+CONFIG_TOUCHSCREEN_TPS6507X=m
+CONFIG_TOUCHSCREEN_ZET6223=m
+CONFIG_TOUCHSCREEN_ZFORCE=m
+CONFIG_TOUCHSCREEN_COLIBRI_VF50=m
+CONFIG_TOUCHSCREEN_ROHM_BU21023=m
+CONFIG_TOUCHSCREEN_IQS5XX=m
+CONFIG_TOUCHSCREEN_ZINITIX=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_88PM860X_ONKEY=m
+CONFIG_INPUT_88PM80X_ONKEY=m
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ARIZONA_HAPTICS=m
+CONFIG_INPUT_ATC260X_ONKEY=m
+CONFIG_INPUT_ATMEL_CAPTOUCH=m
+CONFIG_INPUT_BMA150=m
+CONFIG_INPUT_E3X0_BUTTON=m
+CONFIG_INPUT_MAX77650_ONKEY=m
+CONFIG_INPUT_MAX77693_HAPTIC=m
+CONFIG_INPUT_MAX8925_ONKEY=m
+CONFIG_INPUT_MAX8997_HAPTIC=m
+CONFIG_INPUT_MC13783_PWRBUTTON=m
+CONFIG_INPUT_MMA8450=m
+CONFIG_INPUT_GPIO_BEEPER=m
+CONFIG_INPUT_GPIO_DECODER=m
+CONFIG_INPUT_GPIO_VIBRA=m
+CONFIG_INPUT_CPCAP_PWRBUTTON=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_KXTJ9=m
+CONFIG_INPUT_POWERMATE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_REGULATOR_HAPTIC=m
+CONFIG_INPUT_RETU_PWRBUTTON=m
+CONFIG_INPUT_TPS65218_PWRBUTTON=m
+CONFIG_INPUT_AXP20X_PEK=m
+CONFIG_INPUT_TWL4030_PWRBUTTON=m
+CONFIG_INPUT_TWL4030_VIBRA=m
+CONFIG_INPUT_TWL6040_VIBRA=m
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PALMAS_PWRBUTTON=m
+CONFIG_INPUT_PCF50633_PMU=m
+CONFIG_INPUT_PCF8574=m
+CONFIG_INPUT_PWM_BEEPER=m
+CONFIG_INPUT_PWM_VIBRA=m
+CONFIG_INPUT_RK805_PWRKEY=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+CONFIG_INPUT_DA7280_HAPTICS=m
+CONFIG_INPUT_DA9052_ONKEY=m
+CONFIG_INPUT_DA9055_ONKEY=m
+CONFIG_INPUT_DA9063_ONKEY=m
+CONFIG_INPUT_WM831X_ON=m
+CONFIG_INPUT_PCAP=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_IMS_PCU=m
+CONFIG_INPUT_IQS269A=m
+CONFIG_INPUT_IQS626A=m
+CONFIG_INPUT_IQS7222=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_INPUT_CMA3000_I2C=m
+CONFIG_INPUT_DRV260X_HAPTICS=m
+CONFIG_INPUT_DRV2665_HAPTICS=m
+CONFIG_INPUT_DRV2667_HAPTICS=m
+CONFIG_INPUT_RAVE_SP_PWRBUTTON=m
+CONFIG_INPUT_STPMIC1_ONKEY=m
+CONFIG_RMI4_I2C=m
+CONFIG_RMI4_SPI=m
+CONFIG_RMI4_SMB=m
+CONFIG_RMI4_F34=y
+CONFIG_RMI4_F3A=y
+CONFIG_RMI4_F54=y
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_RAW=m
+CONFIG_SERIO_ALTERA_PS2=m
+CONFIG_SERIO_PS2MULT=m
+CONFIG_SERIO_ARC_PS2=m
+CONFIG_SERIO_APBPS2=m
+CONFIG_SERIO_GPIO_PS2=m
+CONFIG_USERIO=m
+CONFIG_GAMEPORT_NS558=m
+CONFIG_GAMEPORT_L4=m
+CONFIG_GAMEPORT_EMU10K1=m
+CONFIG_GAMEPORT_FM801=m
+CONFIG_LEGACY_PTY_COUNT=0
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_FINTEK=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXAR=m
+CONFIG_SERIAL_8250_MEN_MCB=m
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_RUNTIME_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_8250_PERICOM=m
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_KGDB_NMI=y
+CONFIG_SERIAL_MAX3100=m
+CONFIG_SERIAL_MAX310X=y
+CONFIG_SERIAL_UARTLITE=m
+CONFIG_SERIAL_JSM=m
+CONFIG_SERIAL_SCCNXP=y
+CONFIG_SERIAL_SCCNXP_CONSOLE=y
+CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_SERIAL_ALTERA_JTAGUART=m
+CONFIG_SERIAL_ALTERA_UART=m
+CONFIG_SERIAL_XILINX_PS_UART=m
+CONFIG_SERIAL_ARC=m
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_FSL_LPUART=m
+CONFIG_SERIAL_CONEXANT_DIGICOLOR=m
+CONFIG_SERIAL_MEN_Z135=m
+CONFIG_SERIAL_SPRD=m
+CONFIG_SERIAL_LITEUART=m
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_MOXA_INTELLIO=m
+CONFIG_MOXA_SMARTIO=m
+CONFIG_SYNCLINK_GT=m
+CONFIG_N_HDLC=m
+CONFIG_GOLDFISH_TTY=m
+CONFIG_N_GSM=m
+CONFIG_NOZOMI=m
+CONFIG_NULL_TTY=m
+CONFIG_RPMSG_TTY=m
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_TTY_PRINTK=y
+CONFIG_PRINTER=m
+CONFIG_PPDEV=m
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_IPMI_HANDLER=y
+CONFIG_IPMI_DEVICE_INTERFACE=y
+CONFIG_IPMI_SI=y
+CONFIG_IPMI_SSIF=m
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_HW_RANDOM_BA431=m
+CONFIG_HW_RANDOM_VIRTIO=m
+CONFIG_HW_RANDOM_POLARFIRE_SOC=m
+CONFIG_HW_RANDOM_CCTRNG=m
+CONFIG_HW_RANDOM_XIPHERA=m
+CONFIG_APPLICOM=m
+CONFIG_TCG_TIS=y
+CONFIG_TCG_TIS_SPI=m
+CONFIG_TCG_TIS_SPI_CR50=y
+CONFIG_TCG_TIS_I2C_CR50=m
+CONFIG_TCG_TIS_I2C_ATMEL=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
+CONFIG_TCG_TIS_I2C_NUVOTON=m
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_VTPM_PROXY=m
+CONFIG_TCG_TIS_ST33ZP24_I2C=m
+CONFIG_TCG_TIS_ST33ZP24_SPI=m
+CONFIG_XILLYBUS=m
+CONFIG_XILLYBUS_PCIE=m
+CONFIG_XILLYBUS_OF=m
+CONFIG_XILLYUSB=m
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=m
+CONFIG_I2C_MUX_GPIO=m
+CONFIG_I2C_MUX_GPMUX=m
+CONFIG_I2C_MUX_LTC4306=m
+CONFIG_I2C_MUX_PCA9541=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_MUX_PINCTRL=m
+CONFIG_I2C_MUX_REG=m
+CONFIG_I2C_DEMUX_PINCTRL=m
+CONFIG_I2C_MUX_MLXCPLD=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+CONFIG_I2C_I801=m
+CONFIG_I2C_ISCH=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_NVIDIA_GPU=m
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+CONFIG_I2C_CBUS_GPIO=m
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_DESIGNWARE_PCI=m
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_KEMPLD=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_PCA_PLATFORM=m
+CONFIG_I2C_RK3X=m
+CONFIG_I2C_SIMTEC=m
+CONFIG_I2C_XILINX=m
+CONFIG_I2C_DIOLAN_U2C=m
+CONFIG_I2C_DLN2=m
+CONFIG_I2C_CP2615=m
+CONFIG_I2C_PARPORT=m
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TAOS_EVM=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_I2C_VIPERBOARD=m
+CONFIG_I2C_FSI=m
+CONFIG_I2C_VIRTIO=m
+CONFIG_I2C_STUB=m
+CONFIG_I3C=m
+CONFIG_CDNS_I3C_MASTER=m
+CONFIG_DW_I3C_MASTER=m
+CONFIG_SVC_I3C_MASTER=m
+CONFIG_MIPI_I3C_HCI=m
+CONFIG_SPI=y
+CONFIG_SPI_ALTERA=m
+CONFIG_SPI_ALTERA_DFL=m
+CONFIG_SPI_AXI_SPI_ENGINE=m
+CONFIG_SPI_BUTTERFLY=m
+CONFIG_SPI_CADENCE=m
+CONFIG_SPI_CADENCE_XSPI=m
+CONFIG_SPI_DESIGNWARE=m
+CONFIG_SPI_DW_DMA=y
+CONFIG_SPI_DW_PCI=m
+CONFIG_SPI_DW_MMIO=m
+CONFIG_SPI_DLN2=m
+CONFIG_SPI_FSI=m
+CONFIG_SPI_NXP_FLEXSPI=m
+CONFIG_SPI_GPIO=m
+CONFIG_SPI_LM70_LLP=m
+CONFIG_SPI_FSL_SPI=y
+CONFIG_SPI_OC_TINY=m
+CONFIG_SPI_PXA2XX=m
+CONFIG_SPI_SC18IS602=m
+CONFIG_SPI_SIFIVE=y
+CONFIG_SPI_MXIC=m
+CONFIG_SPI_XCOMM=m
+CONFIG_SPI_ZYNQMP_GQSPI=m
+CONFIG_SPI_AMD=m
+CONFIG_SPI_MUX=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_LOOPBACK_TEST=m
+CONFIG_SPI_TLE62X0=m
+CONFIG_SPI_SLAVE=y
+CONFIG_SPI_SLAVE_TIME=m
+CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m
+CONFIG_SPMI=m
+CONFIG_SPMI_HISI3670=m
+CONFIG_HSI=m
+CONFIG_HSI_CHAR=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_PARPORT=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_DP83640_PHY=m
+CONFIG_PTP_1588_CLOCK_INES=m
+CONFIG_PTP_1588_CLOCK_IDT82P33=m
+CONFIG_PTP_1588_CLOCK_IDTCM=m
+CONFIG_PTP_1588_CLOCK_OCP=m
+CONFIG_PINCTRL_AS3722=y
+CONFIG_PINCTRL_AXP209=m
+CONFIG_PINCTRL_DA9062=m
+CONFIG_PINCTRL_MAX77620=m
+CONFIG_PINCTRL_MCP23S08=m
+CONFIG_PINCTRL_MICROCHIP_SGPIO=y
+CONFIG_PINCTRL_OCELOT=y
+CONFIG_PINCTRL_PALMAS=y
+CONFIG_PINCTRL_RK805=m
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_PINCTRL_STMFX=m
+CONFIG_PINCTRL_SX150X=y
+CONFIG_PINCTRL_LOCHNAGAR=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_74XX_MMIO=m
+CONFIG_GPIO_ALTERA=m
+CONFIG_GPIO_CADENCE=m
+CONFIG_GPIO_DWAPB=m
+CONFIG_GPIO_EXAR=m
+CONFIG_GPIO_FTGPIO010=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_GRGPIO=m
+CONFIG_GPIO_HLWD=m
+CONFIG_GPIO_LOGICVC=m
+CONFIG_GPIO_MB86S7X=m
+CONFIG_GPIO_MENZ127=m
+CONFIG_GPIO_SIFIVE=y
+CONFIG_GPIO_SIOX=m
+CONFIG_GPIO_SYSCON=m
+CONFIG_GPIO_WCD934X=m
+CONFIG_GPIO_ADNP=m
+CONFIG_GPIO_GW_PLD=m
+CONFIG_GPIO_MAX7300=m
+CONFIG_GPIO_MAX732X=m
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
+CONFIG_GPIO_PCA9570=m
+CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_TPIC2810=m
+CONFIG_GPIO_ADP5520=m
+CONFIG_GPIO_ARIZONA=m
+CONFIG_GPIO_BD71815=m
+CONFIG_GPIO_BD71828=m
+CONFIG_GPIO_BD9571MWV=m
+CONFIG_GPIO_DA9052=m
+CONFIG_GPIO_DA9055=m
+CONFIG_GPIO_DLN2=m
+CONFIG_GPIO_JANZ_TTL=m
+CONFIG_GPIO_KEMPLD=m
+CONFIG_GPIO_LP3943=m
+CONFIG_GPIO_LP873X=m
+CONFIG_GPIO_LP87565=m
+CONFIG_GPIO_MADERA=m
+CONFIG_GPIO_MAX77620=m
+CONFIG_GPIO_MAX77650=m
+CONFIG_GPIO_PALMAS=y
+CONFIG_GPIO_RC5T583=y
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_TC3589X=y
+CONFIG_GPIO_TPS65086=m
+CONFIG_GPIO_TPS65218=m
+CONFIG_GPIO_TPS6586X=y
+CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_TPS65912=m
+CONFIG_GPIO_TWL4030=m
+CONFIG_GPIO_TWL6040=m
+CONFIG_GPIO_UCB1400=m
+CONFIG_GPIO_WM831X=m
+CONFIG_GPIO_WM8350=m
+CONFIG_GPIO_WM8994=m
+CONFIG_GPIO_PCI_IDIO_16=m
+CONFIG_GPIO_PCIE_IDIO_24=m
+CONFIG_GPIO_RDC321X=m
+CONFIG_GPIO_74X164=m
+CONFIG_GPIO_MAX3191X=m
+CONFIG_GPIO_MAX7301=m
+CONFIG_GPIO_MC33880=m
+CONFIG_GPIO_PISOSR=m
+CONFIG_GPIO_XRA1403=m
+CONFIG_GPIO_MOXTET=m
+CONFIG_GPIO_VIPERBOARD=m
+CONFIG_GPIO_AGGREGATOR=m
+CONFIG_GPIO_VIRTIO=m
+CONFIG_GPIO_SIM=m
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_DS1WM=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_MASTER_SGI=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2405=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2805=m
+CONFIG_W1_SLAVE_DS2430=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2438=m
+CONFIG_W1_SLAVE_DS250X=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+CONFIG_POWER_RESET_AS3722=y
+CONFIG_POWER_RESET_ATC260X=m
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+CONFIG_POWER_RESET_LTC2952=y
+CONFIG_POWER_RESET_MT6323=y
+CONFIG_POWER_RESET_REGULATOR=y
+CONFIG_POWER_RESET_RESTART=y
+CONFIG_POWER_RESET_TPS65086=y
+CONFIG_SYSCON_REBOOT_MODE=m
+CONFIG_NVMEM_REBOOT_MODE=m
+CONFIG_PDA_POWER=m
+CONFIG_GENERIC_ADC_BATTERY=m
+CONFIG_IP5XXX_POWER=m
+CONFIG_MAX8925_POWER=m
+CONFIG_WM831X_BACKUP=m
+CONFIG_WM831X_POWER=m
+CONFIG_WM8350_POWER=m
+CONFIG_TEST_POWER=m
+CONFIG_BATTERY_88PM860X=m
+CONFIG_CHARGER_ADP5061=m
+CONFIG_BATTERY_ACT8945A=m
+CONFIG_BATTERY_CW2015=m
+CONFIG_BATTERY_DS2760=m
+CONFIG_BATTERY_DS2780=m
+CONFIG_BATTERY_DS2781=m
+CONFIG_BATTERY_DS2782=m
+CONFIG_BATTERY_SAMSUNG_SDI=y
+CONFIG_BATTERY_SBS=m
+CONFIG_CHARGER_SBS=m
+CONFIG_MANAGER_SBS=m
+CONFIG_BATTERY_BQ27XXX=m
+CONFIG_BATTERY_DA9030=m
+CONFIG_BATTERY_DA9052=m
+CONFIG_CHARGER_DA9150=m
+CONFIG_BATTERY_DA9150=m
+CONFIG_CHARGER_AXP20X=m
+CONFIG_BATTERY_AXP20X=m
+CONFIG_AXP20X_POWER=m
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_MAX17042=m
+CONFIG_BATTERY_MAX1721X=m
+CONFIG_BATTERY_TWL4030_MADC=m
+CONFIG_CHARGER_88PM860X=m
+CONFIG_CHARGER_PCF50633=m
+CONFIG_BATTERY_RX51=m
+CONFIG_CHARGER_ISP1704=m
+CONFIG_CHARGER_MAX8903=m
+CONFIG_CHARGER_TWL4030=m
+CONFIG_CHARGER_LP8727=m
+CONFIG_CHARGER_LP8788=m
+CONFIG_CHARGER_GPIO=m
+CONFIG_CHARGER_MANAGER=y
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_PWM_FAN=y
+CONFIG_THERMAL_NETLINK=y
+CONFIG_THERMAL_STATISTICS=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CPU_IDLE_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
+CONFIG_THERMAL_EMULATION=y
+CONFIG_THERMAL_MMIO=m
+CONFIG_MAX77620_THERMAL=m
+CONFIG_DA9062_THERMAL=m
+CONFIG_GENERIC_ADC_THERMAL=m
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=m
+CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SOFT_WATCHDOG_PRETIMEOUT=y
+CONFIG_BD957XMUF_WATCHDOG=m
+CONFIG_DA9052_WATCHDOG=m
+CONFIG_DA9055_WATCHDOG=m
+CONFIG_DA9063_WATCHDOG=m
+CONFIG_DA9062_WATCHDOG=m
+CONFIG_GPIO_WATCHDOG=m
+CONFIG_MENF21BMC_WATCHDOG=m
+CONFIG_MENZ069_WATCHDOG=m
+CONFIG_WM831X_WATCHDOG=m
+CONFIG_WM8350_WATCHDOG=m
+CONFIG_XILINX_WATCHDOG=m
+CONFIG_ZIIRAVE_WATCHDOG=m
+CONFIG_RAVE_SP_WATCHDOG=m
+CONFIG_CADENCE_WATCHDOG=m
+CONFIG_DW_WATCHDOG=m
+CONFIG_RN5T618_WATCHDOG=m
+CONFIG_TWL4030_WATCHDOG=m
+CONFIG_MAX63XX_WATCHDOG=m
+CONFIG_MAX77620_WATCHDOG=m
+CONFIG_RETU_WATCHDOG=m
+CONFIG_STPMIC1_WATCHDOG=m
+CONFIG_ALIM7101_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_KEMPLD_WDT=m
+CONFIG_MEN_A21_WDT=m
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+CONFIG_USBPCWATCHDOG=m
+CONFIG_SSB_SDIOHOST=y
+CONFIG_SSB_DRIVER_GPIO=y
+CONFIG_BCMA_HOST_SOC=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_MFD_ACT8945A=m
+CONFIG_MFD_AS3711=y
+CONFIG_MFD_AS3722=y
+CONFIG_PMIC_ADP5520=y
+CONFIG_MFD_AAT2870_CORE=y
+CONFIG_MFD_ATMEL_FLEXCOM=m
+CONFIG_MFD_ATMEL_HLCDC=m
+CONFIG_MFD_BCM590XX=m
+CONFIG_MFD_BD9571MWV=m
+CONFIG_MFD_AXP20X_I2C=m
+CONFIG_MFD_MADERA=m
+CONFIG_MFD_MADERA_I2C=m
+CONFIG_MFD_MADERA_SPI=m
+CONFIG_MFD_CS47L15=y
+CONFIG_MFD_CS47L35=y
+CONFIG_MFD_CS47L85=y
+CONFIG_MFD_CS47L90=y
+CONFIG_MFD_CS47L92=y
+CONFIG_PMIC_DA903X=y
+CONFIG_MFD_DA9052_SPI=y
+CONFIG_MFD_DA9052_I2C=y
+CONFIG_MFD_DA9055=y
+CONFIG_MFD_DA9062=m
+CONFIG_MFD_DA9063=y
+CONFIG_MFD_DA9150=m
+CONFIG_MFD_DLN2=m
+CONFIG_MFD_GATEWORKS_GSC=m
+CONFIG_MFD_MC13XXX_SPI=m
+CONFIG_MFD_MC13XXX_I2C=m
+CONFIG_MFD_MP2629=m
+CONFIG_MFD_HI6421_PMIC=m
+CONFIG_MFD_HI6421_SPMI=m
+CONFIG_HTC_PASIC3=m
+CONFIG_HTC_I2CPLD=y
+CONFIG_LPC_ICH=m
+CONFIG_MFD_IQS62X=m
+CONFIG_MFD_JANZ_CMODIO=m
+CONFIG_MFD_KEMPLD=m
+CONFIG_MFD_88PM800=m
+CONFIG_MFD_88PM805=m
+CONFIG_MFD_88PM860X=y
+CONFIG_MFD_MAX14577=y
+CONFIG_MFD_MAX77620=y
+CONFIG_MFD_MAX77650=m
+CONFIG_MFD_MAX77686=y
+CONFIG_MFD_MAX77693=y
+CONFIG_MFD_MAX77714=m
+CONFIG_MFD_MAX77843=y
+CONFIG_MFD_MAX8907=m
+CONFIG_MFD_MAX8925=y
+CONFIG_MFD_MAX8997=y
+CONFIG_MFD_MAX8998=y
+CONFIG_MFD_MT6360=m
+CONFIG_MFD_MT6397=m
+CONFIG_MFD_MENF21BMC=m
+CONFIG_EZX_PCAP=y
+CONFIG_MFD_CPCAP=m
+CONFIG_MFD_VIPERBOARD=m
+CONFIG_MFD_NTXEC=m
+CONFIG_MFD_RETU=m
+CONFIG_MFD_PCF50633=m
+CONFIG_PCF50633_ADC=m
+CONFIG_PCF50633_GPIO=m
+CONFIG_UCB1400_CORE=m
+CONFIG_MFD_RT4831=m
+CONFIG_MFD_RT5033=m
+CONFIG_MFD_RC5T583=y
+CONFIG_MFD_RK808=m
+CONFIG_MFD_RN5T618=m
+CONFIG_MFD_SEC_CORE=y
+CONFIG_MFD_SI476X_CORE=m
+CONFIG_MFD_SM501=m
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_MFD_SKY81452=m
+CONFIG_MFD_STMPE=y
+CONFIG_STMPE_SPI=y
+CONFIG_MFD_TI_AM335X_TSCADC=m
+CONFIG_MFD_LP3943=m
+CONFIG_MFD_LP8788=y
+CONFIG_MFD_TI_LMU=m
+CONFIG_MFD_PALMAS=y
+CONFIG_TPS6105X=m
+CONFIG_TPS65010=m
+CONFIG_TPS6507X=m
+CONFIG_MFD_TPS65086=m
+CONFIG_MFD_TPS65090=y
+CONFIG_MFD_TI_LP873X=m
+CONFIG_MFD_TI_LP87565=m
+CONFIG_MFD_TPS65218=m
+CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_TPS65912_I2C=y
+CONFIG_MFD_TPS65912_SPI=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL6040_CORE=y
+CONFIG_MFD_LM3533=m
+CONFIG_MFD_TC3589X=y
+CONFIG_MFD_VX855=m
+CONFIG_MFD_LOCHNAGAR=y
+CONFIG_MFD_ARIZONA_I2C=m
+CONFIG_MFD_ARIZONA_SPI=m
+CONFIG_MFD_CS47L24=y
+CONFIG_MFD_WM5102=y
+CONFIG_MFD_WM5110=y
+CONFIG_MFD_WM8997=y
+CONFIG_MFD_WM8998=y
+CONFIG_MFD_WM8400=y
+CONFIG_MFD_WM831X_I2C=y
+CONFIG_MFD_WM831X_SPI=y
+CONFIG_MFD_WM8350_I2C=y
+CONFIG_MFD_WM8994=m
+CONFIG_MFD_ROHM_BD718XX=m
+CONFIG_MFD_ROHM_BD71828=m
+CONFIG_MFD_ROHM_BD957XMUF=m
+CONFIG_MFD_STPMIC1=m
+CONFIG_MFD_WCD934X=m
+CONFIG_MFD_ATC260X_I2C=m
+CONFIG_MFD_QCOM_PM8008=m
+CONFIG_RAVE_SP_CORE=m
+CONFIG_MFD_INTEL_M10_BMC=m
+CONFIG_MFD_RSMU_I2C=m
+CONFIG_MFD_RSMU_SPI=m
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_REGULATOR_88PG86X=m
+CONFIG_REGULATOR_88PM800=m
+CONFIG_REGULATOR_88PM8607=m
+CONFIG_REGULATOR_ACT8865=m
+CONFIG_REGULATOR_ACT8945A=m
+CONFIG_REGULATOR_AD5398=m
+CONFIG_REGULATOR_AAT2870=m
+CONFIG_REGULATOR_ARIZONA_LDO1=m
+CONFIG_REGULATOR_ARIZONA_MICSUPP=m
+CONFIG_REGULATOR_AS3711=m
+CONFIG_REGULATOR_AS3722=m
+CONFIG_REGULATOR_ATC260X=m
+CONFIG_REGULATOR_AXP20X=m
+CONFIG_REGULATOR_BCM590XX=m
+CONFIG_REGULATOR_BD71815=m
+CONFIG_REGULATOR_BD71828=m
+CONFIG_REGULATOR_BD718XX=m
+CONFIG_REGULATOR_BD9571MWV=m
+CONFIG_REGULATOR_BD957XMUF=m
+CONFIG_REGULATOR_CPCAP=m
+CONFIG_REGULATOR_DA903X=m
+CONFIG_REGULATOR_DA9052=m
+CONFIG_REGULATOR_DA9055=m
+CONFIG_REGULATOR_DA9062=m
+CONFIG_REGULATOR_DA9063=m
+CONFIG_REGULATOR_DA9121=m
+CONFIG_REGULATOR_DA9210=m
+CONFIG_REGULATOR_DA9211=m
+CONFIG_REGULATOR_FAN53555=m
+CONFIG_REGULATOR_FAN53880=m
+CONFIG_REGULATOR_GPIO=m
+CONFIG_REGULATOR_HI6421=m
+CONFIG_REGULATOR_HI6421V530=m
+CONFIG_REGULATOR_HI6421V600=m
+CONFIG_REGULATOR_ISL9305=m
+CONFIG_REGULATOR_ISL6271A=m
+CONFIG_REGULATOR_LM363X=m
+CONFIG_REGULATOR_LOCHNAGAR=m
+CONFIG_REGULATOR_LP3971=m
+CONFIG_REGULATOR_LP3972=m
+CONFIG_REGULATOR_LP872X=m
+CONFIG_REGULATOR_LP873X=m
+CONFIG_REGULATOR_LP8755=m
+CONFIG_REGULATOR_LP87565=m
+CONFIG_REGULATOR_LP8788=m
+CONFIG_REGULATOR_LTC3589=m
+CONFIG_REGULATOR_LTC3676=m
+CONFIG_REGULATOR_MAX14577=m
+CONFIG_REGULATOR_MAX1586=m
+CONFIG_REGULATOR_MAX77620=m
+CONFIG_REGULATOR_MAX77650=m
+CONFIG_REGULATOR_MAX8649=m
+CONFIG_REGULATOR_MAX8660=m
+CONFIG_REGULATOR_MAX8893=m
+CONFIG_REGULATOR_MAX8907=m
+CONFIG_REGULATOR_MAX8925=m
+CONFIG_REGULATOR_MAX8952=m
+CONFIG_REGULATOR_MAX8973=m
+CONFIG_REGULATOR_MAX8997=m
+CONFIG_REGULATOR_MAX8998=m
+CONFIG_REGULATOR_MAX20086=m
+CONFIG_REGULATOR_MAX77686=m
+CONFIG_REGULATOR_MAX77693=m
+CONFIG_REGULATOR_MAX77802=m
+CONFIG_REGULATOR_MAX77826=m
+CONFIG_REGULATOR_MC13783=m
+CONFIG_REGULATOR_MC13892=m
+CONFIG_REGULATOR_MCP16502=m
+CONFIG_REGULATOR_MP5416=m
+CONFIG_REGULATOR_MP8859=m
+CONFIG_REGULATOR_MP886X=m
+CONFIG_REGULATOR_MPQ7920=m
+CONFIG_REGULATOR_MT6311=m
+CONFIG_REGULATOR_MT6315=m
+CONFIG_REGULATOR_MT6323=m
+CONFIG_REGULATOR_MT6358=m
+CONFIG_REGULATOR_MT6359=m
+CONFIG_REGULATOR_MT6360=m
+CONFIG_REGULATOR_MT6397=m
+CONFIG_REGULATOR_PALMAS=m
+CONFIG_REGULATOR_PCA9450=m
+CONFIG_REGULATOR_PCAP=m
+CONFIG_REGULATOR_PCF50633=m
+CONFIG_REGULATOR_PF8X00=m
+CONFIG_REGULATOR_PFUZE100=m
+CONFIG_REGULATOR_PV88060=m
+CONFIG_REGULATOR_PV88080=m
+CONFIG_REGULATOR_PV88090=m
+CONFIG_REGULATOR_PWM=m
+CONFIG_REGULATOR_QCOM_SPMI=m
+CONFIG_REGULATOR_QCOM_USB_VBUS=m
+CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m
+CONFIG_REGULATOR_RC5T583=m
+CONFIG_REGULATOR_RK808=m
+CONFIG_REGULATOR_RN5T618=m
+CONFIG_REGULATOR_RT4801=m
+CONFIG_REGULATOR_RT4831=m
+CONFIG_REGULATOR_RT5033=m
+CONFIG_REGULATOR_RT5190A=m
+CONFIG_REGULATOR_RT5759=m
+CONFIG_REGULATOR_RT6160=m
+CONFIG_REGULATOR_RT6245=m
+CONFIG_REGULATOR_RTQ2134=m
+CONFIG_REGULATOR_RTMV20=m
+CONFIG_REGULATOR_RTQ6752=m
+CONFIG_REGULATOR_S2MPA01=m
+CONFIG_REGULATOR_S2MPS11=m
+CONFIG_REGULATOR_S5M8767=m
+CONFIG_REGULATOR_SKY81452=m
+CONFIG_REGULATOR_SLG51000=m
+CONFIG_REGULATOR_STPMIC1=m
+CONFIG_REGULATOR_SY8106A=m
+CONFIG_REGULATOR_SY8824X=m
+CONFIG_REGULATOR_SY8827N=m
+CONFIG_REGULATOR_TPS51632=m
+CONFIG_REGULATOR_TPS62360=m
+CONFIG_REGULATOR_TPS6286X=m
+CONFIG_REGULATOR_TPS65023=m
+CONFIG_REGULATOR_TPS6507X=m
+CONFIG_REGULATOR_TPS65086=m
+CONFIG_REGULATOR_TPS65090=m
+CONFIG_REGULATOR_TPS65132=m
+CONFIG_REGULATOR_TPS65218=m
+CONFIG_REGULATOR_TPS6524X=m
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_REGULATOR_TPS65910=m
+CONFIG_REGULATOR_TPS65912=m
+CONFIG_REGULATOR_TWL4030=m
+CONFIG_REGULATOR_VCTRL=m
+CONFIG_REGULATOR_WM831X=m
+CONFIG_REGULATOR_WM8350=m
+CONFIG_REGULATOR_WM8400=m
+CONFIG_REGULATOR_WM8994=m
+CONFIG_REGULATOR_QCOM_LABIBB=m
+CONFIG_RC_CORE=m
+CONFIG_LIRC=y
+CONFIG_RC_DECODERS=y
+CONFIG_IR_IMON_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_RCMM_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
+CONFIG_IR_HIX5HD2=m
+CONFIG_IR_IGORPLUGUSB=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_IMON=m
+CONFIG_IR_IMON_RAW=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_PWM_TX=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_SERIAL=m
+CONFIG_IR_SERIAL_TRANSMITTER=y
+CONFIG_IR_SPI=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_TOY=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_RC_XBOX_DVD=m
+CONFIG_MEDIA_CEC_RC=y
+CONFIG_MEDIA_CEC_SUPPORT=y
+CONFIG_CEC_CH7322=m
+CONFIG_USB_PULSE8_CEC=m
+CONFIG_USB_RAINSHADOW_CEC=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_SUPPORT_FILTER=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_RADIO_SUPPORT=y
+CONFIG_MEDIA_SDR_SUPPORT=y
+CONFIG_MEDIA_PLATFORM_SUPPORT=y
+CONFIG_MEDIA_TEST_SUPPORT=y
+CONFIG_V4L2_FLASH_LED_CLASS=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_GSPCA=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_PWC=m
+CONFIG_USB_S2255=m
+CONFIG_VIDEO_USBTV=m
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_VIDEO_GO7007=m
+CONFIG_VIDEO_GO7007_USB=m
+CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_STK1160_COMMON=m
+CONFIG_VIDEO_AU0828=m
+CONFIG_VIDEO_AU0828_RC=y
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_DVB_AS102=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+CONFIG_DVB_USB_V2=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_AF9035=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_AZ6007=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_DVBSKY=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_MXL111SF=m
+CONFIG_DVB_USB_RTL28XXU=m
+CONFIG_DVB_USB_ZD1301=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_CXUSB_ANALOG=y
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_PCTV452E=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_SMS_USB_DRV=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_V4L2=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_USB_AIRSPY=m
+CONFIG_USB_HACKRF=m
+CONFIG_USB_MSI2500=m
+CONFIG_MEDIA_PCI_SUPPORT=y
+CONFIG_VIDEO_SOLO6X10=m
+CONFIG_VIDEO_TW5864=m
+CONFIG_VIDEO_TW68=m
+CONFIG_VIDEO_TW686X=m
+CONFIG_VIDEO_DT3155=m
+CONFIG_VIDEO_IVTV=m
+CONFIG_VIDEO_IVTV_ALSA=m
+CONFIG_VIDEO_FB_IVTV=m
+CONFIG_VIDEO_BT848=m
+CONFIG_DVB_BT8XX=m
+CONFIG_VIDEO_CX18=m
+CONFIG_VIDEO_CX18_ALSA=m
+CONFIG_VIDEO_CX23885=m
+CONFIG_MEDIA_ALTERA_CI=m
+CONFIG_VIDEO_CX25821=m
+CONFIG_VIDEO_CX25821_ALSA=m
+CONFIG_VIDEO_CX88=m
+CONFIG_VIDEO_CX88_ALSA=m
+CONFIG_VIDEO_CX88_BLACKBIRD=m
+CONFIG_VIDEO_CX88_DVB=m
+CONFIG_VIDEO_SAA7134=m
+CONFIG_VIDEO_SAA7134_ALSA=m
+CONFIG_VIDEO_SAA7134_DVB=m
+CONFIG_VIDEO_SAA7134_GO7007=m
+CONFIG_VIDEO_SAA7164=m
+CONFIG_DVB_B2C2_FLEXCOP_PCI=m
+CONFIG_DVB_DDBRIDGE=m
+CONFIG_DVB_DM1105=m
+CONFIG_MANTIS_CORE=m
+CONFIG_DVB_MANTIS=m
+CONFIG_DVB_HOPPER=m
+CONFIG_DVB_NETUP_UNIDVB=m
+CONFIG_DVB_NGENE=m
+CONFIG_DVB_PLUTO2=m
+CONFIG_DVB_PT1=m
+CONFIG_DVB_PT3=m
+CONFIG_DVB_SMIPCIE=m
+CONFIG_RADIO_MAXIRADIO=m
+CONFIG_RADIO_SAA7706H=m
+CONFIG_RADIO_SHARK=m
+CONFIG_RADIO_SHARK2=m
+CONFIG_RADIO_SI4713=m
+CONFIG_RADIO_SI476X=m
+CONFIG_RADIO_TEA5764=m
+CONFIG_RADIO_TEF6862=m
+CONFIG_RADIO_WL1273=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_KEENE=m
+CONFIG_USB_MA901=m
+CONFIG_USB_MR800=m
+CONFIG_USB_RAREMONO=m
+CONFIG_RADIO_SI470X=m
+CONFIG_USB_SI470X=m
+CONFIG_I2C_SI470X=m
+CONFIG_USB_SI4713=m
+CONFIG_PLATFORM_SI4713=m
+CONFIG_RADIO_WL128X=m
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SDR_PLATFORM_DRIVERS=y
+CONFIG_DVB_PLATFORM_DRIVERS=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m
+CONFIG_VIDEO_MUX=m
+CONFIG_VIDEO_ASPEED=m
+CONFIG_VIDEO_CADENCE_CSI2RX=m
+CONFIG_VIDEO_CADENCE_CSI2TX=m
+CONFIG_VIDEO_CAFE_CCIC=m
+CONFIG_VIDEO_XILINX=m
+CONFIG_VIDEO_XILINX_CSI2RXSS=m
+CONFIG_VIDEO_XILINX_TPG=m
+CONFIG_SMS_SDIO_DRV=m
+CONFIG_V4L_TEST_DRIVERS=y
+CONFIG_VIDEO_VIM2M=m
+CONFIG_VIDEO_VICODEC=m
+CONFIG_VIDEO_VIMC=m
+CONFIG_VIDEO_VIVID=m
+CONFIG_VIDEO_VIVID_CEC=y
+CONFIG_DVB_FIREDTV=m
+CONFIG_SMS_SIANO_DEBUGFS=y
+CONFIG_VIDEO_HI556=m
+CONFIG_VIDEO_HI846=m
+CONFIG_VIDEO_HI847=m
+CONFIG_VIDEO_IMX208=m
+CONFIG_VIDEO_IMX214=m
+CONFIG_VIDEO_IMX219=m
+CONFIG_VIDEO_IMX258=m
+CONFIG_VIDEO_IMX274=m
+CONFIG_VIDEO_IMX290=m
+CONFIG_VIDEO_IMX319=m
+CONFIG_VIDEO_IMX334=m
+CONFIG_VIDEO_IMX335=m
+CONFIG_VIDEO_IMX355=m
+CONFIG_VIDEO_IMX412=m
+CONFIG_VIDEO_MT9M001=m
+CONFIG_VIDEO_MT9M032=m
+CONFIG_VIDEO_MT9M111=m
+CONFIG_VIDEO_MT9P031=m
+CONFIG_VIDEO_MT9T001=m
+CONFIG_VIDEO_MT9T112=m
+CONFIG_VIDEO_MT9V032=m
+CONFIG_VIDEO_MT9V111=m
+CONFIG_VIDEO_NOON010PC30=m
+CONFIG_VIDEO_OG01A1B=m
+CONFIG_VIDEO_OV02A10=m
+CONFIG_VIDEO_OV08D10=m
+CONFIG_VIDEO_OV13858=m
+CONFIG_VIDEO_OV13B10=m
+CONFIG_VIDEO_OV2659=m
+CONFIG_VIDEO_OV2680=m
+CONFIG_VIDEO_OV2685=m
+CONFIG_VIDEO_OV5640=m
+CONFIG_VIDEO_OV5645=m
+CONFIG_VIDEO_OV5647=m
+CONFIG_VIDEO_OV5670=m
+CONFIG_VIDEO_OV5675=m
+CONFIG_VIDEO_OV5693=m
+CONFIG_VIDEO_OV5695=m
+CONFIG_VIDEO_OV6650=m
+CONFIG_VIDEO_OV7251=m
+CONFIG_VIDEO_OV772X=m
+CONFIG_VIDEO_OV7740=m
+CONFIG_VIDEO_OV8856=m
+CONFIG_VIDEO_OV9282=m
+CONFIG_VIDEO_OV9640=m
+CONFIG_VIDEO_OV9650=m
+CONFIG_VIDEO_RDACM20=m
+CONFIG_VIDEO_RDACM21=m
+CONFIG_VIDEO_RJ54N1=m
+CONFIG_VIDEO_S5C73M3=m
+CONFIG_VIDEO_S5K4ECGX=m
+CONFIG_VIDEO_S5K5BAF=m
+CONFIG_VIDEO_S5K6A3=m
+CONFIG_VIDEO_S5K6AA=m
+CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_VS6624=m
+CONFIG_VIDEO_CCS=m
+CONFIG_VIDEO_ET8EK8=m
+CONFIG_VIDEO_M5MOLS=m
+CONFIG_VIDEO_AD5820=m
+CONFIG_VIDEO_AK7375=m
+CONFIG_VIDEO_DW9714=m
+CONFIG_VIDEO_DW9768=m
+CONFIG_VIDEO_DW9807_VCM=m
+CONFIG_VIDEO_ADP1653=m
+CONFIG_VIDEO_LM3560=m
+CONFIG_VIDEO_LM3646=m
+CONFIG_VIDEO_TDA1997X=m
+CONFIG_VIDEO_TDA9840=m
+CONFIG_VIDEO_TEA6415C=m
+CONFIG_VIDEO_TEA6420=m
+CONFIG_VIDEO_TLV320AIC23B=m
+CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_ADV7183=m
+CONFIG_VIDEO_ADV748X=m
+CONFIG_VIDEO_ADV7604=m
+CONFIG_VIDEO_ADV7604_CEC=y
+CONFIG_VIDEO_ADV7842=m
+CONFIG_VIDEO_ADV7842_CEC=y
+CONFIG_VIDEO_BT819=m
+CONFIG_VIDEO_BT856=m
+CONFIG_VIDEO_BT866=m
+CONFIG_VIDEO_ISL7998X=m
+CONFIG_VIDEO_KS0127=m
+CONFIG_VIDEO_MAX9286=m
+CONFIG_VIDEO_ML86V7667=m
+CONFIG_VIDEO_SAA7110=m
+CONFIG_VIDEO_TC358743=m
+CONFIG_VIDEO_TC358743_CEC=y
+CONFIG_VIDEO_TVP514X=m
+CONFIG_VIDEO_TVP7002=m
+CONFIG_VIDEO_TW9910=m
+CONFIG_VIDEO_VPX3220=m
+CONFIG_VIDEO_AD9389B=m
+CONFIG_VIDEO_ADV7170=m
+CONFIG_VIDEO_ADV7175=m
+CONFIG_VIDEO_ADV7343=m
+CONFIG_VIDEO_ADV7393=m
+CONFIG_VIDEO_AK881X=m
+CONFIG_VIDEO_SAA7185=m
+CONFIG_VIDEO_THS8200=m
+CONFIG_SDR_MAX2175=m
+CONFIG_VIDEO_I2C=m
+CONFIG_VIDEO_ST_MIPID02=m
+CONFIG_VIDEO_THS7303=m
+CONFIG_CXD2880_SPI_DRV=m
+CONFIG_VIDEO_GS1662=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_DIB9000=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_CXD2880=m
+CONFIG_DVB_MN88443X=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LNBH29=m
+CONFIG_DVB_DUMMY_FE=m
+CONFIG_DRM=m
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_DP_AUX_CHARDEV=y
+CONFIG_DRM_DP_CEC=y
+CONFIG_DRM_I2C_NXP_TDA998X=m
+CONFIG_DRM_I2C_NXP_TDA9950=m
+CONFIG_DRM_KOMEDA=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_AMDGPU=m
+CONFIG_DRM_AMDGPU_SI=y
+CONFIG_DRM_AMDGPU_CIK=y
+CONFIG_DRM_AMDGPU_USERPTR=y
+CONFIG_DRM_AMD_ACP=y
+CONFIG_DRM_AMD_DC_HDCP=y
+CONFIG_DRM_AMD_DC_SI=y
+CONFIG_DRM_NOUVEAU=m
+CONFIG_DRM_AST=m
+CONFIG_DRM_SMI=m
+CONFIG_DRM_SMI_HDMI=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_CYBER2000=m
+CONFIG_FB_ASILIANT=y
+CONFIG_FB_IMSTT=y
+CONFIG_FB_UVESA=m
+CONFIG_FB_EFI=y
+CONFIG_FB_OPENCORES=m
+CONFIG_FB_S1D13XXX=m
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_I2C=y
+CONFIG_FB_RIVA=m
+CONFIG_FB_RIVA_I2C=y
+CONFIG_FB_I740=m
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_RADEON=m
+CONFIG_FB_ATY128=m
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+CONFIG_FB_S3=m
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_NEOMAGIC=m
+CONFIG_FB_KYRO=m
+CONFIG_FB_3DFX=m
+# CONFIG_FB_3DFX_I2C is not set
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_VT8623=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_ARK=m
+CONFIG_FB_PM3=m
+CONFIG_FB_CARMINE=m
+CONFIG_FB_SM501=m
+CONFIG_FB_SMSCUFX=m
+CONFIG_FB_UDL=m
+CONFIG_FB_GOLDFISH=m
+CONFIG_FB_METRONOME=m
+CONFIG_FB_MB862XX=m
+CONFIG_FB_SIMPLE=m
+CONFIG_FB_SSD1307=m
+CONFIG_FB_SM712=m
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_L4F00242T03=m
+CONFIG_LCD_LMS283GF05=m
+CONFIG_LCD_LTV350QV=m
+CONFIG_LCD_ILI922X=m
+CONFIG_LCD_TDO24M=m
+CONFIG_LCD_VGG2432A4=m
+CONFIG_LCD_PLATFORM=m
+CONFIG_LCD_AMS369FG06=m
+CONFIG_LCD_LMS501KF03=m
+CONFIG_LCD_HX8357=m
+CONFIG_LCD_OTM3225A=m
+CONFIG_BACKLIGHT_KTD253=m
+CONFIG_BACKLIGHT_LM3533=m
+CONFIG_BACKLIGHT_PWM=m
+CONFIG_BACKLIGHT_DA903X=m
+CONFIG_BACKLIGHT_DA9052=m
+CONFIG_BACKLIGHT_MAX8925=m
+CONFIG_BACKLIGHT_QCOM_WLED=m
+CONFIG_BACKLIGHT_RT4831=m
+CONFIG_BACKLIGHT_WM831X=m
+CONFIG_BACKLIGHT_ADP5520=m
+CONFIG_BACKLIGHT_ADP8860=m
+CONFIG_BACKLIGHT_ADP8870=m
+CONFIG_BACKLIGHT_88PM860X=m
+CONFIG_BACKLIGHT_PCF50633=m
+CONFIG_BACKLIGHT_AAT2870=m
+CONFIG_BACKLIGHT_LM3630A=m
+CONFIG_BACKLIGHT_LM3639=m
+CONFIG_BACKLIGHT_LP855X=m
+CONFIG_BACKLIGHT_LP8788=m
+CONFIG_BACKLIGHT_PANDORA=m
+CONFIG_BACKLIGHT_SKY81452=m
+CONFIG_BACKLIGHT_AS3711=m
+CONFIG_BACKLIGHT_GPIO=m
+CONFIG_BACKLIGHT_LV5207LP=m
+CONFIG_BACKLIGHT_BD6107=m
+CONFIG_BACKLIGHT_ARCXCNN=m
+CONFIG_BACKLIGHT_RAVE_SP=m
+CONFIG_BACKLIGHT_LED=m
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y
+CONFIG_SOUND=m
+# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
+CONFIG_SND=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_DUMMY=m
+CONFIG_SND_ALOOP=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+CONFIG_SND_MTS64=m
+CONFIG_SND_SERIAL_U16550=m
+CONFIG_SND_SERIAL_GENERIC=m
+CONFIG_SND_MPU401=m
+CONFIG_SND_PORTMAN2X4=m
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AD1889=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_ATIIXP_MODEM=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
+CONFIG_SND_AW2=m
+CONFIG_SND_BT87X=m
+CONFIG_SND_CA0106=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_OXYGEN=m
+CONFIG_SND_CS4281=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CTXFI=m
+CONFIG_SND_DARLA20=m
+CONFIG_SND_GINA20=m
+CONFIG_SND_LAYLA20=m
+CONFIG_SND_DARLA24=m
+CONFIG_SND_GINA24=m
+CONFIG_SND_LAYLA24=m
+CONFIG_SND_MONA=m
+CONFIG_SND_MIA=m
+CONFIG_SND_ECHO3G=m
+CONFIG_SND_INDIGO=m
+CONFIG_SND_INDIGOIO=m
+CONFIG_SND_INDIGODJ=m
+CONFIG_SND_INDIGOIOX=m
+CONFIG_SND_INDIGODJX=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X_BOOL=y
+CONFIG_SND_HDSP=m
+CONFIG_SND_HDSPM=m
+CONFIG_SND_ICE1724=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_LOLA=m
+CONFIG_SND_LX6464ES=m
+CONFIG_SND_MIXART=m
+CONFIG_SND_NM256=m
+CONFIG_SND_PCXHR=m
+CONFIG_SND_RIPTIDE=m
+CONFIG_SND_RME32=m
+CONFIG_SND_RME96=m
+CONFIG_SND_RME9652=m
+CONFIG_SND_VIA82XX=m
+CONFIG_SND_VIA82XX_MODEM=m
+CONFIG_SND_VIRTUOSO=m
+CONFIG_SND_VX222=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_INPUT_BEEP=y
+CONFIG_SND_HDA_INPUT_BEEP_MODE=0
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=m
+CONFIG_SND_HDA_CODEC_ANALOG=m
+CONFIG_SND_HDA_CODEC_SIGMATEL=m
+CONFIG_SND_HDA_CODEC_VIA=m
+CONFIG_SND_HDA_CODEC_HDMI=m
+CONFIG_SND_HDA_CODEC_CIRRUS=m
+CONFIG_SND_HDA_CODEC_CS8409=m
+CONFIG_SND_HDA_CODEC_CONEXANT=m
+CONFIG_SND_HDA_CODEC_CA0110=m
+CONFIG_SND_HDA_CODEC_CA0132=m
+CONFIG_SND_HDA_CODEC_CMEDIA=m
+CONFIG_SND_HDA_CODEC_SI3054=m
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_USB_HIFACE=m
+CONFIG_SND_BCD2000=m
+CONFIG_SND_USB_POD=m
+CONFIG_SND_USB_PODHD=m
+CONFIG_SND_USB_TONEPORT=m
+CONFIG_SND_USB_VARIAX=m
+CONFIG_SND_DICE=m
+CONFIG_SND_OXFW=m
+CONFIG_SND_ISIGHT=m
+CONFIG_SND_FIREWORKS=m
+CONFIG_SND_BEBOB=m
+CONFIG_SND_FIREWIRE_DIGI00X=m
+CONFIG_SND_FIREWIRE_TASCAM=m
+CONFIG_SND_FIREWIRE_MOTU=m
+CONFIG_SND_FIREFACE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_ADI=m
+CONFIG_SND_SOC_ADI_AXI_I2S=m
+CONFIG_SND_SOC_ADI_AXI_SPDIF=m
+CONFIG_SND_SOC_AMD_ACP=m
+CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m
+CONFIG_SND_AMD_ACP_CONFIG=m
+CONFIG_SND_ATMEL_SOC=m
+CONFIG_SND_SOC_MIKROE_PROTO=m
+CONFIG_SND_BCM63XX_I2S_WHISTLER=m
+CONFIG_SND_DESIGNWARE_I2S=m
+CONFIG_SND_DESIGNWARE_PCM=y
+CONFIG_SND_SOC_FSL_ASRC=m
+CONFIG_SND_SOC_FSL_SAI=m
+CONFIG_SND_SOC_FSL_MQS=m
+CONFIG_SND_SOC_FSL_AUDMIX=m
+CONFIG_SND_SOC_FSL_SSI=m
+CONFIG_SND_SOC_FSL_SPDIF=m
+CONFIG_SND_SOC_FSL_ESAI=m
+CONFIG_SND_SOC_FSL_MICFIL=m
+CONFIG_SND_SOC_FSL_EASRC=m
+CONFIG_SND_SOC_FSL_XCVR=m
+CONFIG_SND_SOC_FSL_RPMSG=m
+CONFIG_SND_SOC_IMX_AUDMUX=m
+CONFIG_SND_I2S_HI6210_I2S=m
+CONFIG_SND_SOC_IMG=y
+CONFIG_SND_SOC_IMG_I2S_IN=m
+CONFIG_SND_SOC_IMG_I2S_OUT=m
+CONFIG_SND_SOC_IMG_PARALLEL_OUT=m
+CONFIG_SND_SOC_IMG_SPDIF_IN=m
+CONFIG_SND_SOC_IMG_SPDIF_OUT=m
+CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC=m
+CONFIG_SND_SOC_MTK_BTCVSD=m
+CONFIG_SND_SOC_SOF_TOPLEVEL=y
+CONFIG_SND_SOC_SOF_PCI=m
+CONFIG_SND_SOC_SOF_OF=m
+CONFIG_SND_SOC_XILINX_I2S=m
+CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER=m
+CONFIG_SND_SOC_XILINX_SPDIF=m
+CONFIG_SND_SOC_XTFPGA_I2S=m
+CONFIG_SND_SOC_AC97_CODEC=m
+CONFIG_SND_SOC_ADAU1372_I2C=m
+CONFIG_SND_SOC_ADAU1372_SPI=m
+CONFIG_SND_SOC_ADAU1701=m
+CONFIG_SND_SOC_ADAU1761_I2C=m
+CONFIG_SND_SOC_ADAU1761_SPI=m
+CONFIG_SND_SOC_ADAU7002=m
+CONFIG_SND_SOC_ADAU7118_HW=m
+CONFIG_SND_SOC_ADAU7118_I2C=m
+CONFIG_SND_SOC_AK4104=m
+CONFIG_SND_SOC_AK4118=m
+CONFIG_SND_SOC_AK4375=m
+CONFIG_SND_SOC_AK4458=m
+CONFIG_SND_SOC_AK4554=m
+CONFIG_SND_SOC_AK4613=m
+CONFIG_SND_SOC_AK4642=m
+CONFIG_SND_SOC_AK5386=m
+CONFIG_SND_SOC_AK5558=m
+CONFIG_SND_SOC_ALC5623=m
+CONFIG_SND_SOC_AW8738=m
+CONFIG_SND_SOC_BD28623=m
+CONFIG_SND_SOC_BT_SCO=m
+CONFIG_SND_SOC_CPCAP=m
+CONFIG_SND_SOC_CS35L32=m
+CONFIG_SND_SOC_CS35L33=m
+CONFIG_SND_SOC_CS35L34=m
+CONFIG_SND_SOC_CS35L35=m
+CONFIG_SND_SOC_CS35L36=m
+CONFIG_SND_SOC_CS35L41_SPI=m
+CONFIG_SND_SOC_CS35L41_I2C=m
+CONFIG_SND_SOC_CS35L45_SPI=m
+CONFIG_SND_SOC_CS35L45_I2C=m
+CONFIG_SND_SOC_CS42L42=m
+CONFIG_SND_SOC_CS42L51_I2C=m
+CONFIG_SND_SOC_CS42L52=m
+CONFIG_SND_SOC_CS42L56=m
+CONFIG_SND_SOC_CS42L73=m
+CONFIG_SND_SOC_CS4234=m
+CONFIG_SND_SOC_CS4265=m
+CONFIG_SND_SOC_CS4270=m
+CONFIG_SND_SOC_CS4271_I2C=m
+CONFIG_SND_SOC_CS4271_SPI=m
+CONFIG_SND_SOC_CS42XX8_I2C=m
+CONFIG_SND_SOC_CS43130=m
+CONFIG_SND_SOC_CS4341=m
+CONFIG_SND_SOC_CS4349=m
+CONFIG_SND_SOC_CS53L30=m
+CONFIG_SND_SOC_CX2072X=m
+CONFIG_SND_SOC_DA7213=m
+CONFIG_SND_SOC_DMIC=m
+CONFIG_SND_SOC_ES7134=m
+CONFIG_SND_SOC_ES7241=m
+CONFIG_SND_SOC_ES8316=m
+CONFIG_SND_SOC_ES8328_I2C=m
+CONFIG_SND_SOC_ES8328_SPI=m
+CONFIG_SND_SOC_GTM601=m
+CONFIG_SND_SOC_ICS43432=m
+CONFIG_SND_SOC_INNO_RK3036=m
+CONFIG_SND_SOC_LOCHNAGAR_SC=m
+CONFIG_SND_SOC_MAX98088=m
+CONFIG_SND_SOC_MAX98357A=m
+CONFIG_SND_SOC_MAX98504=m
+CONFIG_SND_SOC_MAX9867=m
+CONFIG_SND_SOC_MAX98927=m
+CONFIG_SND_SOC_MAX98520=m
+CONFIG_SND_SOC_MAX98373_I2C=m
+CONFIG_SND_SOC_MAX98373_SDW=m
+CONFIG_SND_SOC_MAX98390=m
+CONFIG_SND_SOC_MAX98396=m
+CONFIG_SND_SOC_MAX9860=m
+CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m
+CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m
+CONFIG_SND_SOC_PCM1681=m
+CONFIG_SND_SOC_PCM1789_I2C=m
+CONFIG_SND_SOC_PCM179X_I2C=m
+CONFIG_SND_SOC_PCM179X_SPI=m
+CONFIG_SND_SOC_PCM186X_I2C=m
+CONFIG_SND_SOC_PCM186X_SPI=m
+CONFIG_SND_SOC_PCM3060_I2C=m
+CONFIG_SND_SOC_PCM3060_SPI=m
+CONFIG_SND_SOC_PCM3168A_I2C=m
+CONFIG_SND_SOC_PCM3168A_SPI=m
+CONFIG_SND_SOC_PCM5102A=m
+CONFIG_SND_SOC_PCM512x_I2C=m
+CONFIG_SND_SOC_PCM512x_SPI=m
+CONFIG_SND_SOC_RK3328=m
+CONFIG_SND_SOC_RK817=m
+CONFIG_SND_SOC_RT1308_SDW=m
+CONFIG_SND_SOC_RT1316_SDW=m
+CONFIG_SND_SOC_RT5616=m
+CONFIG_SND_SOC_RT5631=m
+CONFIG_SND_SOC_RT5640=m
+CONFIG_SND_SOC_RT5659=m
+CONFIG_SND_SOC_RT5682_SDW=m
+CONFIG_SND_SOC_RT700_SDW=m
+CONFIG_SND_SOC_RT711_SDW=m
+CONFIG_SND_SOC_RT711_SDCA_SDW=m
+CONFIG_SND_SOC_RT715_SDW=m
+CONFIG_SND_SOC_RT715_SDCA_SDW=m
+CONFIG_SND_SOC_RT9120=m
+CONFIG_SND_SOC_SDW_MOCKUP=m
+CONFIG_SND_SOC_SGTL5000=m
+CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m
+CONFIG_SND_SOC_SIMPLE_MUX=m
+CONFIG_SND_SOC_SPDIF=m
+CONFIG_SND_SOC_SSM2305=m
+CONFIG_SND_SOC_SSM2518=m
+CONFIG_SND_SOC_SSM2602_SPI=m
+CONFIG_SND_SOC_SSM2602_I2C=m
+CONFIG_SND_SOC_SSM4567=m
+CONFIG_SND_SOC_STA32X=m
+CONFIG_SND_SOC_STA350=m
+CONFIG_SND_SOC_STI_SAS=m
+CONFIG_SND_SOC_TAS2552=m
+CONFIG_SND_SOC_TAS2562=m
+CONFIG_SND_SOC_TAS2764=m
+CONFIG_SND_SOC_TAS2770=m
+CONFIG_SND_SOC_TAS5086=m
+CONFIG_SND_SOC_TAS571X=m
+CONFIG_SND_SOC_TAS5720=m
+CONFIG_SND_SOC_TAS5805M=m
+CONFIG_SND_SOC_TAS6424=m
+CONFIG_SND_SOC_TDA7419=m
+CONFIG_SND_SOC_TFA9879=m
+CONFIG_SND_SOC_TFA989X=m
+CONFIG_SND_SOC_TLV320ADC3XXX=m
+CONFIG_SND_SOC_TLV320AIC23_I2C=m
+CONFIG_SND_SOC_TLV320AIC23_SPI=m
+CONFIG_SND_SOC_TLV320AIC31XX=m
+CONFIG_SND_SOC_TLV320AIC32X4_I2C=m
+CONFIG_SND_SOC_TLV320AIC32X4_SPI=m
+CONFIG_SND_SOC_TLV320AIC3X_I2C=m
+CONFIG_SND_SOC_TLV320AIC3X_SPI=m
+CONFIG_SND_SOC_TLV320ADCX140=m
+CONFIG_SND_SOC_TS3A227E=m
+CONFIG_SND_SOC_TSCS42XX=m
+CONFIG_SND_SOC_TSCS454=m
+CONFIG_SND_SOC_UDA1334=m
+CONFIG_SND_SOC_WCD9335=m
+CONFIG_SND_SOC_WCD934X=m
+CONFIG_SND_SOC_WCD938X_SDW=m
+CONFIG_SND_SOC_WM8510=m
+CONFIG_SND_SOC_WM8523=m
+CONFIG_SND_SOC_WM8524=m
+CONFIG_SND_SOC_WM8580=m
+CONFIG_SND_SOC_WM8711=m
+CONFIG_SND_SOC_WM8728=m
+CONFIG_SND_SOC_WM8731_I2C=m
+CONFIG_SND_SOC_WM8731_SPI=m
+CONFIG_SND_SOC_WM8737=m
+CONFIG_SND_SOC_WM8741=m
+CONFIG_SND_SOC_WM8750=m
+CONFIG_SND_SOC_WM8753=m
+CONFIG_SND_SOC_WM8770=m
+CONFIG_SND_SOC_WM8776=m
+CONFIG_SND_SOC_WM8782=m
+CONFIG_SND_SOC_WM8804_I2C=m
+CONFIG_SND_SOC_WM8804_SPI=m
+CONFIG_SND_SOC_WM8903=m
+CONFIG_SND_SOC_WM8904=m
+CONFIG_SND_SOC_WM8940=m
+CONFIG_SND_SOC_WM8960=m
+CONFIG_SND_SOC_WM8962=m
+CONFIG_SND_SOC_WM8974=m
+CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_SOC_WM8985=m
+CONFIG_SND_SOC_WSA881X=m
+CONFIG_SND_SOC_ZL38060=m
+CONFIG_SND_SOC_MAX9759=m
+CONFIG_SND_SOC_MT6351=m
+CONFIG_SND_SOC_MT6358=m
+CONFIG_SND_SOC_MT6660=m
+CONFIG_SND_SOC_NAU8315=m
+CONFIG_SND_SOC_NAU8540=m
+CONFIG_SND_SOC_NAU8810=m
+CONFIG_SND_SOC_NAU8821=m
+CONFIG_SND_SOC_NAU8822=m
+CONFIG_SND_SOC_NAU8824=m
+CONFIG_SND_SOC_TPA6130A2=m
+CONFIG_SND_SOC_LPASS_WSA_MACRO=m
+CONFIG_SND_SOC_LPASS_VA_MACRO=m
+CONFIG_SND_SOC_LPASS_RX_MACRO=m
+CONFIG_SND_SOC_LPASS_TX_MACRO=m
+CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_AUDIO_GRAPH_CARD=m
+CONFIG_SND_AUDIO_GRAPH_CARD2=m
+CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE=m
+CONFIG_SND_TEST_COMPONENT=m
+CONFIG_SND_VIRTIO=m
+CONFIG_HID=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=m
+CONFIG_HID_A4TECH=m
+CONFIG_HID_ACCUTOUCH=m
+CONFIG_HID_ACRUX=m
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=m
+CONFIG_HID_APPLEIR=m
+CONFIG_HID_ASUS=m
+CONFIG_HID_AUREAL=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_BETOP_FF=m
+CONFIG_HID_BIGBEN_FF=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CORSAIR=m
+CONFIG_HID_COUGAR=m
+CONFIG_HID_MACALLY=m
+CONFIG_HID_PRODIKEYS=m
+CONFIG_HID_CMEDIA=m
+CONFIG_HID_CP2112=m
+CONFIG_HID_CREATIVE_SB0540=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=m
+CONFIG_HID_ELAN=m
+CONFIG_HID_ELECOM=m
+CONFIG_HID_ELO=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_FT260=m
+CONFIG_HID_GEMBIRD=m
+CONFIG_HID_GFRM=m
+CONFIG_HID_GLORIOUS=m
+CONFIG_HID_HOLTEK=m
+CONFIG_HOLTEK_FF=y
+CONFIG_HID_VIVALDI=m
+CONFIG_HID_GT683R=m
+CONFIG_HID_KEYTOUCH=m
+CONFIG_HID_KYE=m
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_VIEWSONIC=m
+CONFIG_HID_XIAOMI=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_ICADE=m
+CONFIG_HID_ITE=m
+CONFIG_HID_JABRA=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LENOVO=m
+CONFIG_HID_LETSKETCH=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MALTRON=m
+CONFIG_HID_MAYFLASH=m
+CONFIG_HID_MEGAWORLD_FF=m
+CONFIG_HID_REDRAGON=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NINTENDO=m
+CONFIG_NINTENDO_FF=y
+CONFIG_HID_NTI=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PENMOUNT=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PICOLCD_FB=y
+CONFIG_HID_PICOLCD_BACKLIGHT=y
+CONFIG_HID_PICOLCD_LCD=y
+CONFIG_HID_PICOLCD_LEDS=y
+CONFIG_HID_PICOLCD_CIR=y
+CONFIG_HID_PLANTRONICS=m
+CONFIG_HID_PLAYSTATION=m
+CONFIG_PLAYSTATION_FF=y
+CONFIG_HID_RAZER=m
+CONFIG_HID_PRIMAX=m
+CONFIG_HID_RETRODE=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_SAITEK=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SEMITEK=m
+CONFIG_HID_SIGMAMICRO=m
+CONFIG_HID_SONY=m
+CONFIG_SONY_FF=y
+CONFIG_HID_SPEEDLINK=m
+CONFIG_HID_STEAM=m
+CONFIG_HID_STEELSERIES=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_RMI=m
+CONFIG_HID_GREENASIA=m
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THINGM=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_UDRAW_PS3=m
+CONFIG_HID_U2FZERO=m
+CONFIG_HID_WACOM=m
+CONFIG_HID_WIIMOTE=m
+CONFIG_HID_XINMO=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_ZEROPLUS_FF=y
+CONFIG_HID_ZYDACRON=m
+CONFIG_HID_SENSOR_HUB=m
+CONFIG_HID_SENSOR_CUSTOM_SENSOR=m
+CONFIG_HID_ALPS=m
+CONFIG_HID_MCP2221=m
+CONFIG_USB_HID=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_I2C_HID_OF=m
+CONFIG_I2C_HID_OF_GOODIX=m
+CONFIG_USB_LED_TRIG=y
+CONFIG_USB_CONN_GPIO=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_LEDS_TRIGGER_USBPORT=m
+CONFIG_USB_MON=m
+CONFIG_USB_C67X00_HCD=m
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DBGCAP=y
+CONFIG_USB_XHCI_PCI_RENESAS=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_FSL=m
+CONFIG_USB_OXU210HP_HCD=m
+CONFIG_USB_ISP116X_HCD=m
+CONFIG_USB_FOTG210_HCD=m
+CONFIG_USB_MAX3421_HCD=m
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_U132_HCD=m
+CONFIG_USB_SL811_HCD=m
+CONFIG_USB_SL811_HCD_ISO=y
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_HCD_BCMA=m
+CONFIG_USB_HCD_SSB=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_TMC=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_REALTEK=m
+CONFIG_USB_STORAGE_DATAFAB=m
+CONFIG_USB_STORAGE_FREECOM=m
+CONFIG_USB_STORAGE_ISD200=m
+CONFIG_USB_STORAGE_USBAT=m
+CONFIG_USB_STORAGE_SDDR09=m
+CONFIG_USB_STORAGE_SDDR55=m
+CONFIG_USB_STORAGE_JUMPSHOT=m
+CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
+CONFIG_USB_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USBIP_CORE=m
+CONFIG_USBIP_VHCI_HCD=m
+CONFIG_USBIP_HOST=m
+CONFIG_USBIP_VUDC=m
+CONFIG_USB_CDNS_SUPPORT=m
+CONFIG_USB_CDNS3=m
+CONFIG_USB_CDNS3_GADGET=y
+CONFIG_USB_CDNS3_HOST=y
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_MUSB_POLARFIRE_SOC=m
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_USB_DWC3=m
+CONFIG_USB_DWC3_ULPI=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_PCI=m
+CONFIG_USB_CHIPIDEA=m
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_ISP1760=m
+CONFIG_USB_USS720=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_F8153X=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7715_PARPORT=y
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MXUPORT=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_UPD78F0730=m
+CONFIG_USB_SERIAL_XR=m
+CONFIG_USB_SERIAL_DEBUG=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_APPLE_MFI_FASTCHARGE=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_TEST=m
+CONFIG_USB_EHSET_TEST_FIXTURE=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_YUREX=m
+CONFIG_USB_HUB_USB251XB=m
+CONFIG_USB_HSIC_USB3503=m
+CONFIG_USB_HSIC_USB4604=m
+CONFIG_USB_LINK_LAYER_TEST=m
+CONFIG_USB_CHAOSKEY=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GPIO_VBUS=m
+CONFIG_TAHVO_USB=m
+CONFIG_TAHVO_USB_HOST_BY_DEFAULT=y
+CONFIG_USB_ISP1301=m
+CONFIG_USB_GADGET=m
+CONFIG_U_SERIAL_CONSOLE=y
+CONFIG_USB_FOTG210_UDC=m
+CONFIG_USB_GR_UDC=m
+CONFIG_USB_R8A66597=m
+CONFIG_USB_PXA27X=m
+CONFIG_USB_MV_UDC=m
+CONFIG_USB_MV_U3D=m
+CONFIG_USB_SNP_UDC_PLAT=m
+CONFIG_USB_BDC_UDC=m
+CONFIG_USB_AMD5536UDC=m
+CONFIG_USB_NET2272=m
+CONFIG_USB_NET2272_DMA=y
+CONFIG_USB_NET2280=m
+CONFIG_USB_GOKU=m
+CONFIG_USB_EG20T=m
+CONFIG_USB_GADGET_XILINX=m
+CONFIG_USB_MAX3420_UDC=m
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_PHONET=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_CONFIGFS_F_TCM=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_GADGET_UAC1=y
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_EEM=y
+CONFIG_USB_G_NCM=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FUNCTIONFS=m
+CONFIG_USB_FUNCTIONFS_ETH=y
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+CONFIG_USB_FUNCTIONFS_GENERIC=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_GADGET_TARGET=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_NOKIA=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_DBGP=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_USB_RAW_GADGET=m
+CONFIG_TYPEC=m
+CONFIG_TYPEC_TCPM=m
+CONFIG_TYPEC_TCPCI=m
+CONFIG_TYPEC_RT1711H=m
+CONFIG_TYPEC_MT6360=m
+CONFIG_TYPEC_TCPCI_MAXIM=m
+CONFIG_TYPEC_FUSB302=m
+CONFIG_TYPEC_UCSI=m
+CONFIG_UCSI_CCG=m
+CONFIG_TYPEC_TPS6598X=m
+CONFIG_TYPEC_RT1719=m
+CONFIG_TYPEC_HD3SS3220=m
+CONFIG_TYPEC_STUSB160X=m
+CONFIG_TYPEC_WUSB3801=m
+CONFIG_TYPEC_MUX_FSA4480=m
+CONFIG_TYPEC_MUX_PI3USB30532=m
+CONFIG_TYPEC_DP_ALTMODE=m
+CONFIG_TYPEC_NVIDIA_ALTMODE=m
+CONFIG_MMC=y
+CONFIG_PWRSEQ_EMMC=m
+CONFIG_PWRSEQ_SD8787=m
+CONFIG_PWRSEQ_SIMPLE=m
+CONFIG_SDIO_UART=m
+CONFIG_MMC_CRYPTO=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ARASAN=m
+CONFIG_MMC_SDHCI_OF_AT91=m
+CONFIG_MMC_SDHCI_OF_DWCMSHC=m
+CONFIG_MMC_SDHCI_CADENCE=m
+CONFIG_MMC_SDHCI_F_SDH30=m
+CONFIG_MMC_SDHCI_MILBEAUT=m
+CONFIG_MMC_SDHCI_SOPHGO=y
+CONFIG_MMC_ALCOR=m
+CONFIG_MMC_TIFM_SD=m
+CONFIG_MMC_SPI=y
+CONFIG_MMC_CB710=m
+CONFIG_MMC_VIA_SDMMC=m
+CONFIG_MMC_DW=m
+CONFIG_MMC_DW_BLUEFIELD=m
+CONFIG_MMC_DW_EXYNOS=m
+CONFIG_MMC_DW_HI3798CV200=m
+CONFIG_MMC_DW_K3=m
+CONFIG_MMC_DW_PCI=m
+CONFIG_MMC_VUB300=m
+CONFIG_MMC_USHC=m
+CONFIG_MMC_USDHI6ROL0=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
+CONFIG_MMC_HSQ=m
+CONFIG_MMC_TOSHIBA_PCI=m
+CONFIG_MMC_MTK=m
+CONFIG_MMC_SDHCI_XENON=m
+CONFIG_MMC_SDHCI_OMAP=m
+CONFIG_MMC_SDHCI_AM654=m
+CONFIG_MMC_LITEX=m
+CONFIG_SCSI_UFSHCD=m
+CONFIG_SCSI_UFS_BSG=y
+CONFIG_SCSI_UFS_CRYPTO=y
+CONFIG_SCSI_UFS_HPB=y
+CONFIG_SCSI_UFSHCD_PCI=m
+CONFIG_SCSI_UFS_DWC_TC_PCI=m
+CONFIG_SCSI_UFSHCD_PLATFORM=m
+CONFIG_SCSI_UFS_CDNS_PLATFORM=m
+CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m
+CONFIG_MEMSTICK=m
+CONFIG_MSPRO_BLOCK=m
+CONFIG_MS_BLOCK=m
+CONFIG_MEMSTICK_TIFM_MS=m
+CONFIG_MEMSTICK_JMICRON_38X=m
+CONFIG_MEMSTICK_R592=m
+CONFIG_MEMSTICK_REALTEK_PCI=m
+CONFIG_MEMSTICK_REALTEK_USB=m
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+CONFIG_LEDS_CLASS_MULTICOLOR=m
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
+CONFIG_LEDS_88PM860X=m
+CONFIG_LEDS_AN30259A=m
+CONFIG_LEDS_AW2013=m
+CONFIG_LEDS_BCM6328=m
+CONFIG_LEDS_BCM6358=m
+CONFIG_LEDS_CPCAP=m
+CONFIG_LEDS_CR0014114=m
+CONFIG_LEDS_EL15203000=m
+CONFIG_LEDS_LM3530=m
+CONFIG_LEDS_LM3532=m
+CONFIG_LEDS_LM3533=m
+CONFIG_LEDS_LM3642=m
+CONFIG_LEDS_LM3692X=m
+CONFIG_LEDS_MT6323=m
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_LP3952=m
+CONFIG_LEDS_LP50XX=m
+CONFIG_LEDS_LP55XX_COMMON=m
+CONFIG_LEDS_LP5521=m
+CONFIG_LEDS_LP5523=m
+CONFIG_LEDS_LP5562=m
+CONFIG_LEDS_LP8501=m
+CONFIG_LEDS_LP8788=m
+CONFIG_LEDS_LP8860=m
+CONFIG_LEDS_PCA955X=m
+CONFIG_LEDS_PCA955X_GPIO=y
+CONFIG_LEDS_PCA963X=m
+CONFIG_LEDS_WM831X_STATUS=m
+CONFIG_LEDS_WM8350=m
+CONFIG_LEDS_DA903X=m
+CONFIG_LEDS_DA9052=m
+CONFIG_LEDS_DAC124S085=m
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+CONFIG_LEDS_BD2802=m
+CONFIG_LEDS_LT3593=m
+CONFIG_LEDS_ADP5520=m
+CONFIG_LEDS_MC13783=m
+CONFIG_LEDS_TCA6507=m
+CONFIG_LEDS_TLC591XX=m
+CONFIG_LEDS_MAX77650=m
+CONFIG_LEDS_MAX8997=m
+CONFIG_LEDS_LM355x=m
+CONFIG_LEDS_MENF21BMC=m
+CONFIG_LEDS_IS31FL319X=m
+CONFIG_LEDS_IS31FL32XX=m
+CONFIG_LEDS_BLINKM=m
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_MLXREG=m
+CONFIG_LEDS_USER=m
+CONFIG_LEDS_SPI_BYTE=m
+CONFIG_LEDS_TI_LMU_COMMON=m
+CONFIG_LEDS_LM3697=m
+CONFIG_LEDS_LM36274=m
+CONFIG_LEDS_AAT1290=m
+CONFIG_LEDS_AS3645A=m
+CONFIG_LEDS_KTD2692=m
+CONFIG_LEDS_LM3601X=m
+CONFIG_LEDS_MAX77693=m
+CONFIG_LEDS_MT6360=m
+CONFIG_LEDS_RT4505=m
+CONFIG_LEDS_RT8515=m
+CONFIG_LEDS_SGM3140=m
+CONFIG_LEDS_PWM_MULTICOLOR=m
+CONFIG_LEDS_QCOM_LPG=m
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_MTD=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_ACTIVITY=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+CONFIG_LEDS_TRIGGER_PATTERN=m
+CONFIG_LEDS_TRIGGER_TTY=m
+CONFIG_INFINIBAND=m
+CONFIG_INFINIBAND_USER_MAD=m
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_BNXT_RE=m
+CONFIG_INFINIBAND_CXGB4=m
+CONFIG_INFINIBAND_EFA=m
+CONFIG_INFINIBAND_IRDMA=m
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_MLX5_INFINIBAND=m
+CONFIG_INFINIBAND_MTHCA=m
+# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
+CONFIG_INFINIBAND_OCRDMA=m
+CONFIG_INFINIBAND_QEDR=m
+CONFIG_INFINIBAND_VMWARE_PVRDMA=m
+CONFIG_INFINIBAND_IPOIB=m
+CONFIG_INFINIBAND_IPOIB_CM=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+CONFIG_INFINIBAND_SRP=m
+CONFIG_INFINIBAND_SRPT=m
+CONFIG_INFINIBAND_ISER=m
+CONFIG_INFINIBAND_ISERT=m
+CONFIG_INFINIBAND_RTRS_CLIENT=m
+CONFIG_INFINIBAND_RTRS_SERVER=m
+CONFIG_EDAC=y
+# CONFIG_EDAC_LEGACY_SYSFS is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_88PM860X=m
+CONFIG_RTC_DRV_88PM80X=m
+CONFIG_RTC_DRV_ABB5ZES3=m
+CONFIG_RTC_DRV_ABEOZ9=m
+CONFIG_RTC_DRV_ABX80X=m
+CONFIG_RTC_DRV_AS3722=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_DS1307_CENTURY=y
+CONFIG_RTC_DRV_DS1374=m
+CONFIG_RTC_DRV_DS1374_WDT=y
+CONFIG_RTC_DRV_DS1672=m
+CONFIG_RTC_DRV_HYM8563=m
+CONFIG_RTC_DRV_LP8788=m
+CONFIG_RTC_DRV_MAX6900=m
+CONFIG_RTC_DRV_MAX8907=m
+CONFIG_RTC_DRV_MAX8925=m
+CONFIG_RTC_DRV_MAX8998=m
+CONFIG_RTC_DRV_MAX8997=m
+CONFIG_RTC_DRV_MAX77686=m
+CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_RS5C372=m
+CONFIG_RTC_DRV_ISL1208=m
+CONFIG_RTC_DRV_ISL12022=m
+CONFIG_RTC_DRV_ISL12026=m
+CONFIG_RTC_DRV_X1205=m
+CONFIG_RTC_DRV_PCF8523=m
+CONFIG_RTC_DRV_PCF85063=m
+CONFIG_RTC_DRV_PCF85363=m
+CONFIG_RTC_DRV_PCF8563=m
+CONFIG_RTC_DRV_PCF8583=m
+CONFIG_RTC_DRV_M41T80=m
+CONFIG_RTC_DRV_M41T80_WDT=y
+CONFIG_RTC_DRV_BD70528=m
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_RTC_DRV_PALMAS=m
+CONFIG_RTC_DRV_TPS6586X=m
+CONFIG_RTC_DRV_TPS65910=m
+CONFIG_RTC_DRV_RC5T583=m
+CONFIG_RTC_DRV_RC5T619=m
+CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_FM3130=m
+CONFIG_RTC_DRV_RX8010=m
+CONFIG_RTC_DRV_RX8581=m
+CONFIG_RTC_DRV_RX8025=m
+CONFIG_RTC_DRV_EM3027=m
+CONFIG_RTC_DRV_RV3028=m
+CONFIG_RTC_DRV_RV3032=m
+CONFIG_RTC_DRV_RV8803=m
+CONFIG_RTC_DRV_S5M=m
+CONFIG_RTC_DRV_SD3078=m
+CONFIG_RTC_DRV_M41T93=m
+CONFIG_RTC_DRV_M41T94=m
+CONFIG_RTC_DRV_DS1302=m
+CONFIG_RTC_DRV_DS1305=m
+CONFIG_RTC_DRV_DS1343=m
+CONFIG_RTC_DRV_DS1347=m
+CONFIG_RTC_DRV_DS1390=m
+CONFIG_RTC_DRV_MAX6916=m
+CONFIG_RTC_DRV_R9701=m
+CONFIG_RTC_DRV_RX4581=m
+CONFIG_RTC_DRV_RS5C348=m
+CONFIG_RTC_DRV_MAX6902=m
+CONFIG_RTC_DRV_PCF2123=m
+CONFIG_RTC_DRV_MCP795=m
+CONFIG_RTC_DRV_DS3232=m
+CONFIG_RTC_DRV_PCF2127=m
+CONFIG_RTC_DRV_RV3029C2=m
+CONFIG_RTC_DRV_RX6110=m
+CONFIG_RTC_DRV_DS1286=m
+CONFIG_RTC_DRV_DS1511=m
+CONFIG_RTC_DRV_DS1553=m
+CONFIG_RTC_DRV_DS1685_FAMILY=m
+CONFIG_RTC_DRV_DS1742=m
+CONFIG_RTC_DRV_DS2404=m
+CONFIG_RTC_DRV_DA9052=m
+CONFIG_RTC_DRV_DA9055=m
+CONFIG_RTC_DRV_DA9063=m
+CONFIG_RTC_DRV_EFI=m
+CONFIG_RTC_DRV_STK17TA8=m
+CONFIG_RTC_DRV_M48T86=m
+CONFIG_RTC_DRV_M48T35=m
+CONFIG_RTC_DRV_M48T59=m
+CONFIG_RTC_DRV_MSM6242=m
+CONFIG_RTC_DRV_BQ4802=m
+CONFIG_RTC_DRV_RP5C01=m
+CONFIG_RTC_DRV_V3020=m
+CONFIG_RTC_DRV_WM831X=m
+CONFIG_RTC_DRV_WM8350=m
+CONFIG_RTC_DRV_PCF50633=m
+CONFIG_RTC_DRV_ZYNQMP=m
+CONFIG_RTC_DRV_NTXEC=m
+CONFIG_RTC_DRV_CADENCE=m
+CONFIG_RTC_DRV_FTRTC010=m
+CONFIG_RTC_DRV_PCAP=m
+CONFIG_RTC_DRV_MC13XXX=m
+CONFIG_RTC_DRV_MT6397=m
+CONFIG_RTC_DRV_R7301=m
+CONFIG_RTC_DRV_CPCAP=m
+CONFIG_RTC_DRV_HID_SENSOR_TIME=m
+CONFIG_RTC_DRV_ASTBMC=m
+CONFIG_DMADEVICES=y
+CONFIG_ALTERA_MSGDMA=m
+CONFIG_DW_AXI_DMAC=m
+CONFIG_FSL_EDMA=m
+CONFIG_INTEL_IDMA64=m
+CONFIG_PLX_DMA=m
+CONFIG_XILINX_ZYNQMP_DPDMA=m
+CONFIG_QCOM_HIDMA_MGMT=m
+CONFIG_QCOM_HIDMA=m
+CONFIG_DW_DMAC=m
+CONFIG_DW_DMAC_PCI=m
+CONFIG_DW_EDMA_PCIE=m
+CONFIG_SF_PDMA=m
+CONFIG_ASYNC_TX_DMA=y
+CONFIG_SW_SYNC=y
+CONFIG_UDMABUF=y
+CONFIG_DMABUF_HEAPS=y
+CONFIG_DMABUF_HEAPS_SYSTEM=y
+CONFIG_DMABUF_HEAPS_CMA=y
+CONFIG_HD44780=m
+CONFIG_KS0108=m
+CONFIG_IMG_ASCII_LCD=m
+CONFIG_HT16K33=m
+CONFIG_LCD2S=m
+CONFIG_PANEL=m
+CONFIG_UIO_CIF=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_DMEM_GENIRQ=m
+CONFIG_UIO_AEC=m
+CONFIG_UIO_SERCOS3=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_UIO_NETX=m
+CONFIG_UIO_PRUSS=m
+CONFIG_UIO_MF624=m
+CONFIG_UIO_DFL=m
+CONFIG_VFIO=m
+CONFIG_VFIO_NOIOMMU=y
+CONFIG_VFIO_PCI=m
+CONFIG_MLX5_VFIO_PCI=m
+CONFIG_VFIO_MDEV=m
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_VDPA=m
+CONFIG_VIRTIO_PMEM=m
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VDPA=m
+CONFIG_VDPA_SIM=m
+CONFIG_VDPA_SIM_NET=m
+CONFIG_VDPA_SIM_BLOCK=m
+CONFIG_VDPA_USER=m
+CONFIG_IFCVF=m
+CONFIG_MLX5_VDPA_NET=m
+CONFIG_VP_VDPA=m
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_SCSI=m
+CONFIG_VHOST_VSOCK=m
+CONFIG_VHOST_VDPA=m
+CONFIG_COMEDI=m
+CONFIG_COMEDI_MISC_DRIVERS=y
+CONFIG_COMEDI_BOND=m
+CONFIG_COMEDI_TEST=m
+CONFIG_COMEDI_PARPORT=m
+CONFIG_COMEDI_ISA_DRIVERS=y
+CONFIG_COMEDI_PCL711=m
+CONFIG_COMEDI_PCL724=m
+CONFIG_COMEDI_PCL726=m
+CONFIG_COMEDI_PCL730=m
+CONFIG_COMEDI_PCL812=m
+CONFIG_COMEDI_PCL816=m
+CONFIG_COMEDI_PCL818=m
+CONFIG_COMEDI_PCM3724=m
+CONFIG_COMEDI_AMPLC_DIO200_ISA=m
+CONFIG_COMEDI_AMPLC_PC236_ISA=m
+CONFIG_COMEDI_AMPLC_PC263_ISA=m
+CONFIG_COMEDI_RTI800=m
+CONFIG_COMEDI_RTI802=m
+CONFIG_COMEDI_DAC02=m
+CONFIG_COMEDI_DAS16M1=m
+CONFIG_COMEDI_DAS08_ISA=m
+CONFIG_COMEDI_DAS16=m
+CONFIG_COMEDI_DAS800=m
+CONFIG_COMEDI_DAS1800=m
+CONFIG_COMEDI_DAS6402=m
+CONFIG_COMEDI_DT2801=m
+CONFIG_COMEDI_DT2811=m
+CONFIG_COMEDI_DT2814=m
+CONFIG_COMEDI_DT2815=m
+CONFIG_COMEDI_DT2817=m
+CONFIG_COMEDI_DT282X=m
+CONFIG_COMEDI_DMM32AT=m
+CONFIG_COMEDI_FL512=m
+CONFIG_COMEDI_AIO_AIO12_8=m
+CONFIG_COMEDI_AIO_IIRO_16=m
+CONFIG_COMEDI_II_PCI20KC=m
+CONFIG_COMEDI_C6XDIGIO=m
+CONFIG_COMEDI_MPC624=m
+CONFIG_COMEDI_ADQ12B=m
+CONFIG_COMEDI_NI_AT_A2150=m
+CONFIG_COMEDI_NI_AT_AO=m
+CONFIG_COMEDI_NI_ATMIO=m
+CONFIG_COMEDI_NI_ATMIO16D=m
+CONFIG_COMEDI_NI_LABPC_ISA=m
+CONFIG_COMEDI_PCMAD=m
+CONFIG_COMEDI_PCMDA12=m
+CONFIG_COMEDI_PCMMIO=m
+CONFIG_COMEDI_PCMUIO=m
+CONFIG_COMEDI_MULTIQ3=m
+CONFIG_COMEDI_S526=m
+CONFIG_COMEDI_PCI_DRIVERS=m
+CONFIG_COMEDI_8255_PCI=m
+CONFIG_COMEDI_ADDI_APCI_1032=m
+CONFIG_COMEDI_ADDI_APCI_1500=m
+CONFIG_COMEDI_ADDI_APCI_1516=m
+CONFIG_COMEDI_ADDI_APCI_1564=m
+CONFIG_COMEDI_ADDI_APCI_16XX=m
+CONFIG_COMEDI_ADDI_APCI_2032=m
+CONFIG_COMEDI_ADDI_APCI_2200=m
+CONFIG_COMEDI_ADDI_APCI_3120=m
+CONFIG_COMEDI_ADDI_APCI_3501=m
+CONFIG_COMEDI_ADDI_APCI_3XXX=m
+CONFIG_COMEDI_ADL_PCI6208=m
+CONFIG_COMEDI_ADL_PCI7X3X=m
+CONFIG_COMEDI_ADL_PCI8164=m
+CONFIG_COMEDI_ADL_PCI9111=m
+CONFIG_COMEDI_ADL_PCI9118=m
+CONFIG_COMEDI_ADV_PCI1710=m
+CONFIG_COMEDI_ADV_PCI1720=m
+CONFIG_COMEDI_ADV_PCI1723=m
+CONFIG_COMEDI_ADV_PCI1724=m
+CONFIG_COMEDI_ADV_PCI1760=m
+CONFIG_COMEDI_ADV_PCI_DIO=m
+CONFIG_COMEDI_AMPLC_DIO200_PCI=m
+CONFIG_COMEDI_AMPLC_PC236_PCI=m
+CONFIG_COMEDI_AMPLC_PC263_PCI=m
+CONFIG_COMEDI_AMPLC_PCI224=m
+CONFIG_COMEDI_AMPLC_PCI230=m
+CONFIG_COMEDI_CONTEC_PCI_DIO=m
+CONFIG_COMEDI_DAS08_PCI=m
+CONFIG_COMEDI_DT3000=m
+CONFIG_COMEDI_DYNA_PCI10XX=m
+CONFIG_COMEDI_GSC_HPDI=m
+CONFIG_COMEDI_MF6X4=m
+CONFIG_COMEDI_ICP_MULTI=m
+CONFIG_COMEDI_DAQBOARD2000=m
+CONFIG_COMEDI_JR3_PCI=m
+CONFIG_COMEDI_KE_COUNTER=m
+CONFIG_COMEDI_CB_PCIDAS64=m
+CONFIG_COMEDI_CB_PCIDAS=m
+CONFIG_COMEDI_CB_PCIDDA=m
+CONFIG_COMEDI_CB_PCIMDAS=m
+CONFIG_COMEDI_CB_PCIMDDA=m
+CONFIG_COMEDI_ME4000=m
+CONFIG_COMEDI_ME_DAQ=m
+CONFIG_COMEDI_NI_6527=m
+CONFIG_COMEDI_NI_65XX=m
+CONFIG_COMEDI_NI_660X=m
+CONFIG_COMEDI_NI_670X=m
+CONFIG_COMEDI_NI_LABPC_PCI=m
+CONFIG_COMEDI_NI_PCIDIO=m
+CONFIG_COMEDI_NI_PCIMIO=m
+CONFIG_COMEDI_RTD520=m
+CONFIG_COMEDI_S626=m
+CONFIG_COMEDI_USB_DRIVERS=m
+CONFIG_COMEDI_DT9812=m
+CONFIG_COMEDI_NI_USB6501=m
+CONFIG_COMEDI_USBDUX=m
+CONFIG_COMEDI_USBDUXFAST=m
+CONFIG_COMEDI_USBDUXSIGMA=m
+CONFIG_COMEDI_VMK80XX=m
+CONFIG_COMEDI_8255_SA=m
+CONFIG_COMEDI_TESTS=m
+CONFIG_COMEDI_TESTS_EXAMPLE=m
+CONFIG_COMEDI_TESTS_NI_ROUTES=m
+CONFIG_STAGING=y
+CONFIG_PRISM2_USB=m
+CONFIG_RTL8192U=m
+CONFIG_RTLLIB=m
+CONFIG_RTL8192E=m
+CONFIG_RTL8723BS=m
+CONFIG_R8712U=m
+CONFIG_R8188EU=m
+CONFIG_RTS5208=m
+CONFIG_VT6655=m
+CONFIG_VT6656=m
+CONFIG_ADIS16203=m
+CONFIG_ADIS16240=m
+CONFIG_AD7816=m
+CONFIG_ADT7316=m
+CONFIG_ADT7316_I2C=m
+CONFIG_AD9832=m
+CONFIG_AD9834=m
+CONFIG_AD5933=m
+CONFIG_ADE7854=m
+CONFIG_AD2S1210=m
+CONFIG_FB_SM750=m
+CONFIG_STAGING_MEDIA=y
+CONFIG_VIDEO_MAX96712=m
+CONFIG_LTE_GDM724X=m
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SEPS525=m
+CONFIG_FB_TFT_SH1106=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1305=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1611=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_MOST_COMPONENTS=m
+CONFIG_MOST_NET=m
+CONFIG_MOST_VIDEO=m
+CONFIG_MOST_DIM2=m
+CONFIG_MOST_I2C=m
+CONFIG_KS7010=m
+CONFIG_PI433=m
+CONFIG_XIL_AXIS_FIFO=m
+CONFIG_FIELDBUS_DEV=m
+CONFIG_HMS_ANYBUSS_BUS=m
+CONFIG_ARCX_ANYBUS_CONTROLLER=m
+CONFIG_HMS_PROFINET=m
+CONFIG_QLGE=m
+CONFIG_VME_BUS=y
+CONFIG_VME_TSI148=m
+CONFIG_VME_FAKE=m
+CONFIG_VME_USER=m
+CONFIG_GOLDFISH_PIPE=m
+CONFIG_COMMON_CLK_WM831X=m
+CONFIG_LMK04832=m
+CONFIG_COMMON_CLK_MAX77686=m
+CONFIG_COMMON_CLK_MAX9485=m
+CONFIG_COMMON_CLK_RK808=m
+CONFIG_COMMON_CLK_SI5341=m
+CONFIG_COMMON_CLK_SI5351=m
+CONFIG_COMMON_CLK_SI514=m
+CONFIG_COMMON_CLK_SI544=m
+CONFIG_COMMON_CLK_SI570=m
+CONFIG_COMMON_CLK_CDCE706=m
+CONFIG_COMMON_CLK_CDCE925=m
+CONFIG_COMMON_CLK_CS2000_CP=m
+CONFIG_COMMON_CLK_S2MPS11=m
+CONFIG_CLK_TWL6040=m
+CONFIG_COMMON_CLK_AXI_CLKGEN=m
+CONFIG_COMMON_CLK_LOCHNAGAR=m
+CONFIG_COMMON_CLK_PALMAS=m
+CONFIG_COMMON_CLK_PWM=m
+CONFIG_COMMON_CLK_RS9_PCIE=m
+CONFIG_COMMON_CLK_VC5=m
+CONFIG_COMMON_CLK_BD718XX=m
+CONFIG_COMMON_CLK_FIXED_MMIO=y
+CONFIG_XILINX_VCU=m
+CONFIG_HWSPINLOCK=y
+CONFIG_MICROCHIP_PIT64B=y
+CONFIG_MAILBOX=y
+CONFIG_PLATFORM_MHU=m
+CONFIG_ALTERA_MBOX=m
+CONFIG_MAILBOX_TEST=m
+CONFIG_POLARFIRE_SOC_MAILBOX=m
+CONFIG_RPMSG_CHAR=m
+CONFIG_RPMSG_CTRL=m
+CONFIG_RPMSG_QCOM_GLINK_RPM=m
+CONFIG_RPMSG_VIRTIO=m
+CONFIG_SOUNDWIRE=m
+CONFIG_SOUNDWIRE_QCOM=m
+CONFIG_LITEX_SOC_CONTROLLER=m
+CONFIG_POLARFIRE_SOC_SYS_CTRL=m
+CONFIG_SOC_TI=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_DEVFREQ_GOV_PASSIVE=y
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_EXTCON_ADC_JACK=m
+CONFIG_EXTCON_FSA9480=m
+CONFIG_EXTCON_GPIO=m
+CONFIG_EXTCON_MAX14577=m
+CONFIG_EXTCON_MAX3355=m
+CONFIG_EXTCON_MAX77693=m
+CONFIG_EXTCON_MAX77843=m
+CONFIG_EXTCON_MAX8997=m
+CONFIG_EXTCON_PALMAS=m
+CONFIG_EXTCON_PTN5150=m
+CONFIG_EXTCON_RT8973A=m
+CONFIG_EXTCON_SM5502=m
+CONFIG_EXTCON_USB_GPIO=m
+CONFIG_EXTCON_USBC_TUSB320=m
+CONFIG_MEMORY=y
+CONFIG_FPGA_DFL_EMIF=m
+CONFIG_IIO=m
+CONFIG_IIO_SW_DEVICE=m
+CONFIG_IIO_SW_TRIGGER=m
+CONFIG_ADIS16201=m
+CONFIG_ADIS16209=m
+CONFIG_ADXL313_I2C=m
+CONFIG_ADXL313_SPI=m
+CONFIG_ADXL355_I2C=m
+CONFIG_ADXL355_SPI=m
+CONFIG_ADXL367_SPI=m
+CONFIG_ADXL367_I2C=m
+CONFIG_ADXL372_SPI=m
+CONFIG_ADXL372_I2C=m
+CONFIG_BMA220=m
+CONFIG_BMA400=m
+CONFIG_BMC150_ACCEL=m
+CONFIG_BMI088_ACCEL=m
+CONFIG_DA280=m
+CONFIG_DA311=m
+CONFIG_DMARD06=m
+CONFIG_DMARD09=m
+CONFIG_DMARD10=m
+CONFIG_FXLS8962AF_I2C=m
+CONFIG_FXLS8962AF_SPI=m
+CONFIG_HID_SENSOR_ACCEL_3D=m
+CONFIG_KXSD9=m
+CONFIG_KXCJK1013=m
+CONFIG_MC3230=m
+CONFIG_MMA7455_I2C=m
+CONFIG_MMA7455_SPI=m
+CONFIG_MMA7660=m
+CONFIG_MMA8452=m
+CONFIG_MMA9551=m
+CONFIG_MMA9553=m
+CONFIG_MXC4005=m
+CONFIG_MXC6255=m
+CONFIG_SCA3000=m
+CONFIG_SCA3300=m
+CONFIG_STK8312=m
+CONFIG_STK8BA50=m
+CONFIG_AD7091R5=m
+CONFIG_AD7124=m
+CONFIG_AD7192=m
+CONFIG_AD7266=m
+CONFIG_AD7280=m
+CONFIG_AD7291=m
+CONFIG_AD7292=m
+CONFIG_AD7298=m
+CONFIG_AD7476=m
+CONFIG_AD7606_IFACE_PARALLEL=m
+CONFIG_AD7606_IFACE_SPI=m
+CONFIG_AD7766=m
+CONFIG_AD7768_1=m
+CONFIG_AD7780=m
+CONFIG_AD7791=m
+CONFIG_AD7793=m
+CONFIG_AD7887=m
+CONFIG_AD7923=m
+CONFIG_AD7949=m
+CONFIG_AD799X=m
+CONFIG_AD9467=m
+CONFIG_ADI_AXI_ADC=m
+CONFIG_AXP20X_ADC=m
+CONFIG_AXP288_ADC=m
+CONFIG_CC10001_ADC=m
+CONFIG_CPCAP_ADC=m
+CONFIG_DA9150_GPADC=m
+CONFIG_DLN2_ADC=m
+CONFIG_ENVELOPE_DETECTOR=m
+CONFIG_HI8435=m
+CONFIG_HX711=m
+CONFIG_INA2XX_ADC=m
+CONFIG_LP8788_ADC=m
+CONFIG_LTC2471=m
+CONFIG_LTC2485=m
+CONFIG_LTC2496=m
+CONFIG_LTC2497=m
+CONFIG_MAX1027=m
+CONFIG_MAX11100=m
+CONFIG_MAX1118=m
+CONFIG_MAX1241=m
+CONFIG_MAX1363=m
+CONFIG_MAX9611=m
+CONFIG_MCP320X=m
+CONFIG_MCP3422=m
+CONFIG_MCP3911=m
+CONFIG_MEDIATEK_MT6360_ADC=m
+CONFIG_MEN_Z188_ADC=m
+CONFIG_MP2629_ADC=m
+CONFIG_NAU7802=m
+CONFIG_PALMAS_GPADC=m
+CONFIG_QCOM_SPMI_IADC=m
+CONFIG_QCOM_SPMI_VADC=m
+CONFIG_QCOM_SPMI_ADC5=m
+CONFIG_RN5T618_ADC=m
+CONFIG_SD_ADC_MODULATOR=m
+CONFIG_STMPE_ADC=m
+CONFIG_TI_ADC081C=m
+CONFIG_TI_ADC0832=m
+CONFIG_TI_ADC084S021=m
+CONFIG_TI_ADC12138=m
+CONFIG_TI_ADC108S102=m
+CONFIG_TI_ADC128S052=m
+CONFIG_TI_ADC161S626=m
+CONFIG_TI_ADS1015=m
+CONFIG_TI_ADS7950=m
+CONFIG_TI_ADS8344=m
+CONFIG_TI_ADS8688=m
+CONFIG_TI_ADS124S08=m
+CONFIG_TI_ADS131E08=m
+CONFIG_TI_AM335X_ADC=m
+CONFIG_TI_TLC4541=m
+CONFIG_TI_TSC2046=m
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL6030_GPADC=m
+CONFIG_VF610_ADC=m
+CONFIG_VIPERBOARD_ADC=m
+CONFIG_XILINX_XADC=m
+CONFIG_AD74413R=m
+CONFIG_IIO_RESCALE=m
+CONFIG_AD8366=m
+CONFIG_ADA4250=m
+CONFIG_HMC425=m
+CONFIG_AD7150=m
+CONFIG_AD7746=m
+CONFIG_ATLAS_PH_SENSOR=m
+CONFIG_ATLAS_EZO_SENSOR=m
+CONFIG_BME680=m
+CONFIG_CCS811=m
+CONFIG_IAQCORE=m
+CONFIG_PMS7003=m
+CONFIG_SCD30_CORE=m
+CONFIG_SCD30_I2C=m
+CONFIG_SCD30_SERIAL=m
+CONFIG_SCD4X=m
+CONFIG_SENSIRION_SGP30=m
+CONFIG_SENSIRION_SGP40=m
+CONFIG_SPS30_I2C=m
+CONFIG_SPS30_SERIAL=m
+CONFIG_SENSEAIR_SUNRISE_CO2=m
+CONFIG_VZ89X=m
+CONFIG_IIO_SSP_SENSORS_COMMONS=m
+CONFIG_IIO_SSP_SENSORHUB=m
+CONFIG_AD3552R=m
+CONFIG_AD5064=m
+CONFIG_AD5360=m
+CONFIG_AD5380=m
+CONFIG_AD5421=m
+CONFIG_AD5446=m
+CONFIG_AD5449=m
+CONFIG_AD5592R=m
+CONFIG_AD5593R=m
+CONFIG_AD5504=m
+CONFIG_AD5624R_SPI=m
+CONFIG_LTC2688=m
+CONFIG_AD5686_SPI=m
+CONFIG_AD5696_I2C=m
+CONFIG_AD5755=m
+CONFIG_AD5758=m
+CONFIG_AD5761=m
+CONFIG_AD5764=m
+CONFIG_AD5766=m
+CONFIG_AD5770R=m
+CONFIG_AD5791=m
+CONFIG_AD7293=m
+CONFIG_AD7303=m
+CONFIG_AD8801=m
+CONFIG_DPOT_DAC=m
+CONFIG_DS4424=m
+CONFIG_LTC1660=m
+CONFIG_LTC2632=m
+CONFIG_M62332=m
+CONFIG_MAX517=m
+CONFIG_MAX5821=m
+CONFIG_MCP4725=m
+CONFIG_MCP4922=m
+CONFIG_TI_DAC082S085=m
+CONFIG_TI_DAC5571=m
+CONFIG_TI_DAC7311=m
+CONFIG_TI_DAC7612=m
+CONFIG_VF610_DAC=m
+CONFIG_IIO_SIMPLE_DUMMY=m
+CONFIG_ADMV8818=m
+CONFIG_AD9523=m
+CONFIG_ADF4350=m
+CONFIG_ADF4371=m
+CONFIG_ADMV1013=m
+CONFIG_ADMV1014=m
+CONFIG_ADMV4420=m
+CONFIG_ADRF6780=m
+CONFIG_ADIS16080=m
+CONFIG_ADIS16130=m
+CONFIG_ADIS16136=m
+CONFIG_ADIS16260=m
+CONFIG_ADXRS290=m
+CONFIG_ADXRS450=m
+CONFIG_BMG160=m
+CONFIG_FXAS21002C=m
+CONFIG_HID_SENSOR_GYRO_3D=m
+CONFIG_MPU3050_I2C=m
+CONFIG_IIO_ST_GYRO_3AXIS=m
+CONFIG_ITG3200=m
+CONFIG_AFE4403=m
+CONFIG_AFE4404=m
+CONFIG_MAX30100=m
+CONFIG_MAX30102=m
+CONFIG_AM2315=m
+CONFIG_DHT11=m
+CONFIG_HDC100X=m
+CONFIG_HDC2010=m
+CONFIG_HID_SENSOR_HUMIDITY=m
+CONFIG_HTS221=m
+CONFIG_HTU21=m
+CONFIG_SI7005=m
+CONFIG_SI7020=m
+CONFIG_ADIS16400=m
+CONFIG_ADIS16460=m
+CONFIG_ADIS16475=m
+CONFIG_ADIS16480=m
+CONFIG_BMI160_I2C=m
+CONFIG_BMI160_SPI=m
+CONFIG_FXOS8700_I2C=m
+CONFIG_FXOS8700_SPI=m
+CONFIG_KMX61=m
+CONFIG_INV_ICM42600_I2C=m
+CONFIG_INV_ICM42600_SPI=m
+CONFIG_INV_MPU6050_I2C=m
+CONFIG_INV_MPU6050_SPI=m
+CONFIG_IIO_ST_LSM6DSX=m
+CONFIG_IIO_ST_LSM9DS0=m
+CONFIG_ADJD_S311=m
+CONFIG_ADUX1020=m
+CONFIG_AL3010=m
+CONFIG_AL3320A=m
+CONFIG_APDS9300=m
+CONFIG_APDS9960=m
+CONFIG_AS73211=m
+CONFIG_BH1750=m
+CONFIG_BH1780=m
+CONFIG_CM32181=m
+CONFIG_CM3232=m
+CONFIG_CM3323=m
+CONFIG_CM3605=m
+CONFIG_CM36651=m
+CONFIG_GP2AP002=m
+CONFIG_GP2AP020A00F=m
+CONFIG_IQS621_ALS=m
+CONFIG_SENSORS_ISL29018=m
+CONFIG_SENSORS_ISL29028=m
+CONFIG_ISL29125=m
+CONFIG_HID_SENSOR_ALS=m
+CONFIG_HID_SENSOR_PROX=m
+CONFIG_JSA1212=m
+CONFIG_RPR0521=m
+CONFIG_SENSORS_LM3533=m
+CONFIG_LTR501=m
+CONFIG_LV0104CS=m
+CONFIG_MAX44000=m
+CONFIG_MAX44009=m
+CONFIG_NOA1305=m
+CONFIG_OPT3001=m
+CONFIG_PA12203001=m
+CONFIG_SI1133=m
+CONFIG_SI1145=m
+CONFIG_STK3310=m
+CONFIG_ST_UVIS25=m
+CONFIG_TCS3414=m
+CONFIG_TCS3472=m
+CONFIG_SENSORS_TSL2563=m
+CONFIG_TSL2583=m
+CONFIG_TSL2591=m
+CONFIG_TSL2772=m
+CONFIG_TSL4531=m
+CONFIG_US5182D=m
+CONFIG_VCNL4000=m
+CONFIG_VCNL4035=m
+CONFIG_VEML6030=m
+CONFIG_VEML6070=m
+CONFIG_VL6180=m
+CONFIG_ZOPT2201=m
+CONFIG_AK8974=m
+CONFIG_AK09911=m
+CONFIG_BMC150_MAGN_I2C=m
+CONFIG_BMC150_MAGN_SPI=m
+CONFIG_MAG3110=m
+CONFIG_HID_SENSOR_MAGNETOMETER_3D=m
+CONFIG_MMC35240=m
+CONFIG_SENSORS_HMC5843_I2C=m
+CONFIG_SENSORS_HMC5843_SPI=m
+CONFIG_SENSORS_RM3100_I2C=m
+CONFIG_SENSORS_RM3100_SPI=m
+CONFIG_YAMAHA_YAS530=m
+CONFIG_IIO_MUX=m
+CONFIG_HID_SENSOR_INCLINOMETER_3D=m
+CONFIG_HID_SENSOR_DEVICE_ROTATION=m
+CONFIG_IIO_HRTIMER_TRIGGER=m
+CONFIG_IIO_INTERRUPT_TRIGGER=m
+CONFIG_IIO_TIGHTLOOP_TRIGGER=m
+CONFIG_IIO_SYSFS_TRIGGER=m
+CONFIG_IQS624_POS=m
+CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m
+CONFIG_AD5110=m
+CONFIG_AD5272=m
+CONFIG_DS1803=m
+CONFIG_MAX5432=m
+CONFIG_MAX5481=m
+CONFIG_MAX5487=m
+CONFIG_MCP4018=m
+CONFIG_MCP4131=m
+CONFIG_MCP4531=m
+CONFIG_MCP41010=m
+CONFIG_TPL0102=m
+CONFIG_LMP91000=m
+CONFIG_ABP060MG=m
+CONFIG_BMP280=m
+CONFIG_DLHL60D=m
+CONFIG_DPS310=m
+CONFIG_HID_SENSOR_PRESS=m
+CONFIG_HP03=m
+CONFIG_ICP10100=m
+CONFIG_MPL115_I2C=m
+CONFIG_MPL115_SPI=m
+CONFIG_MPL3115=m
+CONFIG_MS5611=m
+CONFIG_MS5611_I2C=m
+CONFIG_MS5611_SPI=m
+CONFIG_MS5637=m
+CONFIG_IIO_ST_PRESS=m
+CONFIG_T5403=m
+CONFIG_HP206C=m
+CONFIG_ZPA2326=m
+CONFIG_AS3935=m
+CONFIG_ISL29501=m
+CONFIG_LIDAR_LITE_V2=m
+CONFIG_MB1232=m
+CONFIG_PING=m
+CONFIG_RFD77402=m
+CONFIG_SRF04=m
+CONFIG_SX9310=m
+CONFIG_SX9324=m
+CONFIG_SX9360=m
+CONFIG_SX9500=m
+CONFIG_SRF08=m
+CONFIG_VCNL3020=m
+CONFIG_VL53L0X_I2C=m
+CONFIG_AD2S90=m
+CONFIG_AD2S1200=m
+CONFIG_IQS620AT_TEMP=m
+CONFIG_LTC2983=m
+CONFIG_MAXIM_THERMOCOUPLE=m
+CONFIG_HID_SENSOR_TEMP=m
+CONFIG_MLX90614=m
+CONFIG_MLX90632=m
+CONFIG_TMP006=m
+CONFIG_TMP007=m
+CONFIG_TMP117=m
+CONFIG_TSYS01=m
+CONFIG_TSYS02D=m
+CONFIG_MAX31856=m
+CONFIG_MAX31865=m
+CONFIG_NTB=m
+CONFIG_NTB_MSI=y
+CONFIG_NTB_IDT=m
+CONFIG_NTB_EPF=m
+CONFIG_NTB_SWITCHTEC=m
+CONFIG_NTB_PINGPONG=m
+CONFIG_NTB_TOOL=m
+CONFIG_NTB_PERF=m
+CONFIG_NTB_TRANSPORT=m
+CONFIG_PWM=y
+CONFIG_PWM_ATMEL_HLCDC_PWM=m
+CONFIG_PWM_ATMEL_TCB=m
+CONFIG_PWM_DWC=m
+CONFIG_PWM_FSL_FTM=m
+CONFIG_PWM_IQS620A=m
+CONFIG_PWM_LP3943=m
+CONFIG_PWM_NTXEC=m
+CONFIG_PWM_PCA9685=m
+CONFIG_PWM_SIFIVE=y
+CONFIG_PWM_STMPE=y
+CONFIG_PWM_TWL=m
+CONFIG_PWM_TWL_LED=m
+CONFIG_PWM_XILINX=m
+CONFIG_AL_FIC=y
+CONFIG_XILINX_INTC=y
+CONFIG_IPACK_BUS=m
+CONFIG_BOARD_TPCI200=m
+CONFIG_SERIAL_IPOCTAL=m
+CONFIG_RESET_TI_SYSCON=m
+CONFIG_PHY_CAN_TRANSCEIVER=m
+CONFIG_BCM_KONA_USB2_PHY=m
+CONFIG_PHY_CADENCE_TORRENT=m
+CONFIG_PHY_CADENCE_DPHY=m
+CONFIG_PHY_CADENCE_DPHY_RX=m
+CONFIG_PHY_CADENCE_SIERRA=m
+CONFIG_PHY_CADENCE_SALVO=m
+CONFIG_PHY_PXA_28NM_HSIC=m
+CONFIG_PHY_PXA_28NM_USB2=m
+CONFIG_PHY_LAN966X_SERDES=m
+CONFIG_PHY_CPCAP_USB=m
+CONFIG_PHY_MAPPHONE_MDM6600=m
+CONFIG_PHY_OCELOT_SERDES=m
+CONFIG_PHY_QCOM_USB_HS=m
+CONFIG_PHY_QCOM_USB_HSIC=m
+CONFIG_PHY_SAMSUNG_USB2=m
+CONFIG_PHY_TUSB1210=m
+CONFIG_POWERCAP=y
+CONFIG_IDLE_INJECT=y
+CONFIG_DTPM=y
+CONFIG_MCB=m
+CONFIG_MCB_PCI=m
+CONFIG_MCB_LPC=m
+CONFIG_USB4=m
+CONFIG_LIBNVDIMM=y
+CONFIG_BLK_DEV_PMEM=m
+CONFIG_OF_PMEM=m
+CONFIG_DAX=y
+CONFIG_DEV_DAX=m
+CONFIG_NVMEM_RMEM=m
+CONFIG_NVMEM_SPMI_SDAM=m
+CONFIG_STM=m
+CONFIG_STM_PROTO_BASIC=m
+CONFIG_STM_PROTO_SYS_T=m
+CONFIG_STM_DUMMY=m
+CONFIG_STM_SOURCE_CONSOLE=m
+CONFIG_STM_SOURCE_HEARTBEAT=m
+CONFIG_STM_SOURCE_FTRACE=m
+CONFIG_INTEL_TH=m
+CONFIG_INTEL_TH_PCI=m
+CONFIG_INTEL_TH_GTH=m
+CONFIG_INTEL_TH_STH=m
+CONFIG_INTEL_TH_MSU=m
+CONFIG_INTEL_TH_PTI=m
+CONFIG_FPGA=m
+CONFIG_ALTERA_PR_IP_CORE=m
+CONFIG_ALTERA_PR_IP_CORE_PLAT=m
+CONFIG_FPGA_MGR_ALTERA_PS_SPI=m
+CONFIG_FPGA_MGR_ALTERA_CVP=m
+CONFIG_FPGA_MGR_XILINX_SPI=m
+CONFIG_FPGA_MGR_ICE40_SPI=m
+CONFIG_FPGA_MGR_MACHXO2_SPI=m
+CONFIG_ALTERA_FREEZE_BRIDGE=m
+CONFIG_XILINX_PR_DECOUPLER=m
+CONFIG_OF_FPGA_REGION=m
+CONFIG_FPGA_DFL=m
+CONFIG_FPGA_DFL_FME=m
+CONFIG_FPGA_DFL_FME_MGR=m
+CONFIG_FPGA_DFL_FME_BRIDGE=m
+CONFIG_FPGA_DFL_FME_REGION=m
+CONFIG_FPGA_DFL_AFU=m
+CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000=m
+CONFIG_FPGA_DFL_PCI=m
+CONFIG_FSI=m
+CONFIG_FSI_MASTER_GPIO=m
+CONFIG_FSI_MASTER_HUB=m
+CONFIG_FSI_MASTER_ASPEED=m
+CONFIG_FSI_SCOM=m
+CONFIG_FSI_SBEFIFO=m
+CONFIG_FSI_OCC=m
+CONFIG_MUX_ADG792A=m
+CONFIG_MUX_ADGS1408=m
+CONFIG_MUX_GPIO=m
+CONFIG_MUX_MMIO=m
+CONFIG_SIOX=m
+CONFIG_SIOX_BUS_GPIO=m
+CONFIG_SLIM_QCOM_CTRL=m
+CONFIG_INTERCONNECT=y
+CONFIG_MOST=m
+CONFIG_MOST_USB_HDM=m
+CONFIG_MOST_CDEV=m
+CONFIG_MOST_SND=m
+CONFIG_PECI=m
+CONFIG_VALIDATE_FS_PARSER=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=m
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+CONFIG_JFS_STATISTICS=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_F2FS_FS=m
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_F2FS_FS_COMPRESSION=y
+# CONFIG_F2FS_IOSTAT is not set
+CONFIG_F2FS_UNFAIR_RWSEM=y
+CONFIG_ZONEFS_FS=m
+CONFIG_FS_ENCRYPTION=y
+CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
+CONFIG_FS_VERITY=y
+CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y
+CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_VIRTIO_FS=m
+CONFIG_OVERLAY_FS=m
+CONFIG_OVERLAY_FS_XINO_AUTO=y
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=m
+CONFIG_CACHEFILES_ERROR_INJECTION=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_EXFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS3_FS=m
+CONFIG_NTFS3_LZX_XPRESS=y
+CONFIG_NTFS3_FS_POSIX_ACL=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_VMCORE_DEVICE_DUMP=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
+CONFIG_HUGETLBFS=y
+CONFIG_EFIVAR_FS=y
+CONFIG_ORANGEFS_FS=m
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+CONFIG_UBIFS_FS=m
+CONFIG_UBIFS_FS_AUTHENTICATION=y
+CONFIG_CRAMFS=m
+CONFIG_CRAMFS_MTD=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZSTD=y
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_QNX6FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_PSTORE=y
+CONFIG_PSTORE_RAM=m
+CONFIG_PSTORE_BLK=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_EROFS_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_BLOCKLAYOUT=y
+CONFIG_NFSD_SCSILAYOUT=y
+CONFIG_NFSD_FLEXFILELAYOUT=y
+CONFIG_NFSD_V4_2_INTER_SSC=y
+CONFIG_NFSD_V4_SECURITY_LABEL=y
+CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_CEPH_FS=m
+CONFIG_CEPH_FSCACHE=y
+CONFIG_CEPH_FS_POSIX_ACL=y
+CONFIG_CEPH_FS_SECURITY_LABEL=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_SWN_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+CONFIG_SMB_SERVER=m
+CONFIG_SMB_SERVER_SMBDIRECT=y
+CONFIG_SMB_SERVER_KERBEROS5=y
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+CONFIG_AFS_FSCACHE=y
+CONFIG_9P_FS=m
+CONFIG_9P_FSCACHE=y
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_9P_FS_SECURITY=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_MAC_ROMAN=m
+CONFIG_NLS_MAC_CELTIC=m
+CONFIG_NLS_MAC_CENTEURO=m
+CONFIG_NLS_MAC_CROATIAN=m
+CONFIG_NLS_MAC_CYRILLIC=m
+CONFIG_NLS_MAC_GAELIC=m
+CONFIG_NLS_MAC_GREEK=m
+CONFIG_NLS_MAC_ICELAND=m
+CONFIG_NLS_MAC_INUIT=m
+CONFIG_NLS_MAC_ROMANIAN=m
+CONFIG_NLS_MAC_TURKISH=m
+CONFIG_DLM=m
+CONFIG_UNICODE=y
+CONFIG_KEYS_REQUEST_CACHE=y
+CONFIG_PERSISTENT_KEYRINGS=y
+CONFIG_TRUSTED_KEYS=y
+CONFIG_USER_DECRYPTED_DATA=y
+CONFIG_KEY_DH_OPERATIONS=y
+CONFIG_KEY_NOTIFICATIONS=y
+CONFIG_SECURITY_DMESG_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_INFINIBAND=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_SMACK_NETFILTER=y
+CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_YAMA=y
+CONFIG_SECURITY_SAFESETID=y
+CONFIG_SECURITY_LOCKDOWN_LSM=y
+CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
+CONFIG_SECURITY_LANDLOCK=y
+CONFIG_INTEGRITY_SIGNATURE=y
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
+CONFIG_INTEGRITY_PLATFORM_KEYRING=y
+CONFIG_INTEGRITY_MACHINE_KEYRING=y
+CONFIG_IMA=y
+CONFIG_IMA_KEXEC=y
+CONFIG_IMA_APPRAISE=y
+CONFIG_IMA_ARCH_POLICY=y
+CONFIG_IMA_APPRAISE_MODSIG=y
+CONFIG_EVM=y
+CONFIG_EVM_EXTRA_SMACK_XATTRS=y
+CONFIG_EVM_ADD_XATTRS=y
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
+CONFIG_LSM="landlock,lockdown,yama,integrity,apparmor"
+CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_DH_RFC7919_GROUPS=y
+CONFIG_CRYPTO_ECDSA=m
+CONFIG_CRYPTO_ECRDSA=m
+CONFIG_CRYPTO_SM2=m
+CONFIG_CRYPTO_CURVE25519=m
+CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA3=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_DRBG_HASH=y
+CONFIG_CRYPTO_DRBG_CTR=y
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
+# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set
+CONFIG_CRYPTO_STATS=y
+CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
+CONFIG_CRYPTO_DEV_CHELSIO=m
+CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_CRYPTO_DEV_CCREE=m
+CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m
+CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
+CONFIG_PKCS7_TEST_KEY=m
+CONFIG_SIGNED_PE_FILE_VERIFICATION=y
+CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
+CONFIG_SECONDARY_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+CONFIG_SYSTEM_REVOCATION_LIST=y
+CONFIG_XZ_DEC_MICROLZMA=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_DMA_RESTRICTED_POOL=y
+CONFIG_DMA_CMA=y
+CONFIG_DMA_PERNUMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=32
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_FONT_6x10=y
+CONFIG_FONT_TER16x32=y
+CONFIG_PRINTK_TIME=y
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_FRAME_WARN=1024
+CONFIG_VMLINUX_MAP=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+CONFIG_PAGE_POISONING=y
+CONFIG_DEBUG_WX=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_KFENCE=y
+CONFIG_KFENCE_SAMPLE_INTERVAL=0
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_TRACE is not set
+CONFIG_BOOTTIME_TRACING=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_STACK_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_HWLAT_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BPF_KPROBE_OVERRIDE=y
+CONFIG_SYNTH_EVENTS=y
+CONFIG_TRACE_EVENT_INJECT=y
+CONFIG_SAMPLES=y
+CONFIG_SAMPLE_TRACE_PRINTK=m
+CONFIG_SAMPLE_TRACE_ARRAY=m
+CONFIG_NOTIFIER_ERROR_INJECTION=m
+CONFIG_FUNCTION_ERROR_INJECTION=y
+CONFIG_TEST_BPF=m
+CONFIG_TEST_BLACKHOLE_DEV=m
+CONFIG_MEMTEST=y
diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
index 32a34ed73509..9d71fe3d35c7 100644
--- a/arch/riscv/errata/thead/errata.c
+++ b/arch/riscv/errata/thead/errata.c
@@ -48,6 +48,22 @@ static bool errata_probe_cmo(unsigned int stage,
 	return true;
 }
 
+static bool errata_probe_pmu(unsigned int stage,
+			     unsigned long arch_id, unsigned long impid)
+{
+	if (!IS_ENABLED(CONFIG_ERRATA_THEAD_PMU))
+		return false;
+
+	/* target-c9xx cores report arch_id and impid as 0 */
+	if (arch_id != 0 || impid != 0)
+		return false;
+
+	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
+		return false;
+
+	return true;
+}
+
 static u32 thead_errata_probe(unsigned int stage,
 			      unsigned long archid, unsigned long impid)
 {
@@ -59,6 +75,9 @@ static u32 thead_errata_probe(unsigned int stage,
 	if (errata_probe_cmo(stage, archid, impid))
 		cpu_req_errata |= BIT(ERRATA_THEAD_CMO);
 
+	if (errata_probe_pmu(stage, archid, impid))
+		cpu_req_errata |= BIT(ERRATA_THEAD_PMU);
+
 	return cpu_req_errata;
 }
 
diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h
index 110752594228..2b1f98b7e9bf 100644
--- a/arch/riscv/include/asm/barrier.h
+++ b/arch/riscv/include/asm/barrier.h
@@ -29,12 +29,22 @@
 #define __smp_rmb()	RISCV_FENCE(r,r)
 #define __smp_wmb()	RISCV_FENCE(w,w)
 
+#ifdef CONFIG_ARCH_SOPHGO
 #define __smp_store_release(p, v)					\
 do {									\
 	compiletime_assert_atomic_type(*p);				\
 	RISCV_FENCE(rw,w);						\
 	WRITE_ONCE(*p, v);						\
+	RISCV_FENCE(w,rw);						\
 } while (0)
+#else
+#define __smp_store_release(p, v)					\
+do {									\
+	compiletime_assert_atomic_type(*p);				\
+	RISCV_FENCE(rw,w);						\
+	WRITE_ONCE(*p, v);						\
+} while (0)
+#endif
 
 #define __smp_load_acquire(p)						\
 ({									\
@@ -44,6 +54,18 @@ do {									\
 	___p1;								\
 })
 
+#define smp_cond_load_acquire(ptr, cond_expr) ({			\
+	typeof(ptr) __PTR = (ptr);					\
+	__unqual_scalar_typeof(*ptr) VAL;				\
+	for (;;) {							\
+		VAL = __smp_load_acquire(__PTR);			\
+		if (cond_expr)						\
+			break;						\
+		cpu_relax();						\
+	}								\
+	(typeof(*ptr))VAL;						\
+})
+
 /*
  * This is a very specific barrier: it's currently only used in two places in
  * the kernel, both in the scheduler.  See include/linux/spinlock.h for the two
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
index f6fbe7042f1c..03e3b95ae6da 100644
--- a/arch/riscv/include/asm/cacheflush.h
+++ b/arch/riscv/include/asm/cacheflush.h
@@ -17,6 +17,13 @@ static inline void local_flush_icache_all(void)
 
 static inline void flush_dcache_page(struct page *page)
 {
+	/*
+	 * HugeTLB pages are always fully mapped and only head page will be
+	 * set PG_dcache_clean (see comments in flush_icache_pte()).
+	 */
+	if (PageHuge(page))
+		page = compound_head(page);
+
 	if (test_bit(PG_dcache_clean, &page->flags))
 		clear_bit(PG_dcache_clean, &page->flags);
 }
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 0e571f6483d9..6234054fef4a 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -24,6 +24,12 @@
 #define SR_FS_CLEAN	_AC(0x00004000, UL)
 #define SR_FS_DIRTY	_AC(0x00006000, UL)
 
+#define SR_VS		_AC(0x01800000, UL) /* Vector Status */
+#define SR_VS_OFF	_AC(0x00000000, UL)
+#define SR_VS_INITIAL	_AC(0x00800000, UL)
+#define SR_VS_CLEAN	_AC(0x01000000, UL)
+#define SR_VS_DIRTY	_AC(0x01800000, UL)
+
 #define SR_XS		_AC(0x00018000, UL) /* Extension Status */
 #define SR_XS_OFF	_AC(0x00000000, UL)
 #define SR_XS_INITIAL	_AC(0x00008000, UL)
@@ -297,6 +303,13 @@
 #define CSR_MIMPID		0xf13
 #define CSR_MHARTID		0xf14
 
+#define CSR_VSTART		0x8
+#define CSR_VXSAT		0x9
+#define CSR_VXRM		0xa
+#define CSR_VL			0xc20
+#define CSR_VTYPE		0xc21
+#define CSR_VLENB		0xc22
+
 #ifdef CONFIG_RISCV_M_MODE
 # define CSR_STATUS	CSR_MSTATUS
 # define CSR_IE		CSR_MIE
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index 7d2675bb7161..26de5a8cb3ee 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -6,6 +6,7 @@
 #define ASM_ERRATA_LIST_H
 
 #include <asm/alternative.h>
+#include <asm/csr.h>
 #include <asm/vendorid_list.h>
 
 #ifdef CONFIG_ERRATA_SIFIVE
@@ -17,7 +18,8 @@
 #ifdef CONFIG_ERRATA_THEAD
 #define	ERRATA_THEAD_PBMT 0
 #define	ERRATA_THEAD_CMO 1
-#define	ERRATA_THEAD_NUMBER 2
+#define	ERRATA_THEAD_PMU 2
+#define	ERRATA_THEAD_NUMBER 3
 #endif
 
 #define	CPUFEATURE_SVPBMT 0
@@ -113,9 +115,12 @@ asm volatile(ALTERNATIVE(						\
  *   0000000    11001     00000      000      00000  0001011
  */
 #define THEAD_inval_A0	".long 0x0265000b"
-#define THEAD_clean_A0	".long 0x0255000b"
+#define THEAD_clean_A0	".long 0x0275000b"
 #define THEAD_flush_A0	".long 0x0275000b"
 #define THEAD_SYNC_S	".long 0x0190000b"
+#define THEAD_inval_PA_A0	".long 0x02a5000b"
+#define THEAD_clean_PA_A0	".long 0x02b5000b"
+#define THEAD_flush_PA_A0	".long 0x02b5000b"
 
 #define ALT_CMO_OP(_op, _start, _size, _cachesize)			\
 asm volatile(ALTERNATIVE_2(						\
@@ -142,6 +147,45 @@ asm volatile(ALTERNATIVE_2(						\
 	    "r"((unsigned long)(_start) + (_size))			\
 	: "a0")
 
+#define ALT_CMO_OP_VPA(_op, _vaddr, _paddr, _size, _cachesize)		\
+asm volatile(ALTERNATIVE_2(						\
+	__nops(6),							\
+	"mv a0, %1\n\t"							\
+	"j 2f\n\t"							\
+	"3:\n\t"							\
+	"cbo." __stringify(_op) " (a0)\n\t"				\
+	"add a0, a0, %0\n\t"						\
+	"2:\n\t"							\
+	"bltu a0, %2, 3b\n\t"						\
+	"nop", 0, CPUFEATURE_ZICBOM, CONFIG_RISCV_ISA_ZICBOM,		\
+	"mv a0, %3\n\t"							\
+	"j 2f\n\t"							\
+	"3:\n\t"							\
+	THEAD_##_op##_PA_A0 "\n\t"					\
+	"add a0, a0, %0\n\t"						\
+	"2:\n\t"							\
+	"bltu a0, %4, 3b\n\t"						\
+	THEAD_SYNC_S, THEAD_VENDOR_ID,					\
+			ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO)	\
+	: : "r"(_cachesize),						\
+	    "r"((unsigned long)(_vaddr) & ~((_cachesize) - 1UL)),	\
+	    "r"((unsigned long)(_vaddr) + (_size)),			\
+	    "r"((unsigned long)(_paddr) & ~((_cachesize) - 1UL)),	\
+	    "r"((unsigned long)(_paddr) + (_size))			\
+	: "a0")
+
+#define THEAD_C9XX_RV_IRQ_PMU			17
+#define THEAD_C9XX_CSR_SCOUNTEROF		0x5c5
+
+#define ALT_SBI_PMU_OVERFLOW(__ovl)					\
+asm volatile(ALTERNATIVE(						\
+	"csrr %0, " __stringify(CSR_SSCOUNTOVF),			\
+	"csrr %0, " __stringify(THEAD_C9XX_CSR_SCOUNTEROF),		\
+		THEAD_VENDOR_ID, ERRATA_THEAD_PMU,			\
+		CONFIG_ERRATA_THEAD_PMU)				\
+	: "=r" (__ovl) :						\
+	: "memory")
+
 #endif /* __ASSEMBLY__ */
 
 #endif
diff --git a/arch/riscv/include/asm/fixmap.h b/arch/riscv/include/asm/fixmap.h
index 0a55099bb734..365bbbd63251 100644
--- a/arch/riscv/include/asm/fixmap.h
+++ b/arch/riscv/include/asm/fixmap.h
@@ -10,6 +10,10 @@
 #include <linux/sizes.h>
 #include <linux/pgtable.h>
 #include <asm/page.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_size.h>
+#endif
 
 #ifdef CONFIG_MMU
 /*
@@ -37,6 +41,10 @@ enum fixed_addresses {
 	FIX_TEXT_POKE1,
 	FIX_TEXT_POKE0,
 	FIX_EARLYCON_MEM_BASE,
+#ifdef CONFIG_HIGHMEM
+	FIX_KMAP_BEGIN,
+	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1,
+#endif
 
 	__end_of_permanent_fixed_addresses,
 	/*
@@ -47,7 +55,12 @@ enum fixed_addresses {
 #define FIX_BTMAPS_SLOTS	7
 #define TOTAL_FIX_BTMAPS	(NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
 
+#ifdef CONFIG_HIGHMEM
+	FIX_BTMAP_END = __ALIGN_MASK(__end_of_permanent_fixed_addresses,
+				((PMD_SIZE / PAGE_SIZE) - 1)) + 1,
+#else
 	FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+#endif
 	FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
 
 	__end_of_fixed_addresses
diff --git a/arch/riscv/include/asm/highmem.h b/arch/riscv/include/asm/highmem.h
new file mode 100644
index 000000000000..a36fc835b8ab
--- /dev/null
+++ b/arch/riscv/include/asm/highmem.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#include <asm/kmap_size.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+
+#define flush_cache_kmaps() do {} while (0)
+
+extern pte_t *pkmap_page_table;
+#endif
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index b22525290073..bfeae8dbdfa4 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -35,6 +35,7 @@ extern unsigned long elf_hwcap;
 #define RISCV_ISA_EXT_m		('m' - 'a')
 #define RISCV_ISA_EXT_s		('s' - 'a')
 #define RISCV_ISA_EXT_u		('u' - 'a')
+#define RISCV_ISA_EXT_v		('v' - 'a')
 
 /*
  * Increse this to higher value as kernel support more ISA extensions.
diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
index 2b56769cb530..62f3ddc7c498 100644
--- a/arch/riscv/include/asm/kexec.h
+++ b/arch/riscv/include/asm/kexec.h
@@ -56,6 +56,7 @@ extern riscv_kexec_method riscv_kexec_norelocate;
 
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops elf_kexec_ops;
+extern const struct kexec_file_ops image_kexec_ops;
 
 struct purgatory_info;
 int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
index 42a042c0e13e..5a5b1f70b155 100644
--- a/arch/riscv/include/asm/pgtable-64.h
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -93,13 +93,13 @@ typedef struct {
 /*
  * [63:59] T-Head Memory Type definitions:
  *
- * 00000 - NC   Weakly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable
+ * 00010 - NC   Weakly-ordered, Non-cacheable, Non-bufferable, Shareable, Non-trustable
  * 01110 - PMA  Weakly-ordered, Cacheable, Bufferable, Shareable, Non-trustable
- * 10000 - IO   Strongly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable
+ * 10010 - IO   Strongly-ordered, Non-cacheable, Non-bufferable, Shareable, Non-trustable
  */
 #define _PAGE_PMA_THEAD		((1UL << 62) | (1UL << 61) | (1UL << 60))
-#define _PAGE_NOCACHE_THEAD	0UL
-#define _PAGE_IO_THEAD		(1UL << 63)
+#define _PAGE_NOCACHE_THEAD	((1UL << 61) | (1UL << 60))
+#define _PAGE_IO_THEAD		((1UL << 63) | (1UL << 60))
 #define _PAGE_MTMASK_THEAD	(_PAGE_PMA_THEAD | _PAGE_IO_THEAD | (1UL << 59))
 
 static inline u64 riscv_page_mtmask(void)
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 59bb53da473d..31134b959485 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -89,7 +89,12 @@
 #ifdef CONFIG_64BIT
 #define MAX_FDT_SIZE	 PMD_SIZE
 #define FIX_FDT_SIZE	 (MAX_FDT_SIZE + SZ_2M)
+#ifdef CONFIG_HIGHMEM
+#define FIXADDR_PMD_NUM  20
+#define FIXADDR_SIZE     ((PMD_SIZE * FIXADDR_PMD_NUM) + FIX_FDT_SIZE)
+#else
 #define FIXADDR_SIZE     (PMD_SIZE + FIX_FDT_SIZE)
+#endif
 #else
 #define MAX_FDT_SIZE	 PGDIR_SIZE
 #define FIX_FDT_SIZE	 MAX_FDT_SIZE
@@ -99,6 +104,14 @@
 
 #endif
 
+#ifdef CONFIG_HIGHMEM
+#define PKMAP_BASE       ((FIXADDR_START - PMD_SIZE) & (PMD_MASK))
+#define LAST_PKMAP       (PMD_SIZE >> PAGE_SHIFT)
+#define LAST_PKMAP_MASK  (LAST_PKMAP - 1)
+#define PKMAP_NR(virt)   (((virt) - PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)   (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+#endif
+
 #ifdef CONFIG_XIP_KERNEL
 #define XIP_OFFSET		SZ_32M
 #define XIP_OFFSET_MASK		(SZ_32M - 1)
@@ -454,6 +467,9 @@ static inline void __set_pte_at(struct mm_struct *mm,
 		flush_icache_pte(pteval);
 
 	set_pte(ptep, pteval);
+#ifdef CONFIG_HIGHMEM
+	local_flush_tlb_page(addr);
+#endif
 }
 
 static inline void set_pte_at(struct mm_struct *mm,
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 94a0590c6971..44d2eb381ca6 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -39,6 +39,7 @@ struct thread_struct {
 	unsigned long s[12];	/* s[0]: frame pointer */
 	struct __riscv_d_ext_state fstate;
 	unsigned long bad_cause;
+	struct __riscv_v_state vstate;
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 9baddaee5623..8cb7c579aa21 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -327,4 +327,9 @@ int sbi_err_map_linux_errno(int err);
 static inline int sbi_remote_fence_i(const struct cpumask *cpu_mask) { return -1; }
 static inline void sbi_init(void) {}
 #endif /* CONFIG_RISCV_SBI */
+
+unsigned long riscv_cached_mvendorid(unsigned int cpu_id);
+unsigned long riscv_cached_marchid(unsigned int cpu_id);
+unsigned long riscv_cached_mimpid(unsigned int cpu_id);
+
 #endif /* _ASM_RISCV_SBI_H */
diff --git a/arch/riscv/include/asm/sparsemem.h b/arch/riscv/include/asm/sparsemem.h
index 63acaecc3374..8fa7a2b3d769 100644
--- a/arch/riscv/include/asm/sparsemem.h
+++ b/arch/riscv/include/asm/sparsemem.h
@@ -5,7 +5,11 @@
 
 #ifdef CONFIG_SPARSEMEM
 #ifdef CONFIG_64BIT
+#ifdef CONFIG_ARCH_SOPHGO
+#define MAX_PHYSMEM_BITS	44
+#else
 #define MAX_PHYSMEM_BITS	56
+#endif
 #else
 #define MAX_PHYSMEM_BITS	34
 #endif /* CONFIG_64BIT */
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 11463489fec6..d9a0f5445ea5 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -61,6 +61,20 @@ static __always_inline bool has_fpu(void)
 {
 	return static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_FPU]);
 }
+
+static inline void kernel_fpu_begin(void)
+{
+	preempt_disable();
+	fstate_save(current, task_pt_regs(current));
+	csr_set(CSR_SSTATUS, SR_FS);
+}
+
+static inline void kernel_fpu_end(void)
+{
+	csr_clear(CSR_SSTATUS, SR_FS);
+	fstate_restore(current, task_pt_regs(current));
+	preempt_enable();
+}
 #else
 static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
@@ -68,6 +82,56 @@ static __always_inline bool has_fpu(void) { return false; }
 #define __switch_to_aux(__prev, __next) do { } while (0)
 #endif
 
+#ifdef CONFIG_VECTOR
+extern void __vstate_save(struct task_struct *save_to);
+extern void __vstate_restore(struct task_struct *restore_from);
+
+static inline void __vstate_clean(struct pt_regs *regs)
+{
+	regs->status |= (regs->status & ~(SR_VS)) | SR_VS_CLEAN;
+}
+
+static inline void vstate_save(struct task_struct *task,
+		struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) == SR_VS_DIRTY) {
+		__vstate_save(task);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void vstate_restore(struct task_struct *task,
+		struct pt_regs *regs)
+{
+	if ((regs->status & SR_VS) != SR_VS_OFF) {
+		__vstate_restore(task);
+		__vstate_clean(regs);
+	}
+}
+
+static inline void __switch_to_vector(struct task_struct *prev,
+		struct task_struct *next)
+{
+	struct pt_regs *regs;
+
+	regs = task_pt_regs(prev);
+	if (unlikely(regs->status & SR_SD))
+		vstate_save(prev, regs);
+	vstate_restore(next, task_pt_regs(next));
+}
+
+extern struct static_key_false cpu_hwcap_vector;
+static __always_inline bool has_vector(void)
+{
+	return static_branch_likely(&cpu_hwcap_vector);
+}
+#else
+static __always_inline bool has_vector(void) { return false; }
+#define vstate_save(task, regs) do { } while (0)
+#define vstate_restore(task, regs) do { } while (0)
+#define __switch_to_vector(__prev, __next) do { } while (0)
+#endif
+
 extern struct task_struct *__switch_to(struct task_struct *,
 				       struct task_struct *);
 
@@ -77,6 +141,8 @@ do {							\
 	struct task_struct *__next = (next);		\
 	if (has_fpu())					\
 		__switch_to_aux(__prev, __next);	\
+	if (has_vector())				\
+		__switch_to_vector(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
 
diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h
index d6a7428f6248..3cdb24d3f4ed 100644
--- a/arch/riscv/include/asm/timex.h
+++ b/arch/riscv/include/asm/timex.h
@@ -9,6 +9,10 @@
 #include <asm/csr.h>
 
 typedef unsigned long cycles_t;
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+extern u64 dw_timer_read_counter(void);
+extern void __iomem *sched_io_base;
+#endif
 
 #ifdef CONFIG_RISCV_M_MODE
 
@@ -52,7 +56,18 @@ static inline cycles_t get_cycles(void)
 {
 	return csr_read(CSR_TIME);
 }
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+static inline cycles_t dw_get_cycles(void)
+{
+	if (sched_io_base)
+		return dw_timer_read_counter();
+	else
+		return csr_read(CSR_TIME);
+}
+#define get_cycles dw_get_cycles
+#else
 #define get_cycles get_cycles
+#endif
 
 static inline u32 get_cycles_hi(void)
 {
diff --git a/arch/riscv/include/asm/vdso/gettimeofday.h b/arch/riscv/include/asm/vdso/gettimeofday.h
index 77d9c2f721c4..efbfbb9849da 100644
--- a/arch/riscv/include/asm/vdso/gettimeofday.h
+++ b/arch/riscv/include/asm/vdso/gettimeofday.h
@@ -76,6 +76,26 @@ static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
 	return _vdso_data;
 }
 
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+static inline bool sophgo_vdso_hres_capable(void)
+{
+        return false;
+}
+#define __arch_vdso_hres_capable sophgo_vdso_hres_capable
+
+static inline bool sophgo_vdso_clocksource_ok(const struct vdso_data *vd)
+{
+	return false;
+}
+#define vdso_clocksource_ok sophgo_vdso_clocksource_ok
+
+static inline bool sophgo_vdso_cycles_ok(u64 cycles)
+{
+        return false;
+}
+#define vdso_cycles_ok sophgo_vdso_cycles_ok
+#endif
+
 #ifdef CONFIG_TIME_NS
 static __always_inline
 const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
diff --git a/arch/riscv/include/uapi/asm/elf.h b/arch/riscv/include/uapi/asm/elf.h
index d696d6610231..099434d075a7 100644
--- a/arch/riscv/include/uapi/asm/elf.h
+++ b/arch/riscv/include/uapi/asm/elf.h
@@ -23,6 +23,7 @@ typedef struct user_regs_struct elf_gregset_t;
 typedef __u64 elf_fpreg_t;
 typedef union __riscv_fp_state elf_fpregset_t;
 #define ELF_NFPREG (sizeof(struct __riscv_d_ext_state) / sizeof(elf_fpreg_t))
+#define ELF_NVREG  (sizeof(struct __riscv_v_state) / sizeof(elf_greg_t))
 
 #if __riscv_xlen == 64
 #define ELF_RISCV_R_SYM(r_info)		ELF64_R_SYM(r_info)
diff --git a/arch/riscv/include/uapi/asm/hwcap.h b/arch/riscv/include/uapi/asm/hwcap.h
index 46dc3f5ee99f..c52bb7bbbabe 100644
--- a/arch/riscv/include/uapi/asm/hwcap.h
+++ b/arch/riscv/include/uapi/asm/hwcap.h
@@ -21,5 +21,6 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi/asm/ptrace.h
index 882547f6bd5c..4f03efdac812 100644
--- a/arch/riscv/include/uapi/asm/ptrace.h
+++ b/arch/riscv/include/uapi/asm/ptrace.h
@@ -77,6 +77,14 @@ union __riscv_fp_state {
 	struct __riscv_q_ext_state q;
 };
 
+struct __riscv_v_state {
+	__uint128_t v[32];
+	unsigned long vstart;
+	unsigned long vxsat;
+	unsigned long vxrm;
+	unsigned long vl;
+	unsigned long vtype;
+};
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI_ASM_RISCV_PTRACE_H */
diff --git a/arch/riscv/include/uapi/asm/sigcontext.h b/arch/riscv/include/uapi/asm/sigcontext.h
index 84f2dfcfdbce..f74b3c814423 100644
--- a/arch/riscv/include/uapi/asm/sigcontext.h
+++ b/arch/riscv/include/uapi/asm/sigcontext.h
@@ -17,6 +17,7 @@
 struct sigcontext {
 	struct user_regs_struct sc_regs;
 	union __riscv_fp_state sc_fpregs;
+	struct __riscv_v_state sc_vregs;
 };
 
 #endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index ab333cb792fd..16abad3c2bbd 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/
 
 obj-$(CONFIG_RISCV_M_MODE)	+= traps_misaligned.o
 obj-$(CONFIG_FPU)		+= fpu.o
+obj-$(CONFIG_VECTOR)		+= vector.o
 obj-$(CONFIG_SMP)		+= smpboot.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_SMP)		+= cpu_ops.o
@@ -80,7 +81,7 @@ endif
 obj-$(CONFIG_HOTPLUG_CPU)	+= cpu-hotplug.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_KEXEC_CORE)	+= kexec_relocate.o crash_save_regs.o machine_kexec.o
-obj-$(CONFIG_KEXEC_FILE)	+= elf_kexec.o machine_kexec_file.o
+obj-$(CONFIG_KEXEC_FILE)	+= elf_kexec.o image_kexec.o machine_kexec_file.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index df9444397908..5eda9f993dee 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -71,6 +71,44 @@ void asm_offsets(void)
 	OFFSET(TASK_THREAD_F30, task_struct, thread.fstate.f[30]);
 	OFFSET(TASK_THREAD_F31, task_struct, thread.fstate.f[31]);
 	OFFSET(TASK_THREAD_FCSR, task_struct, thread.fstate.fcsr);
+	OFFSET(TASK_THREAD_V0,  task_struct, thread.vstate.v[0]);
+	OFFSET(TASK_THREAD_V1,  task_struct, thread.vstate.v[1]);
+	OFFSET(TASK_THREAD_V2,  task_struct, thread.vstate.v[2]);
+	OFFSET(TASK_THREAD_V3,  task_struct, thread.vstate.v[3]);
+	OFFSET(TASK_THREAD_V4,  task_struct, thread.vstate.v[4]);
+	OFFSET(TASK_THREAD_V5,  task_struct, thread.vstate.v[5]);
+	OFFSET(TASK_THREAD_V6,  task_struct, thread.vstate.v[6]);
+	OFFSET(TASK_THREAD_V7,  task_struct, thread.vstate.v[7]);
+	OFFSET(TASK_THREAD_V8,  task_struct, thread.vstate.v[8]);
+	OFFSET(TASK_THREAD_V9,  task_struct, thread.vstate.v[9]);
+	OFFSET(TASK_THREAD_V10, task_struct, thread.vstate.v[10]);
+	OFFSET(TASK_THREAD_V11, task_struct, thread.vstate.v[11]);
+	OFFSET(TASK_THREAD_V12, task_struct, thread.vstate.v[12]);
+	OFFSET(TASK_THREAD_V13, task_struct, thread.vstate.v[13]);
+	OFFSET(TASK_THREAD_V14, task_struct, thread.vstate.v[14]);
+	OFFSET(TASK_THREAD_V15, task_struct, thread.vstate.v[15]);
+	OFFSET(TASK_THREAD_V16, task_struct, thread.vstate.v[16]);
+	OFFSET(TASK_THREAD_V17, task_struct, thread.vstate.v[17]);
+	OFFSET(TASK_THREAD_V18, task_struct, thread.vstate.v[18]);
+	OFFSET(TASK_THREAD_V19, task_struct, thread.vstate.v[19]);
+	OFFSET(TASK_THREAD_V20, task_struct, thread.vstate.v[20]);
+	OFFSET(TASK_THREAD_V21, task_struct, thread.vstate.v[21]);
+	OFFSET(TASK_THREAD_V22, task_struct, thread.vstate.v[22]);
+	OFFSET(TASK_THREAD_V23, task_struct, thread.vstate.v[23]);
+	OFFSET(TASK_THREAD_V24, task_struct, thread.vstate.v[24]);
+	OFFSET(TASK_THREAD_V25, task_struct, thread.vstate.v[25]);
+	OFFSET(TASK_THREAD_V26, task_struct, thread.vstate.v[26]);
+	OFFSET(TASK_THREAD_V27, task_struct, thread.vstate.v[27]);
+	OFFSET(TASK_THREAD_V28, task_struct, thread.vstate.v[28]);
+	OFFSET(TASK_THREAD_V29, task_struct, thread.vstate.v[29]);
+	OFFSET(TASK_THREAD_V30, task_struct, thread.vstate.v[30]);
+	OFFSET(TASK_THREAD_V31, task_struct, thread.vstate.v[31]);
+	OFFSET(TASK_THREAD_VSTART, task_struct, thread.vstate.vstart);
+	OFFSET(TASK_THREAD_VXSAT, task_struct, thread.vstate.vxsat);
+	OFFSET(TASK_THREAD_VXRM, task_struct, thread.vstate.vxrm);
+	OFFSET(TASK_THREAD_VL, task_struct, thread.vstate.vl);
+	OFFSET(TASK_THREAD_VTYPE, task_struct, thread.vstate.vtype);
+	DEFINE(RISCV_VECTOR_VLENB, sizeof(__uint128_t));
 #ifdef CONFIG_STACKPROTECTOR
 	OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
 #endif
@@ -332,6 +370,7 @@ void asm_offsets(void)
 		- offsetof(struct task_struct, thread.ra)
 	);
 
+	/* Float Point */
 	DEFINE(TASK_THREAD_F0_F0,
 		  offsetof(struct task_struct, thread.fstate.f[0])
 		- offsetof(struct task_struct, thread.fstate.f[0])
@@ -465,6 +504,156 @@ void asm_offsets(void)
 		- offsetof(struct task_struct, thread.fstate.f[0])
 	);
 
+	/* Vector */
+	DEFINE(TASK_THREAD_V0_V0,
+		  offsetof(struct task_struct, thread.vstate.v[0])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V1_V0,
+		  offsetof(struct task_struct, thread.vstate.v[1])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V2_V0,
+		  offsetof(struct task_struct, thread.vstate.v[2])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V3_V0,
+		  offsetof(struct task_struct, thread.vstate.v[3])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V4_V0,
+		  offsetof(struct task_struct, thread.vstate.v[4])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V5_V0,
+		  offsetof(struct task_struct, thread.vstate.v[5])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V6_V0,
+		  offsetof(struct task_struct, thread.vstate.v[6])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V7_V0,
+		  offsetof(struct task_struct, thread.vstate.v[7])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V8_V0,
+		  offsetof(struct task_struct, thread.vstate.v[8])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V9_V0,
+		  offsetof(struct task_struct, thread.vstate.v[9])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V10_V0,
+		  offsetof(struct task_struct, thread.vstate.v[10])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V11_V0,
+		  offsetof(struct task_struct, thread.vstate.v[11])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V12_V0,
+		  offsetof(struct task_struct, thread.vstate.v[12])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V13_V0,
+		  offsetof(struct task_struct, thread.vstate.v[13])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V14_V0,
+		  offsetof(struct task_struct, thread.vstate.v[14])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V15_V0,
+		  offsetof(struct task_struct, thread.vstate.v[15])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V16_V0,
+		  offsetof(struct task_struct, thread.vstate.v[16])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V17_V0,
+		  offsetof(struct task_struct, thread.vstate.v[17])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V18_V0,
+		  offsetof(struct task_struct, thread.vstate.v[18])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V19_V0,
+		  offsetof(struct task_struct, thread.vstate.v[19])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V20_V0,
+		  offsetof(struct task_struct, thread.vstate.v[20])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V21_V0,
+		  offsetof(struct task_struct, thread.vstate.v[21])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V22_V0,
+		  offsetof(struct task_struct, thread.vstate.v[22])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V23_V0,
+		  offsetof(struct task_struct, thread.vstate.v[23])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V24_V0,
+		  offsetof(struct task_struct, thread.vstate.v[24])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V25_V0,
+		  offsetof(struct task_struct, thread.vstate.v[25])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V26_V0,
+		  offsetof(struct task_struct, thread.vstate.v[26])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V27_V0,
+		  offsetof(struct task_struct, thread.vstate.v[27])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V28_V0,
+		  offsetof(struct task_struct, thread.vstate.v[28])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V29_V0,
+		  offsetof(struct task_struct, thread.vstate.v[29])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V30_V0,
+		  offsetof(struct task_struct, thread.vstate.v[30])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_V31_V0,
+		  offsetof(struct task_struct, thread.vstate.v[31])
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_VSTART_V0,
+		  offsetof(struct task_struct, thread.vstate.vstart)
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_VXSAT_V0,
+		  offsetof(struct task_struct, thread.vstate.vxsat)
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_VXRM_V0,
+		  offsetof(struct task_struct, thread.vstate.vxrm)
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_VL_V0,
+		  offsetof(struct task_struct, thread.vstate.vl)
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+	DEFINE(TASK_THREAD_VTYPE_V0,
+		  offsetof(struct task_struct, thread.vstate.vtype)
+		- offsetof(struct task_struct, thread.vstate.v[0])
+	);
+
 	/*
 	 * We allocate a pt_regs on the stack when entering the kernel.  This
 	 * ensures the alignment is sane.
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 0f76181dc634..ea60013702d9 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -71,8 +71,6 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid)
 	return -1;
 }
 
-#ifdef CONFIG_PROC_FS
-
 struct riscv_cpuinfo {
 	unsigned long mvendorid;
 	unsigned long marchid;
@@ -80,6 +78,30 @@ struct riscv_cpuinfo {
 };
 static DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
+unsigned long riscv_cached_mvendorid(unsigned int cpu_id)
+{
+	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
+
+	return ci->mvendorid;
+}
+EXPORT_SYMBOL(riscv_cached_mvendorid);
+
+unsigned long riscv_cached_marchid(unsigned int cpu_id)
+{
+	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
+
+	return ci->marchid;
+}
+EXPORT_SYMBOL(riscv_cached_marchid);
+
+unsigned long riscv_cached_mimpid(unsigned int cpu_id)
+{
+	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);
+
+	return ci->mimpid;
+}
+EXPORT_SYMBOL(riscv_cached_mimpid);
+
 static int riscv_cpuinfo_starting(unsigned int cpu)
 {
 	struct riscv_cpuinfo *ci = this_cpu_ptr(&riscv_cpuinfo);
@@ -114,7 +136,9 @@ static int __init riscv_cpuinfo_init(void)
 
 	return 0;
 }
-device_initcall(riscv_cpuinfo_init);
+arch_initcall(riscv_cpuinfo_init);
+
+#ifdef CONFIG_PROC_FS
 
 #define __RISCV_ISA_EXT_DATA(UPROP, EXTID) \
 	{							\
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index fd1238df6149..8dd51087cf94 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2017 SiFive
  */
 
+#include <linux/init.h>
 #include <linux/bitmap.h>
 #include <linux/ctype.h>
 #include <linux/libfdt.h>
@@ -25,6 +26,7 @@
 #define NUM_ALPHA_EXTS ('z' - 'a' + 1)
 
 unsigned long elf_hwcap __read_mostly;
+static bool hide_v0p7 = 0;
 
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
@@ -32,6 +34,19 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 DEFINE_STATIC_KEY_ARRAY_FALSE(riscv_isa_ext_keys, RISCV_ISA_EXT_KEY_MAX);
 EXPORT_SYMBOL(riscv_isa_ext_keys);
 
+#ifdef CONFIG_VECTOR
+__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_vector);
+
+static int __init do_hide_v0p7_ext(char *str)
+{
+	hide_v0p7 = 1;
+
+	pr_notice("Hide vector 0.7 extension\n");
+	return 0;
+}
+early_param("hide_v0p7_ext", do_hide_v0p7_ext);
+#endif
+
 /**
  * riscv_isa_extension_base() - Get base extension word
  *
@@ -84,6 +99,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap['v'] = isa2hwcap['V'] = COMPAT_HWCAP_ISA_V;
 
 	elf_hwcap = 0;
 
@@ -250,6 +266,15 @@ void __init riscv_fill_hwcap(void)
 		if (j >= 0)
 			static_branch_enable(&riscv_isa_ext_keys[j]);
 	}
+
+	#ifdef CONFIG_VECTOR
+	if (elf_hwcap & COMPAT_HWCAP_ISA_V)
+		static_branch_enable(&cpu_hwcap_vector);
+	if (hide_v0p7) {
+		bitmap_clear(riscv_isa, RISCV_ISA_EXT_v, RISCV_ISA_EXT_MAX);
+		elf_hwcap &= ~COMPAT_HWCAP_ISA_V;
+	}
+	#endif
 }
 
 #ifdef CONFIG_RISCV_ALTERNATIVE
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 3221a9e5f372..591933cd022d 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -80,7 +80,7 @@ _save_context:
 	 * Disable the FPU to detect illegal usage of floating point in kernel
 	 * space.
 	 */
-	li t0, SR_SUM | SR_FS
+	li t0, SR_SUM | SR_FS | SR_VS
 
 	REG_L s0, TASK_TI_USER_SP(tp)
 	csrrc s1, CSR_STATUS, t0
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 4bf6c449d78b..01002fad45f4 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -143,7 +143,7 @@ secondary_start_sbi:
 	 * Disable FPU to detect illegal usage of
 	 * floating point in kernel space
 	 */
-	li t0, SR_FS
+	li t0, SR_FS | SR_VS
 	csrc CSR_STATUS, t0
 
 	/* Set trap vector to spin forever to help debug */
@@ -237,7 +237,7 @@ pmp_done:
 	 * Disable FPU to detect illegal usage of
 	 * floating point in kernel space
 	 */
-	li t0, SR_FS
+	li t0, SR_FS | SR_VS
 	csrc CSR_STATUS, t0
 
 #ifdef CONFIG_RISCV_BOOT_SPINWAIT
diff --git a/arch/riscv/kernel/image_kexec.c b/arch/riscv/kernel/image_kexec.c
new file mode 100644
index 000000000000..b0c0aad64c36
--- /dev/null
+++ b/arch/riscv/kernel/image_kexec.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader
+
+ * Adapted from arch/arm64/kernel/kexec_image.c
+ * Copyright (C) 2018 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+#define pr_fmt(fmt)	"kexec_file(Image): " fmt
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/pe.h>
+#include <linux/string.h>
+#include <linux/verification.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+#include <linux/slab.h>
+#include <linux/memblock.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/image.h>
+
+static int prepare_elf_headers(void **addr, unsigned long *sz)
+{
+	struct crash_mem *cmem;
+	unsigned int nr_ranges;
+	int ret;
+	u64 i;
+	phys_addr_t start, end;
+
+	nr_ranges = 2; /* for exclusion of crashkernel region */
+	for_each_mem_range(i, &start, &end)
+		nr_ranges++;
+
+	cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
+	if (!cmem)
+		return -ENOMEM;
+
+	cmem->max_nr_ranges = nr_ranges;
+	cmem->nr_ranges = 0;
+	for_each_mem_range(i, &start, &end) {
+		cmem->ranges[cmem->nr_ranges].start = start;
+		cmem->ranges[cmem->nr_ranges].end = end - 1;
+		cmem->nr_ranges++;
+	}
+
+	/* Exclude crashkernel region */
+	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	if (ret)
+		goto out;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			goto out;
+	}
+
+	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
+
+out:
+	kfree(cmem);
+	return ret;
+}
+
+/*
+ * Tries to add the initrd and DTB to the image. If it is not possible to find
+ * valid locations, this function will undo changes to the image and return non
+ * zero.
+ */
+static int load_other_segments(struct kimage *image,
+			unsigned long kernel_load_addr,
+			unsigned long kernel_size,
+			char *initrd, unsigned long initrd_len,
+			char *cmdline)
+{
+	struct kexec_buf kbuf;
+	void *headers, *fdt = NULL;
+	unsigned long headers_sz, initrd_load_addr = 0,
+		      orig_segments = image->nr_segments;
+	int ret = 0;
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = kernel_load_addr + kernel_size;
+
+	/* load elf core header */
+	if (image->type == KEXEC_TYPE_CRASH) {
+		ret = prepare_elf_headers(&headers, &headers_sz);
+		if (ret) {
+			pr_err("Preparing elf core header failed\n");
+			goto out_err;
+		}
+
+		kbuf.buffer = headers;
+		kbuf.bufsz = headers_sz;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = headers_sz;
+		kbuf.buf_align = PAGE_SIZE;
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = true;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret) {
+			vfree(headers);
+			goto out_err;
+		}
+		image->elf_headers = headers;
+		image->elf_load_addr = kbuf.mem;
+		image->elf_headers_sz = headers_sz;
+
+		pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			 image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
+	}
+
+	/* load initrd */
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = PAGE_SIZE;
+		/* avoid to overlap kernel address */
+		kbuf.buf_min = round_up(kernel_load_addr, SZ_1G);
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+		initrd_load_addr = kbuf.mem;
+
+		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+				initrd_load_addr, kbuf.bufsz, kbuf.memsz);
+	}
+
+	/* load dtb */
+	fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr,
+					   initrd_len, cmdline, 0);
+	if (!fdt) {
+		pr_err("Preparing for new dtb failed\n");
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	/* trim it */
+	fdt_pack(fdt);
+	kbuf.buffer = fdt;
+	kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt);
+	kbuf.buf_align = PAGE_SIZE;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.top_down = false;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		goto out_err;
+	/* Cache the fdt buffer address for memory cleanup */
+	image->arch.fdt = fdt;
+	image->arch.fdt_addr = kbuf.mem;
+
+	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+	return 0;
+
+out_err:
+	image->nr_segments = orig_segments;
+	kvfree(fdt);
+	return ret;
+}
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct riscv_image_header *h =
+		(const struct riscv_image_header *)(kernel_buf);
+
+	if (!h || (kernel_len < sizeof(*h)))
+		return -EINVAL;
+
+	if (memcmp(&h->magic2, RISCV_IMAGE_MAGIC2, sizeof(h->magic2)))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void *image_load(struct kimage *image,
+				char *kernel, unsigned long kernel_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct riscv_image_header *h;
+	u64 flags;
+	bool be_image, be_kernel;
+	struct kexec_buf kbuf;
+	unsigned long text_offset, kernel_segment_number;
+	unsigned long kernel_start;
+	struct kexec_segment *kernel_segment;
+	int ret;
+
+	h = (struct riscv_image_header *)kernel;
+	if (!h->image_size)
+		return ERR_PTR(-EINVAL);
+
+	/* Check cpu features */
+	flags = le64_to_cpu(h->flags);
+	be_image = __HEAD_FLAG(BE);
+	be_kernel = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
+	if (be_image != be_kernel)
+		return ERR_PTR(-EINVAL);
+
+	/* Load the kernel */
+	kbuf.image = image;
+	kbuf.buf_min = 0;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	kbuf.buffer = kernel;
+	kbuf.bufsz = kernel_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = le64_to_cpu(h->image_size);
+	text_offset = le64_to_cpu(h->text_offset);
+	kbuf.buf_align = PAGE_SIZE;
+
+	/* Adjust kernel segment with TEXT_OFFSET */
+	kbuf.memsz += text_offset;
+
+	kernel_segment_number = image->nr_segments;
+
+	/*
+	 * The location of the kernel segment may make it impossible to satisfy
+	 * the other segment requirements, so we try repeatedly to find a
+	 * location that will work.
+	 */
+	while ((ret = kexec_add_buffer(&kbuf)) == 0) {
+		/* Try to load additional data */
+		kernel_segment = &image->segment[kernel_segment_number];
+		ret = load_other_segments(image, kernel_segment->mem,
+					  kernel_segment->memsz, initrd,
+					  initrd_len, cmdline);
+		if (!ret)
+			break;
+
+		/*
+		 * We couldn't find space for the other segments; erase the
+		 * kernel segment and try the next available hole.
+		 */
+		image->nr_segments -= 1;
+		kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	}
+
+	if (ret) {
+		pr_err("Could not find any suitable kernel location!");
+		return ERR_PTR(ret);
+	}
+
+	kernel_segment = &image->segment[kernel_segment_number];
+	kernel_segment->mem += text_offset;
+	kernel_segment->memsz -= text_offset;
+	kernel_start = kernel_segment->mem;
+	image->start = kernel_start;
+
+
+	pr_debug("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+				kernel_segment->mem, kbuf.bufsz,
+				kernel_segment->memsz);
+
+#ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY
+	/* Add purgatory to the image */
+	kbuf.top_down = true;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	ret = kexec_load_purgatory(image, &kbuf);
+	if (ret) {
+		pr_err("Error loading purgatory ret=%d\n", ret);
+		return ERR_PTR(ret);
+	}
+	ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry",
+					     &kernel_start,
+					     sizeof(kernel_start), 0);
+	if (ret)
+		pr_err("Error update purgatory ret=%d\n", ret);
+#endif /* CONFIG_ARCH_HAS_KEXEC_PURGATORY */
+
+	return ret ? ERR_PTR(ret) : NULL;
+}
+
+#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
+static int image_verify_sig(const char *kernel, unsigned long kernel_len)
+{
+	return verify_pefile_signature(kernel, kernel_len, NULL,
+				       VERIFYING_KEXEC_PE_SIGNATURE);
+}
+#endif
+
+const struct kexec_file_ops image_kexec_ops = {
+	.probe = image_probe,
+	.load = image_load,
+#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
+	.verify_sig = image_verify_sig,
+#endif
+};
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index b0bf8c1722c0..401edfd1774f 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -9,6 +9,7 @@
 #include <linux/kexec.h>
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
+	&image_kexec_ops,
 	&elf_kexec_ops,
 	NULL
 };
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c
index a331001e33e6..2f339f52c7c1 100644
--- a/arch/riscv/kernel/module.c
+++ b/arch/riscv/kernel/module.c
@@ -321,6 +321,45 @@ static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
 	[R_RISCV_SUB64]			= apply_r_riscv_sub64_rela,
 };
 
+static inline unsigned int apply_calc_pcrel_lo12(Elf_Shdr *sechdrs,
+			Elf_Rela *rel, Elf_Sym *sym, unsigned int idx,
+			unsigned int symindex, unsigned int relsec,
+			struct module *me, Elf_Addr *v)
+{
+	unsigned long hi20_loc =
+		sechdrs[sechdrs[relsec].sh_info].sh_addr
+		+ rel[idx].r_offset;
+	u32 hi20_type = ELF_RISCV_R_TYPE(rel[idx].r_info);
+	unsigned int found = 0;
+
+	/* Find the corresponding HI20 relocation entry */
+	if (hi20_loc == sym->st_value
+	    && (hi20_type == R_RISCV_PCREL_HI20
+		|| hi20_type == R_RISCV_GOT_HI20)) {
+		s32 hi20, lo12;
+		Elf_Sym *hi20_sym =
+			(Elf_Sym *)sechdrs[symindex].sh_addr
+			+ ELF_RISCV_R_SYM(rel[idx].r_info);
+		unsigned long hi20_sym_val =
+			hi20_sym->st_value + rel[idx].r_addend;
+
+		/* Calculate lo12 */
+		size_t offset = hi20_sym_val - hi20_loc;
+		if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
+		    && hi20_type == R_RISCV_GOT_HI20) {
+			offset = module_emit_got_entry(me, hi20_sym_val);
+			offset = offset - hi20_loc;
+		}
+		hi20 = (offset + 0x800) & 0xfffff000;
+		lo12 = offset - hi20;
+		*v = (Elf_Addr)lo12;
+
+		found = 1;
+	}
+
+	return found;
+}
+
 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 		       unsigned int symindex, unsigned int relsec,
 		       struct module *me)
@@ -369,40 +408,24 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 
 		if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
 			unsigned int j;
+			unsigned int found = 0;
 
-			for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
-				unsigned long hi20_loc =
-					sechdrs[sechdrs[relsec].sh_info].sh_addr
-					+ rel[j].r_offset;
-				u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
-
-				/* Find the corresponding HI20 relocation entry */
-				if (hi20_loc == sym->st_value
-				    && (hi20_type == R_RISCV_PCREL_HI20
-					|| hi20_type == R_RISCV_GOT_HI20)) {
-					s32 hi20, lo12;
-					Elf_Sym *hi20_sym =
-						(Elf_Sym *)sechdrs[symindex].sh_addr
-						+ ELF_RISCV_R_SYM(rel[j].r_info);
-					unsigned long hi20_sym_val =
-						hi20_sym->st_value
-						+ rel[j].r_addend;
-
-					/* Calculate lo12 */
-					size_t offset = hi20_sym_val - hi20_loc;
-					if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
-					    && hi20_type == R_RISCV_GOT_HI20) {
-						offset = module_emit_got_entry(
-							 me, hi20_sym_val);
-						offset = offset - hi20_loc;
-					}
-					hi20 = (offset + 0x800) & 0xfffff000;
-					lo12 = offset - hi20;
-					v = lo12;
+			if (i > 0) {
+				j  = i - 1;
+				found = apply_calc_pcrel_lo12(sechdrs, rel, sym, j,
+							symindex, relsec, me, &v);
+			}
 
-					break;
+			if (found == 0) {
+				for (j = 0; j < sechdrs[relsec].sh_size/sizeof(*rel); j++) {
+					found = apply_calc_pcrel_lo12(sechdrs, rel, sym,
+							j, symindex, relsec, me, &v);
+					if (found) {
+						break;
+					}
 				}
 			}
+
 			if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
 				pr_err(
 				  "%s: Can not find HI20 relocation information\n",
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 8955f2432c2d..daa9ab70d68f 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -124,6 +124,12 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 		 */
 		fstate_restore(current, regs);
 	}
+
+	if (has_vector()) {
+		regs->status |= SR_VS_INITIAL;
+		vstate_restore(current, regs);
+	}
+
 	regs->epc = pc;
 	regs->sp = sp;
 
@@ -189,3 +195,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 	p->thread.sp = (unsigned long)childregs; /* kernel sp */
 	return 0;
 }
+
+EXPORT_SYMBOL_GPL(__fstate_save);
+EXPORT_SYMBOL_GPL(__fstate_restore);
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index 2ae8280ae475..031ca9bc2c5e 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -27,6 +27,9 @@ enum riscv_regset {
 #ifdef CONFIG_FPU
 	REGSET_F,
 #endif
+#ifdef CONFIG_VECTOR
+	REGSET_V,
+#endif
 };
 
 static int riscv_gpr_get(struct task_struct *target,
@@ -83,6 +86,31 @@ static int riscv_fpr_set(struct task_struct *target,
 }
 #endif
 
+#ifdef CONFIG_VECTOR
+static int riscv_vr_get(struct task_struct *target,
+		const struct user_regset *regset,
+		struct membuf to)
+{
+	struct __riscv_v_state *vstate = &target->thread.vstate;
+
+	membuf_write(&to, vstate, offsetof(struct __riscv_v_state, vtype));
+	return membuf_zero(&to, 4);     // explicitly pad
+}
+
+static int riscv_vr_set(struct task_struct *target,
+		const struct user_regset *regset,
+		unsigned int pos, unsigned int count,
+		const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	struct __riscv_v_state *vstate = &target->thread.vstate;
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vstate, 0,
+			offsetof(struct __riscv_v_state, vtype));
+	return ret;
+}
+#endif
+
 static const struct user_regset riscv_user_regset[] = {
 	[REGSET_X] = {
 		.core_note_type = NT_PRSTATUS,
@@ -102,6 +130,16 @@ static const struct user_regset riscv_user_regset[] = {
 		.set = riscv_fpr_set,
 	},
 #endif
+#ifdef CONFIG_VECTOR
+	[REGSET_V] = {
+		.core_note_type = NT_RISCV_VECTOR,
+		.n = ELF_NVREG,
+		.size = sizeof(elf_greg_t),
+		.align = sizeof(elf_greg_t),
+		.regset_get = riscv_vr_get,
+		.set = riscv_vr_set,
+	},
+#endif
 };
 
 static const struct user_regset_view riscv_user_native_view = {
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index dee66c9290cc..e9b18563fc17 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -87,6 +87,40 @@ static long save_fp_state(struct pt_regs *regs,
 #define restore_fp_state(task, regs) (0)
 #endif
 
+#ifdef CONFIG_VECTOR
+static long restore_v_state(struct pt_regs *regs,
+		struct __riscv_v_state *sc_vregs)
+{
+	long err;
+	struct __riscv_v_state __user *state = sc_vregs;
+
+	err = __copy_from_user(&current->thread.vstate, state, sizeof(*state));
+	if (unlikely(err))
+		return err;
+
+	vstate_restore(current, regs);
+
+	return err;
+}
+
+static long save_v_state(struct pt_regs *regs,
+		struct __riscv_v_state *sc_vregs)
+{
+	long err;
+	struct __riscv_v_state __user *state = sc_vregs;
+
+	vstate_save(current, regs);
+	err = __copy_to_user(state, &current->thread.vstate, sizeof(*state));
+	if (unlikely(err))
+		return err;
+
+	return err;
+}
+#else
+#define save_v_state(task, regs) (0)
+#define restore_v_state(task, regs) (0)
+#endif
+
 static long restore_sigcontext(struct pt_regs *regs,
 	struct sigcontext __user *sc)
 {
@@ -96,6 +130,9 @@ static long restore_sigcontext(struct pt_regs *regs,
 	/* Restore the floating-point state. */
 	if (has_fpu())
 		err |= restore_fp_state(regs, &sc->sc_fpregs);
+	/* Restore the vector state. */
+	if (has_vector())
+		err |= restore_v_state(regs, &sc->sc_vregs);
 	return err;
 }
 
@@ -151,6 +188,9 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	/* Save the floating-point state. */
 	if (has_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
+	/* Save the vector state. */
+	if (has_vector())
+		err |= save_v_state(regs, &sc->sc_vregs);
 	return err;
 }
 
diff --git a/arch/riscv/kernel/vector.S b/arch/riscv/kernel/vector.S
new file mode 100644
index 000000000000..00ee1db0cb1e
--- /dev/null
+++ b/arch/riscv/kernel/vector.S
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ * Copyright (C) 2019 T-HEAD
+ *
+ *   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, version 2.
+ *
+ *   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.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm.h>
+#include <asm/csr.h>
+#include <asm/asm-offsets.h>
+
+ENTRY(__vstate_save)
+	li	a2,  TASK_THREAD_V0
+	add	a0,  a0, a2
+
+	li	t1, (SR_VS | SR_FS)
+	csrs	sstatus, t1
+
+	csrr	t0,  CSR_VSTART
+	sd	t0,  TASK_THREAD_VSTART_V0(a0)
+	csrr	t0,  CSR_VXSAT
+	sd	t0,  TASK_THREAD_VXSAT_V0(a0)
+	csrr	t0,  CSR_VXRM
+	sd	t0,  TASK_THREAD_VXRM_V0(a0)
+	csrr	t0,  CSR_VL
+	sd	t0,  TASK_THREAD_VL_V0(a0)
+	csrr	t0,  CSR_VTYPE
+	sd	t0,  TASK_THREAD_VTYPE_V0(a0)
+
+	.word 0x003072d7 	/* vsetvli	t0, x0, e8,m8 	*/
+	.word 0x02050027 	/* vsb.v	v0,  (a0)	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x02050427 	/* vsb.v	v8,  (a0) 	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x02050827 	/* vsb.v	v16, (a0) 	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x02050c27 	/* vsb.v	v24, (a0) 	*/
+
+	csrc	sstatus, t1
+	ret
+ENDPROC(__vstate_save)
+
+ENTRY(__vstate_restore)
+	li	a2,  TASK_THREAD_V0
+	add	a0,  a0, a2
+	mv	t2,  a0
+
+	li	t1, (SR_VS | SR_FS)
+	csrs	sstatus, t1
+
+	.word 0x003072d7	/* vsetvli	t0, x0, e8,m8 	*/
+	.word 0x12050007	/* vlb.v	v0,  (a0) 	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x12050407	/* vlb.v	v8,  (a0)	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x12050807 	/* vlb.v	v16, (a0)	*/
+	addi	a0, a0, RISCV_VECTOR_VLENB*8
+	.word 0x12050c07	/* vlb.v	v24, (a0)	*/
+
+	mv	a0,  t2
+	ld	t0,  TASK_THREAD_VSTART_V0(a0)
+	csrw	CSR_VSTART, t0
+	ld	t0,  TASK_THREAD_VXSAT_V0(a0)
+	csrw	CSR_VXSAT, t0
+	ld	t0,  TASK_THREAD_VXRM_V0(a0)
+	csrw	CSR_VXRM, t0
+	ld	t0,  TASK_THREAD_VL_V0(a0)
+	ld	t2,  TASK_THREAD_VTYPE_V0(a0)
+	.word 0x8072fe57 	/* vsetvl	t3, t0, t2	*/
+	.word 0x32002057	/* vmv.x.s 	zero, v0	*/
+
+	csrc	sstatus, t1
+	ret
+ENDPROC(__vstate_restore)
diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c
index 3ac2ff6a65da..3e976b3084e1 100644
--- a/arch/riscv/kvm/vcpu_timer.c
+++ b/arch/riscv/kvm/vcpu_timer.c
@@ -15,6 +15,10 @@
 #include <asm/delay.h>
 #include <asm/kvm_vcpu_timer.h>
 
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+extern void dw_cs_get_mult_shift(u32 *mult, u32 *shift);
+#endif
+
 static u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt)
 {
 	return get_cycles64() + gt->time_delta;
@@ -357,6 +361,10 @@ void kvm_riscv_guest_timer_init(struct kvm *kvm)
 {
 	struct kvm_guest_timer *gt = &kvm->arch.timer;
 
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+	dw_cs_get_mult_shift(&gt->nsec_mult, &gt->nsec_shift);
+#else
 	riscv_cs_get_mult_shift(&gt->nsec_mult, &gt->nsec_shift);
+#endif
 	gt->time_delta = -get_cycles64();
 }
diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c
index 8a2e7040f8fc..fcd6145fbead 100644
--- a/arch/riscv/mm/cacheflush.c
+++ b/arch/riscv/mm/cacheflush.c
@@ -83,6 +83,13 @@ void flush_icache_pte(pte_t pte)
 {
 	struct page *page = pte_page(pte);
 
+	/*
+	 * HugeTLB pages are always fully mapped, so only setting head page's
+	 * PG_dcache_clean flag is enough.
+	 */
+	if (PageHuge(page))
+		page = compound_head(page);
+
 	if (!test_bit(PG_dcache_clean, &page->flags)) {
 		flush_icache_all();
 		set_bit(PG_dcache_clean, &page->flags);
diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c
index 12e22e7330e7..af490e613bd3 100644
--- a/arch/riscv/mm/context.c
+++ b/arch/riscv/mm/context.c
@@ -12,11 +12,21 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/static_key.h>
+#include <linux/init.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_MMU
+static bool __read_mostly noasid;
+static int __init early_noasid(char *str)
+{
+       noasid = true;
+       pr_notice("ASID disabled!\n");
+
+       return 0;
+}
+early_param("noasid", early_noasid);
 
 DEFINE_STATIC_KEY_FALSE(use_asid_allocator);
 
@@ -274,7 +284,18 @@ static int __init asids_init(void)
 
 	return 0;
 }
-early_initcall(asids_init);
+
+static int  __init init_asids(void)
+{
+       int ret = 0;
+
+       if (!noasid)
+               ret = asids_init();
+
+       return ret;
+}
+early_initcall(init_asids);
+
 #else
 static inline void set_mm(struct mm_struct *prev,
 			  struct mm_struct *next, unsigned int cpu)
diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c
index d919efab6eba..0ad0614d1ad4 100644
--- a/arch/riscv/mm/dma-noncoherent.c
+++ b/arch/riscv/mm/dma-noncoherent.c
@@ -19,13 +19,13 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 
 	switch (dir) {
 	case DMA_TO_DEVICE:
-		ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size);
+		ALT_CMO_OP_VPA(clean, vaddr, paddr, size, riscv_cbom_block_size);
 		break;
 	case DMA_FROM_DEVICE:
-		ALT_CMO_OP(clean, vaddr, size, riscv_cbom_block_size);
+		ALT_CMO_OP_VPA(clean, vaddr, paddr, size, riscv_cbom_block_size);
 		break;
 	case DMA_BIDIRECTIONAL:
-		ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size);
+		ALT_CMO_OP_VPA(flush, vaddr, paddr, size, riscv_cbom_block_size);
 		break;
 	default:
 		break;
@@ -42,7 +42,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 		break;
 	case DMA_FROM_DEVICE:
 	case DMA_BIDIRECTIONAL:
-		ALT_CMO_OP(flush, vaddr, size, riscv_cbom_block_size);
+		ALT_CMO_OP_VPA(flush, vaddr, paddr, size, riscv_cbom_block_size);
 		break;
 	default:
 		break;
@@ -52,8 +52,9 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 void arch_dma_prep_coherent(struct page *page, size_t size)
 {
 	void *flush_addr = page_address(page);
+	phys_addr_t paddr = PFN_PHYS(page_to_pfn(page));
 
-	ALT_CMO_OP(flush, flush_addr, size, riscv_cbom_block_size);
+	ALT_CMO_OP_VPA(flush, flush_addr, paddr, size, riscv_cbom_block_size);
 }
 
 void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c
index 274bc6dd839f..89226458eab8 100644
--- a/arch/riscv/mm/fault.c
+++ b/arch/riscv/mm/fault.c
@@ -152,6 +152,8 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
 		no_context(regs, addr);
 		return;
 	}
+	if (pud_leaf(*pud_k))
+		goto flush_tlb;
 
 	/*
 	 * Since the vmalloc area is global, it is unnecessary
@@ -162,6 +164,8 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
 		no_context(regs, addr);
 		return;
 	}
+	if (pmd_leaf(*pmd_k))
+		goto flush_tlb;
 
 	/*
 	 * Make sure the actual PTE exists as well to
@@ -181,6 +185,7 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
 	 * ordering constraint, not a cache flush; it is
 	 * necessary even after writing invalid entries.
 	 */
+flush_tlb:
 	local_flush_tlb_page(addr);
 }
 
@@ -321,8 +326,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
 	 * signal first. We do not need to release the mmap_lock because it
 	 * would already be released in __lock_page_or_retry in mm/filemap.c.
 	 */
-	if (fault_signal_pending(fault, regs))
+	if (fault_signal_pending(fault, regs)) {
+		if (!user_mode(regs))
+			no_context(regs, addr);
 		return;
+	}
 
 	/* The fault is fully completed (including releasing mmap lock) */
 	if (fault & VM_FAULT_COMPLETED)
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 7c4852af9e3f..18bcb2e77a16 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -31,6 +31,11 @@
 
 #include "../kernel/head.h"
 
+#ifdef CONFIG_HIGHMEM
+#include <asm/highmem.h>
+extern phys_addr_t __init_memblock find_max_low_addr(phys_addr_t limit);
+#endif
+
 struct kernel_mapping kernel_map __ro_after_init;
 EXPORT_SYMBOL(kernel_map);
 #ifdef CONFIG_XIP_KERNEL
@@ -70,6 +75,9 @@ static void __init zone_sizes_init(void)
 	max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit);
 #endif
 	max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
+	max_zone_pfns[ZONE_HIGHMEM] = max_pfn;
+#endif
 
 	free_area_init(max_zone_pfns);
 }
@@ -126,6 +134,10 @@ static inline void print_ml(char *name, unsigned long b, unsigned long t)
 static void __init print_vm_layout(void)
 {
 	pr_notice("Virtual kernel memory layout:\n");
+#ifdef CONFIG_HIGHMEM
+	print_ml("pkmap", (unsigned long)PKMAP_BASE,
+		(unsigned long)FIXADDR_START);
+#endif
 	print_ml("fixmap", (unsigned long)FIXADDR_START,
 		(unsigned long)FIXADDR_TOP);
 	print_ml("pci io", (unsigned long)PCI_IO_START,
@@ -153,6 +165,106 @@ static void __init print_vm_layout(void)
 static void print_vm_layout(void) { }
 #endif /* CONFIG_DEBUG_VM */
 
+#ifdef CONFIG_HIGHMEM
+
+#ifdef CONFIG_DEBUG_VM
+#error Please unset CONFIG_DEBUG_VM when CONFIG_HIGHMEM is set, \
+because CONFIG_DEBUG_VM will trigger VM_BUG_ON_PAGE in __free_pages()->put_page_testzero().
+#endif
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_NUMA)
+#error Please unset CONFIG_SPARSEMEM_VMEMMAP when CONFIG_HIGHMEM and CONFIG_NUMA are set, \
+because vmemmap_verify will report warning that [xxx-xxx] potential offnode page_structs.
+#endif
+
+/* free order size pages for optimize system boot time. */
+#define OPTIMIZE_FREE_PAGES
+
+#ifdef OPTIMIZE_FREE_PAGES
+#define ORDER_SIZE(order)              (1UL << order)
+#define ORDER_MASK(order)              (~(ORDER_SIZE(order) - 1))
+#define PFN_ALIGN_ORDER(pfn, order)    \
+	(((u64)(pfn) + (ORDER_SIZE(order) - 1)) & ORDER_MASK(order))
+
+/* Free the reserved page into the buddy system, so it gets managed. */
+static void __init free_highmem_pages(u64 start, u64 order)
+{
+	struct page *page;
+	u64  i, pfn;
+
+	for (i = 0, pfn = start; i < ORDER_SIZE(order); i++, pfn++) {
+		page = pfn_to_page(pfn);
+		ClearPageReserved(page);
+		set_page_count(page, 0);
+	}
+
+	page = pfn_to_page(start);
+	__free_pages(page, order);
+	adjust_managed_page_count(page, ORDER_SIZE(order));
+}
+
+static void __init free_highpages(void)
+{
+	phys_addr_t range_start, range_end;
+	u64 max_low = max_low_pfn;
+	u64 i, order;
+
+	/* set highmem page free */
+	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
+			&range_start, &range_end, NULL) {
+		u64 start = PFN_UP(range_start), start_align;
+		u64 end = PFN_DOWN(range_end);
+
+		/* Ignore complete lowmem entries */
+		if (end <= max_low)
+			continue;
+
+		/* Truncate partial highmem entries */
+		if (start < max_low)
+			start = max_low;
+
+		order = MAX_ORDER;
+		start_align = PFN_ALIGN_ORDER(start, order);
+
+		for (; start < start_align; start++)
+			free_highmem_page(pfn_to_page(start));
+
+		//step by order size
+		for (; start < end; start += ORDER_SIZE(order))
+			free_highmem_pages(start, order);
+
+		for (; start < end; start++)
+			free_highmem_page(pfn_to_page(start));
+	}
+}
+#else
+static void __init free_highpages(void)
+{
+	unsigned long max_low = max_low_pfn;
+	phys_addr_t range_start, range_end;
+	u64 i;
+
+	/* set highmem page free */
+	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
+			&range_start, &range_end, NULL) {
+		unsigned long start = PFN_UP(range_start);
+		unsigned long end = PFN_DOWN(range_end);
+
+
+		/* Ignore complete lowmem entries */
+		if (end <= max_low)
+			continue;
+
+		/* Truncate partial highmem entries */
+		if (start < max_low)
+			start = max_low;
+
+		for (; start < end; start++)
+			free_highmem_page(pfn_to_page(start));
+	}
+}
+#endif
+#endif
+
 void __init mem_init(void)
 {
 #ifdef CONFIG_FLATMEM
@@ -161,6 +273,9 @@ void __init mem_init(void)
 
 	swiotlb_init(max_pfn > PFN_DOWN(dma32_phys_limit), SWIOTLB_VERBOSE);
 	memblock_free_all();
+#ifdef CONFIG_HIGHMEM
+	free_highpages();
+#endif
 
 	print_vm_layout();
 }
@@ -189,13 +304,18 @@ static void __init setup_bootmem(void)
 	phys_addr_t vmlinux_end = __pa_symbol(&_end);
 	phys_addr_t max_mapped_addr;
 	phys_addr_t phys_ram_end, vmlinux_start;
+#ifdef CONFIG_HIGHMEM
+	phys_addr_t max_low_addr;
+#endif
 
 	if (IS_ENABLED(CONFIG_XIP_KERNEL))
 		vmlinux_start = __pa_symbol(&_sdata);
 	else
 		vmlinux_start = __pa_symbol(&_start);
 
+#ifndef CONFIG_HIGHMEM
 	memblock_enforce_memory_limit(memory_limit);
+#endif
 
 	/*
 	 * Make sure we align the reservation on PMD_SIZE since we will
@@ -228,11 +348,22 @@ static void __init setup_bootmem(void)
 	}
 
 	min_low_pfn = PFN_UP(phys_ram_base);
+#ifdef CONFIG_HIGHMEM
+	max_low_addr = find_max_low_addr(memory_limit);
+	max_low_pfn = PFN_DOWN(max_low_addr);
+	max_pfn = PFN_DOWN(phys_ram_end);
+	memblock_set_current_limit(max_low_addr);
+#else
 	max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end);
+#endif
 	high_memory = (void *)(__va(PFN_PHYS(max_low_pfn)));
 
 	dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
+#ifdef CONFIG_HIGHMEM
+	set_max_mapnr(max_pfn - ARCH_PFN_OFFSET);
+#else
 	set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET);
+#endif
 
 	reserve_initrd_mem();
 
@@ -265,8 +396,14 @@ EXPORT_SYMBOL(riscv_pfn_base);
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
 pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
+#ifdef CONFIG_HIGHMEM
+static pte_t fixmap_pte[PTRS_PER_PTE * FIXADDR_PMD_NUM] __page_aligned_bss;
+#else
 static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss;
-
+#endif
+#ifdef CONFIG_HIGHMEM
+static pte_t pkmap_pte[PTRS_PER_PTE] __page_aligned_bss;
+#endif
 pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
 
 #ifdef CONFIG_XIP_KERNEL
@@ -301,10 +438,17 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 {
 	unsigned long addr = __fix_to_virt(idx);
 	pte_t *ptep;
+#ifdef CONFIG_HIGHMEM
+	unsigned long pte_idx = (addr - FIXADDR_START) >> PAGE_SHIFT;
+#endif
 
 	BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
 
+#ifdef CONFIG_HIGHMEM
+	ptep = &fixmap_pte[pte_idx];
+#else
 	ptep = &fixmap_pte[pte_index(addr)];
+#endif
 
 	if (pgprot_val(prot))
 		set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
@@ -999,8 +1143,26 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 	if (pgtable_l4_enabled)
 		create_pud_mapping(fixmap_pud, FIXADDR_START,
 				   (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE);
+#ifdef CONFIG_HIGHMEM
+	{
+		int i;
+		for (i = 0; i < FIXADDR_PMD_NUM; i++)
+			create_pmd_mapping(fixmap_pmd,
+					   (FIXADDR_START + i * PMD_SIZE),
+					   (uintptr_t)&(fixmap_pte[i * PTRS_PER_PTE]),
+					   PMD_SIZE,
+					   PAGE_TABLE);
+	}
+#else
 	create_pmd_mapping(fixmap_pmd, FIXADDR_START,
 			   (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE);
+#endif
+#ifdef CONFIG_HIGHMEM
+	/* Setup pkmap PMD */
+	create_pmd_mapping(fixmap_pmd, PKMAP_BASE,
+			   (uintptr_t)pkmap_pte, PMD_SIZE, PAGE_TABLE);
+#endif
+
 	/* Setup trampoline PGD and PMD */
 	create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
 			   trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE);
@@ -1206,6 +1368,13 @@ static void __init reserve_crashkernel(void)
 	crashk_res.end = crash_base + crash_size - 1;
 }
 
+#ifdef CONFIG_HIGHMEM
+static void __init pkmap_init(void)
+{
+	pkmap_page_table = &pkmap_pte[pte_index(PKMAP_BASE)];
+}
+#endif
+
 void __init paging_init(void)
 {
 	setup_bootmem();
@@ -1221,6 +1390,9 @@ void __init misc_mem_init(void)
 	arch_numa_init();
 	sparse_init();
 	zone_sizes_init();
+#ifdef CONFIG_HIGHMEM
+	pkmap_init();
+#endif
 	reserve_crashkernel();
 	memblock_dump_all();
 }
diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c
index 5b59d133b6af..bfa5168001e0 100644
--- a/drivers/base/arch_numa.c
+++ b/drivers/base/arch_numa.c
@@ -276,7 +276,11 @@ static int __init numa_alloc_distance(void)
 	int i, j;
 
 	size = nr_node_ids * nr_node_ids * sizeof(numa_distance[0]);
+#ifdef CONFIG_HIGHMEM
+	numa_distance = memblock_alloc_low(size, PAGE_SIZE);
+#else
 	numa_distance = memblock_alloc(size, PAGE_SIZE);
+#endif
 	if (WARN_ON(!numa_distance))
 		return -ENOMEM;
 
diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c
index ed5e91b1e040..210644f3d863 100644
--- a/drivers/char/ipmi/ipmi_si_hardcode.c
+++ b/drivers/char/ipmi/ipmi_si_hardcode.c
@@ -6,7 +6,7 @@
 #include <linux/platform_device.h>
 #include "ipmi_si.h"
 #include "ipmi_plat_data.h"
-
+#include <linux/pci.h>
 /*
  * There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
  * a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS.
@@ -90,6 +90,24 @@ static void __init ipmi_hardcode_init_one(const char *si_type_str,
 	ipmi_platform_add("hardcode-ipmi-si", i, &p);
 }
 
+#ifdef CONFIG_ARCH_SOPHGO
+static void variable_init(struct pci_dev *pdev)
+{
+	unsigned long addr_data = pci_resource_start(pdev, 1) + 0x0e80;
+	// printk("addr_data=0x%lx\n", addr_data);
+	strcpy(si_type_str, "kcs");
+	addrs[0]        = addr_data;
+	num_addrs       = 1;
+	regspacings[0]  = 4;
+	num_regspacings = 1;
+	regsizes[0]     = 4;
+	num_regsizes    = 1;
+	irqs[0]         = 0;
+	num_irqs        = 1;
+	slave_addrs[0]  = 0;
+	num_slave_addrs = 1;
+}
+#endif
 void __init ipmi_hardcode_init(void)
 {
 	unsigned int i;
@@ -97,7 +115,11 @@ void __init ipmi_hardcode_init(void)
 	char *si_type[SI_MAX_PARMS];
 
 	memset(si_type, 0, sizeof(si_type));
-
+#ifdef CONFIG_ARCH_SOPHGO
+	struct pci_dev *pdev = pci_get_device(0x1A03, 0x2402, NULL);
+	if (pdev != NULL)
+		variable_init(pdev);
+#endif
 	/* Parse out the si_type string into its components. */
 	str = si_type_str;
 	if (*str != '\0') {
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 5cd031f3fc97..2fde14778f89 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2156,7 +2156,8 @@ static int __init init_ipmi_si(void)
 		return 0;
 	}
 }
-module_init(init_ipmi_si);
+// module_init(init_ipmi_si);
+late_initcall(init_ipmi_si);
 
 static void wait_msg_processed(struct smi_info *smi_info)
 {
diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c
index 74fa2055868b..6a935100e1ae 100644
--- a/drivers/char/ipmi/ipmi_si_pci.c
+++ b/drivers/char/ipmi/ipmi_si_pci.c
@@ -111,6 +111,12 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
 	io.regsize = DEFAULT_REGSIZE;
 	io.regshift = 0;
 
+#ifdef CONFIG_ARCH_SOPHGO
+	io.addr_data = pci_resource_start(pdev, 1) + 0x0e80;
+	io.slave_addr = 0x20;
+	io.regspacing = 4;
+	io.regsize = 4;
+#endif
 	io.irq = pdev->irq;
 	if (io.irq)
 		io.irq_setup = ipmi_std_irq_setup;
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e3ca0d058a25..109d5900b5fd 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_ARCH_STM32)		+= stm32/
 obj-$(CONFIG_SOC_STARFIVE)		+= starfive/
 obj-$(CONFIG_ARCH_SUNXI)		+= sunxi/
 obj-y					+= sunxi-ng/
+obj-$(CONFIG_ARCH_SOPHGO)		+= sophgo/
 obj-$(CONFIG_ARCH_TEGRA)		+= tegra/
 obj-y					+= ti/
 obj-$(CONFIG_CLK_UNIPHIER)		+= uniphier/
diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile
new file mode 100644
index 000000000000..55997fc07b5b
--- /dev/null
+++ b/drivers/clk/sophgo/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ARCH_SOPHGO)	+= clk-dummy.o
+obj-$(CONFIG_ARCH_SOPHGO)	+= clk.o
+obj-$(CONFIG_ARCH_SOPHGO)	+= clk-mango.o
diff --git a/drivers/clk/sophgo/clk-dummy.c b/drivers/clk/sophgo/clk-dummy.c
new file mode 100644
index 000000000000..99af0e6dae6a
--- /dev/null
+++ b/drivers/clk/sophgo/clk-dummy.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2022 SOPHGO
+ *
+ * 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.
+ */
+
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/string.h>
+#include <linux/log2.h>
+
+#include "clk.h"
+
+/*
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register containing divider
+ * @shift:	shift to the divider bit field
+ * @width:	width of the divider bit field
+ * @initial_val:initial value of the divider
+ * @table:	the div table that the divider supports
+ * @lock:	register lock
+ */
+struct mango_clk_divider {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	u8		flags;
+	u32		initial_val;
+	const struct clk_div_table *table;
+	spinlock_t	*lock;
+};
+
+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct device_node *node;
+	struct of_phandle_args clkspec;
+	int rc, index = 0;
+	u32 rate;
+	struct property *prop;
+	const __be32 *cur;
+	struct clk *clk;
+
+	node = of_find_node_by_name(NULL, "default_rates");
+
+	of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
+		if (rate) {
+			rc = of_parse_phandle_with_args(node, "clocks",
+							"#clock-cells", index, &clkspec);
+			if (rc < 0) {
+				/* skip empty (null) phandles */
+				if (rc == -ENOENT)
+					continue;
+				else
+					return rc;
+			}
+
+			clk = of_clk_get_from_provider(&clkspec);
+			if (IS_ERR(clk))
+				return PTR_ERR(clk);
+			if (!strcmp(clk_hw_get_name(hw), __clk_get_name(clk)))
+				return rate;
+		}
+		index++;
+	}
+	return 0;
+}
+
+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				      unsigned long *prate)
+{
+	return rate;
+}
+
+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	return 0;
+}
+
+/*
+ * @hw: ccf use to hook get mango_pll_clock
+ * @parent_rate: parent rate
+ *
+ * The is function will be called through clk_get_rate
+ * and return current rate after decoding reg value
+ */
+static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct device_node *node;
+	struct of_phandle_args clkspec;
+	int rc, index = 0;
+	u32 rate;
+	struct property *prop;
+	const __be32 *cur;
+
+	node = of_find_node_by_name(NULL, "default_rates");
+
+	of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
+		if (rate) {
+			rc = of_parse_phandle_with_args(node, "clocks",
+							"#clock-cells", index, &clkspec);
+			if (rc < 0) {
+				/* skip empty (null) phandles */
+				if (rc == -ENOENT)
+					continue;
+				else
+					return rc;
+			}
+
+			if (!strncmp(clk_hw_get_name(hw), clkspec.np->name, 4))
+				return rate;
+		}
+		index++;
+	}
+	return 0;
+}
+
+static long mango_clk_pll_round_rate(struct clk_hw *hw,
+				  unsigned long req_rate, unsigned long *prate)
+{
+	return req_rate;
+}
+
+static int mango_clk_pll_determine_rate(struct clk_hw *hw,
+				     struct clk_rate_request *req)
+{
+	req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate),
+					  &req->best_parent_rate);
+	return 0;
+}
+
+static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	return 0;
+}
+
+const struct clk_ops dm_mango_clk_divider_ops = {
+	.recalc_rate = mango_clk_divider_recalc_rate,
+	.round_rate = mango_clk_divider_round_rate,
+	.set_rate = mango_clk_divider_set_rate,
+};
+
+const struct clk_ops dm_mango_clk_divider_ro_ops = {
+	.recalc_rate = mango_clk_divider_recalc_rate,
+	.round_rate = mango_clk_divider_round_rate,
+};
+
+const struct clk_ops dm_mango_clk_pll_ops = {
+	.recalc_rate = mango_clk_pll_recalc_rate,
+	.round_rate = mango_clk_pll_round_rate,
+	.determine_rate = mango_clk_pll_determine_rate,
+	.set_rate = mango_clk_pll_set_rate,
+};
+
+const struct clk_ops dm_mango_clk_pll_ro_ops = {
+	.recalc_rate = mango_clk_pll_recalc_rate,
+	.round_rate = mango_clk_pll_round_rate,
+};
+
+struct mux_cb_clk_name {
+	const char *name;
+	struct list_head node;
+};
+
+static struct list_head mux_cb_clk_name_list =
+	LIST_HEAD_INIT(mux_cb_clk_name_list);
+static int mux_notifier_cb(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	int ret = 0;
+	static unsigned char mux_id = 1;
+	struct clk_notifier_data *ndata = data;
+	struct clk_hw *hw = __clk_get_hw(ndata->clk);
+	const struct clk_ops *ops = &clk_mux_ops;
+	struct mux_cb_clk_name *cb_lsit;
+
+	if (event == PRE_RATE_CHANGE) {
+		struct clk_hw *hw_p = clk_hw_get_parent(hw);
+
+		cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL);
+		if (cb_lsit) {
+			INIT_LIST_HEAD(&cb_lsit->node);
+			list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list);
+		} else {
+			pr_err("mux cb kmalloc mem fail\n");
+			goto out;
+		}
+
+		cb_lsit->name = clk_hw_get_name(hw_p);
+		mux_id = ops->get_parent(hw);
+		if (mux_id > 1) {
+			ret = 1;
+			goto out;
+		}
+		ops->set_parent(hw, !mux_id);
+	} else if (event == POST_RATE_CHANGE) {
+		struct clk_hw *hw_p = clk_hw_get_parent(hw);
+
+		cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list,
+						typeof(*cb_lsit), node);
+		if (cb_lsit) {
+			const char *pre_name = cb_lsit->name;
+
+			list_del_init(&cb_lsit->node);
+			kfree(cb_lsit);
+			if (strcmp(clk_hw_get_name(hw_p), pre_name))
+				goto out;
+		}
+
+		ops->set_parent(hw, mux_id);
+	}
+
+out:
+	return notifier_from_errno(ret);
+}
+
+int dm_set_default_clk_rates(struct device_node *node)
+{
+	struct of_phandle_args clkspec;
+	struct property *prop;
+	const __be32 *cur;
+	int rc, index = 0;
+	struct clk *clk;
+	u32 rate;
+
+	of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
+		if (rate) {
+			rc = of_parse_phandle_with_args(node, "clocks",
+							"#clock-cells", index, &clkspec);
+			if (rc < 0) {
+				/* skip empty (null) phandles */
+				if (rc == -ENOENT)
+					continue;
+				else
+					return rc;
+			}
+
+			clk = of_clk_get_from_provider(&clkspec);
+			if (IS_ERR(clk)) {
+				pr_warn("clk: couldn't get clock %d for %s\n",
+					index, node->full_name);
+				return PTR_ERR(clk);
+			}
+
+			rc = clk_set_rate(clk, rate);
+			if (rc < 0)
+				pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+				       __clk_get_name(clk), rate, rc,
+				       clk_get_rate(clk));
+			clk_put(clk);
+		}
+		index++;
+	}
+
+	return 0;
+}
+
+static struct clk *__register_divider_clks(struct device *dev, const char *name,
+					   const char *parent_name,
+					   unsigned long flags,
+					   void __iomem *reg, u8 shift,
+					   u8 width, u32 initial_val,
+					   u8 clk_divider_flags,
+					   const struct clk_div_table *table,
+					   spinlock_t *lock)
+{
+	struct mango_clk_divider *div;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+		if (width + shift > 16) {
+			pr_warn("divider value exceeds LOWORD field\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	/* allocate the divider */
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+		init.ops = &dm_mango_clk_divider_ro_ops;
+	else
+		init.ops = &dm_mango_clk_divider_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* struct mango_clk_divider assignments */
+	div->reg = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = clk_divider_flags;
+	div->lock = lock;
+	div->hw.init = &init;
+	div->table = table;
+	div->initial_val = initial_val;
+
+	/* register the clock */
+	hw = &div->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(div);
+		hw = ERR_PTR(ret);
+		return ERR_PTR(-EBUSY);
+	}
+
+	return hw->clk;
+}
+
+static inline int register_provider_clks
+(struct device_node *node, struct mango_clk_data *clk_data, int clk_num)
+{
+	return of_clk_add_provider(node, of_clk_src_onecell_get,
+				   &clk_data->clk_data);
+}
+
+static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_gate_clock *gate_clks = table->gate_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->gate_clks_num;
+	int i;
+
+	for (i = 0; i < clk_num; i++) {
+		clk = clk_register_gate(
+			dev, gate_clks[i].name, gate_clks[i].parent_name,
+			gate_clks[i].flags | CLK_IS_CRITICAL, base + gate_clks[i].offset,
+			gate_clks[i].bit_idx, gate_clks[i].gate_flags,
+			&clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				gate_clks[i].name);
+			goto err;
+		}
+
+		if (gate_clks[i].alias)
+			clk_register_clkdev(clk, gate_clks[i].alias, NULL);
+
+		clk_data->clk_data.clks[gate_clks[i].id] = clk;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_gate(clk_data->clk_data.clks[gate_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static int register_divider_clks(struct device *dev,
+				 struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_divider_clock *div_clks = table->div_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->div_clks_num;
+	int i, val;
+
+	for (i = 0; i < clk_num; i++) {
+		clk = __register_divider_clks(
+			NULL, div_clks[i].name, div_clks[i].parent_name,
+			div_clks[i].flags, base + div_clks[i].offset,
+			div_clks[i].shift, div_clks[i].width,
+			div_clks[i].initial_val,
+			(div_clks[i].initial_sel & MANGO_CLK_USE_INIT_VAL) ?
+				div_clks[i].div_flags | CLK_DIVIDER_READ_ONLY :
+				div_clks[i].div_flags,
+			div_clks[i].table, &clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				div_clks[i].name);
+			goto err;
+		}
+
+		clk_data->clk_data.clks[div_clks[i].id] = clk;
+
+		if (div_clks[i].initial_sel == MANGO_CLK_USE_REG_VAL) {
+			regmap_read(clk_data->syscon_top, div_clks[i].offset,
+				    &val);
+
+			/*
+			 * set a default divider factor,
+			 * clk driver should not select divider clock as the
+			 * clock source, before set the divider by right process
+			 * (assert div, set div factor, de assert div).
+			 */
+			if (div_clks[i].initial_val > 0)
+				val |= (div_clks[i].initial_val << 16 | 1 << 3);
+			else {
+				/*
+				 * the div register is config to use divider factor, don't change divider
+				 */
+				if (!(val >> 3 & 0x1))
+					val |= 1 << 16;
+			}
+
+			regmap_write(clk_data->syscon_top, div_clks[i].offset,
+				     val);
+		}
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_divider(clk_data->clk_data.clks[div_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_mux_clock *mux_clks = table->mux_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->mux_clks_num;
+	int i;
+
+	for (i = 0; i < clk_num; i++) {
+		u32 mask = BIT(mux_clks[i].width) - 1;
+
+		clk = clk_register_mux_table(
+			dev, mux_clks[i].name, mux_clks[i].parent_names,
+			mux_clks[i].num_parents, mux_clks[i].flags,
+			base + mux_clks[i].offset, mux_clks[i].shift, mask,
+			mux_clks[i].mux_flags, mux_clks[i].table,
+			&clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				mux_clks[i].name);
+			goto err;
+		}
+
+		clk_data->clk_data.clks[mux_clks[i].id] = clk;
+
+		if (!(mux_clks[i].flags & CLK_MUX_READ_ONLY)) {
+			struct clk *parent;
+			struct notifier_block *clk_nb;
+
+			/* set mux clock default parent here, it's parent index
+			 * value is read from the mux clock reg. dts can override
+			 * setting the mux clock parent later.
+			 */
+			parent = clk_get_parent(clk);
+			clk_set_parent(clk, parent);
+
+			/* add a notify callback function */
+			clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL);
+			if (!clk_nb)
+				goto err;
+			clk_nb->notifier_call = mux_notifier_cb;
+			if (clk_notifier_register(clk, clk_nb))
+				pr_err("%s: failed to register clock notifier for %s\n",
+					__func__, mux_clks[i].name);
+		}
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_mux(clk_data->clk_data.clks[mux_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+/* pll clock init */
+int dm_mango_register_pll_clks(struct device_node *node,
+			 struct mango_clk_data *clk_data, const char *clk_name)
+{
+	struct clk *clk = NULL;
+	struct mango_pll_clock *pll_clks;
+	int i, ret = 0;
+	const struct clk_ops *local_ops;
+
+	pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks;
+	for (i = 0; i < clk_data->table->pll_clks_num; i++) {
+		if (!strcmp(clk_name,  pll_clks[i].name)) {
+			/* have to assigne pll_clks.syscon_top first
+			 * since clk_register_composite will need it
+			 * to calculate current rate.
+			 */
+			pll_clks[i].syscon_top = clk_data->syscon_top;
+			pll_clks[i].lock = &clk_data->lock;
+			if (pll_clks[i].ini_flags & MANGO_CLK_RO)
+				local_ops = &dm_mango_clk_pll_ro_ops;
+			else
+				local_ops = &dm_mango_clk_pll_ops;
+			clk = clk_register_composite(
+				NULL, pll_clks[i].name, &pll_clks[i].parent_name,
+				1, NULL, NULL, &pll_clks[i].hw, local_ops,
+				NULL, NULL, pll_clks[i].flags);
+
+			if (IS_ERR(clk)) {
+				pr_err("%s: failed to register clock %s\n", __func__,
+					pll_clks[i].name);
+				ret = -EINVAL;
+				goto out;
+			}
+			ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+			if (ret)
+				clk_unregister(clk);
+		} else {
+			continue;
+		}
+	}
+
+out:
+	return ret;
+}
+
+/* mux clk init */
+int dm_mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data)
+{
+	int ret;
+	int count;
+	struct clk **clk_table;
+
+	count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num;
+	clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table)
+		return -ENOMEM;
+
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = count;
+
+	ret = register_mux_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_gate_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_provider_clks(node, clk_data, count);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	kfree(clk_table);
+	return ret;
+}
+
+/* pll divider init */
+int dm_mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data)
+{
+	int ret;
+	int count;
+
+	struct clk **clk_table;
+
+	count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num;
+	clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table)
+		return -ENOMEM;
+
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = count;
+
+	ret = register_divider_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_gate_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_provider_clks(node, clk_data, count);
+	if (ret)
+		goto err;
+
+
+	return 0;
+err:
+	kfree(clk_table);
+	pr_err("%s error %d\n", __func__, ret);
+	return ret;
+}
diff --git a/drivers/clk/sophgo/clk-mango.c b/drivers/clk/sophgo/clk-mango.c
new file mode 100644
index 000000000000..ed68a358dd8b
--- /dev/null
+++ b/drivers/clk/sophgo/clk-mango.c
@@ -0,0 +1,977 @@
+/*
+ * Copyright (c) 2022 SOPHGO
+ *
+ * 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.
+ */
+
+#include <linux/of_address.h>
+#include <linux/mfd/syscon.h>
+#include <dt-bindings/clock/sophgo-mango-clock.h>
+
+#include "clk.h"
+
+/* fixed clocks */
+struct mango_pll_clock mango_root_pll_clks[] = {
+	{
+		.id = FPLL_CLK,
+		.name = "fpll_clock",
+		.parent_name = "cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+	}, {
+		.id = DPLL0_CLK,
+		.name = "dpll0_clock",
+		.parent_name = "cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	}, {
+		.id = DPLL1_CLK,
+		.name = "dpll1_clock",
+		.parent_name = "cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	}, {
+		.id = MPLL_CLK,
+		.name = "mpll_clock",
+		.parent_name = "cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	},{
+		.id = FPLL_CLK,
+		.name = "s1_fpll_clock",
+		.parent_name = "s1_cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+	}, {
+		.id = DPLL0_CLK,
+		.name = "s1_dpll0_clock",
+		.parent_name = "s1_cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	}, {
+		.id = DPLL1_CLK,
+		.name = "s1_dpll1_clock",
+		.parent_name = "s1_cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.ini_flags = MANGO_CLK_RO,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	}, {
+		.id = MPLL_CLK,
+		.name = "s1_mpll_clock",
+		.parent_name = "s1_cgi",
+		.flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
+		.status_offset = 0xc0,
+		.enable_offset = 0xc4,
+	}
+};
+
+/* divider clocks */
+static const struct mango_divider_clock s0_div_clks[] = {
+	{ DIV_CLK_MPLL_RP_CPU_NORMAL_0, "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0",
+		0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_MPLL_AXI_DDR_0, "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0",
+		0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
+	{ DIV_CLK_FPLL_DDR01_1, "clk_div_ddr01_1", "clk_gate_ddr01_div1",
+		0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_FPLL_DDR23_1, "clk_div_ddr23_1", "clk_gate_ddr23_div1",
+		0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_FPLL_RP_CPU_NORMAL_1, "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1",
+		0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock",
+		0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal",
+		0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock",
+		0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock",
+		0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock",
+		0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock",
+		0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_PTP_REF_I_ETH0, "clk_div_ptp_ref_i_eth0", "fpll_clock",
+		0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock",
+		0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock",
+		0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock",
+		0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock",
+		0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_AXI_HSPERI, "clk_div_top_axi_hsperi", "fpll_clock",
+		0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_AXI_DDR_1, "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1",
+		0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
+	{ DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53",
+		0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53",
+		0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53",
+		0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53",
+		0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53",
+		0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53",
+		0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53",
+		0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53",
+		0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0",
+		0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0",
+		0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0",
+		0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_DPLL0_DDR01_0, "clk_div_ddr01_0", "clk_gate_ddr01_div0",
+		0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_DPLL1_DDR23_0, "clk_div_ddr23_0", "clk_gate_ddr23_div0",
+		0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+};
+
+/* gate clocks */
+static const struct mango_gate_clock s0_gate_clks[] = {
+	{ GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div1", "mpll_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div1", "mpll_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 },
+	{ GATE_CLK_RP_CPU_NORMAL_DIV1, "clk_gate_rp_cpu_normal_div0", "fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div0", "fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "dpll0_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "dpll1_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 },
+	{ GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 },
+	{ GATE_CLK_TOP_RP_CMN_DIV2, "clk_gate_top_rp_cmn_div2", "clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 },
+	{ GATE_CLK_AXI_PCIE0, "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 },
+	{ GATE_CLK_AXI_PCIE1, "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 },
+	{ GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2",
+		CLK_SET_RATE_PARENT, 0x2004, 10, 0 },
+	{ GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc",
+		CLK_SET_RATE_PARENT, 0x2004, 3, 0 },
+	{ GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd",
+		CLK_SET_RATE_PARENT, 0x2004, 6, 0 },
+	{ GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0",
+		CLK_SET_RATE_PARENT, 0x2000, 30, 0 },
+	{ GATE_CLK_PTP_REF_I_ETH0, "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0",
+		CLK_SET_RATE_PARENT, 0x2004, 0, 0 },
+	{ GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0",
+		CLK_SET_RATE_PARENT, 0x2004, 1, 0 },
+	{ GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 },
+	{ GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc",
+		CLK_SET_RATE_PARENT, 0x2000, 7, 0 },
+	{ GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse",
+		CLK_SET_RATE_PARENT, 0x2000, 20, 0},
+	{ GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 },
+	{ GATE_CLK_TOP_AXI_HSPERI, "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 },
+	{ GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_gate_top_axi0",
+		0, 0x2000, 8, 0 },
+	{ GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_gate_top_axi0",
+		0, 0x2000, 9, 0 },
+	{ GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_gate_top_axi0",
+		CLK_IGNORE_UNUSED, 0x2000, 10, 0 },
+	{ GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_gate_top_axi0",
+		CLK_IGNORE_UNUSED, 0x2000, 11, 0 },
+	{ GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_gate_top_axi0",
+		0, 0x2000, 21, 0 },
+	{ GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_gate_top_axi0",
+		0, 0x2000, 22, 0 },
+	{ GATE_CLK_APB_GPIO_INTR, "clk_gate_apb_gpio_intr", "clk_gate_top_axi0",
+		0, 0x2000, 23, 0 },
+	{ GATE_CLK_APB_I2C, "clk_gate_apb_i2c", "clk_gate_top_axi0",
+		0, 0x2000, 26, 0 },
+	{ GATE_CLK_APB_WDT, "clk_gate_apb_wdt", "clk_gate_top_axi0",
+		0, 0x2000, 27, 0 },
+	{ GATE_CLK_APB_PWM, "clk_gate_apb_pwm", "clk_gate_top_axi0",
+		0, 0x2000, 28, 0 },
+	{ GATE_CLK_APB_RTC, "clk_gate_apb_rtc", "clk_gate_top_axi0",
+		0, 0x2000, 29, 0 },
+	{ GATE_CLK_SYSDMA_AXI, "clk_gate_sysdma_axi", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 3, 0 },
+	{ GATE_CLK_APB_UART, "clk_gate_apb_uart", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 5, 0 },
+	{ GATE_CLK_AXI_DBG_I2C, "clk_gate_axi_dbg_i2c", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 6, 0 },
+	{ GATE_CLK_APB_SPI, "clk_gate_apb_spi", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 25, 0 },
+	{ GATE_CLK_AXI_ETH0, "clk_gate_axi_eth0", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 31, 0 },
+	{ GATE_CLK_AXI_EMMC, "clk_gate_axi_emmc", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2004, 2, 0 },
+	{ GATE_CLK_AXI_SD, "clk_gate_axi_sd", "clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2004, 5, 0 },
+	{ GATE_CLK_TIMER1, "clk_gate_timer1", "clk_div_timer1",
+		CLK_SET_RATE_PARENT, 0x2000, 12, 0 },
+	{ GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2",
+		CLK_SET_RATE_PARENT, 0x2000, 13, 0 },
+	{ GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3",
+		CLK_SET_RATE_PARENT, 0x2000, 14, 0 },
+	{ GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4",
+		CLK_SET_RATE_PARENT, 0x2000, 15, 0 },
+	{ GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5",
+		CLK_SET_RATE_PARENT, 0x2000, 16, 0 },
+	{ GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6",
+		CLK_SET_RATE_PARENT, 0x2000, 17, 0 },
+	{ GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7",
+		CLK_SET_RATE_PARENT, 0x2000, 18, 0 },
+	{ GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8",
+		CLK_SET_RATE_PARENT, 0x2000, 19, 0 },
+	{ GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", "clk_div_100k_emmc",
+		CLK_SET_RATE_PARENT, 0x2004, 4, 0 },
+	{ GATE_CLK_100K_SD, "clk_gate_100k_sd", "clk_div_100k_sd",
+		CLK_SET_RATE_PARENT, 0x2004, 7, 0 },
+	{ GATE_CLK_GPIO_DB, "clk_gate_gpio_db", "clk_div_gpio_db",
+		CLK_SET_RATE_PARENT, 0x2000, 24, 0 },
+	{ GATE_CLK_DDR01, "clk_gate_ddr01", "clk_mux_ddr01",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23, "clk_gate_ddr23", "clk_mux_ddr23",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 },
+	{ GATE_CLK_RP_CPU_NORMAL, "clk_gate_rp_cpu_normal", "clk_mux_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", "clk_mux_axi_ddr",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_RXU0, "clk_gate_rxu0", "clk_gate_rp_cpu_normal",
+		0, 0x368, 0, 0 },
+	{ GATE_CLK_RXU1, "clk_gate_rxu1", "clk_gate_rp_cpu_normal",
+		0, 0x368, 1, 0 },
+	{ GATE_CLK_RXU2, "clk_gate_rxu2", "clk_gate_rp_cpu_normal",
+		0, 0x368, 2, 0 },
+	{ GATE_CLK_RXU3, "clk_gate_rxu3", "clk_gate_rp_cpu_normal",
+		0, 0x368, 3, 0 },
+	{ GATE_CLK_RXU4, "clk_gate_rxu4", "clk_gate_rp_cpu_normal",
+		0, 0x368, 4, 0 },
+	{ GATE_CLK_RXU5, "clk_gate_rxu5", "clk_gate_rp_cpu_normal",
+		0, 0x368, 5, 0 },
+	{ GATE_CLK_RXU6, "clk_gate_rxu6", "clk_gate_rp_cpu_normal",
+		0, 0x368, 6, 0 },
+	{ GATE_CLK_RXU7, "clk_gate_rxu7", "clk_gate_rp_cpu_normal",
+		0, 0x368, 7, 0 },
+	{ GATE_CLK_RXU8, "clk_gate_rxu8", "clk_gate_rp_cpu_normal",
+		0, 0x368, 8, 0 },
+	{ GATE_CLK_RXU9, "clk_gate_rxu9", "clk_gate_rp_cpu_normal",
+		0, 0x368, 9, 0 },
+	{ GATE_CLK_RXU10, "clk_gate_rxu10", "clk_gate_rp_cpu_normal",
+		0, 0x368, 10, 0 },
+	{ GATE_CLK_RXU11, "clk_gate_rxu11", "clk_gate_rp_cpu_normal",
+		0, 0x368, 11, 0 },
+	{ GATE_CLK_RXU12, "clk_gate_rxu12", "clk_gate_rp_cpu_normal",
+		0, 0x368, 12, 0 },
+	{ GATE_CLK_RXU13, "clk_gate_rxu13", "clk_gate_rp_cpu_normal",
+		0, 0x368, 13, 0 },
+	{ GATE_CLK_RXU14, "clk_gate_rxu14", "clk_gate_rp_cpu_normal",
+		0, 0x368, 14, 0 },
+	{ GATE_CLK_RXU15, "clk_gate_rxu15", "clk_gate_rp_cpu_normal",
+		0, 0x368, 15, 0 },
+	{ GATE_CLK_RXU16, "clk_gate_rxu16", "clk_gate_rp_cpu_normal",
+		0, 0x368, 16, 0 },
+	{ GATE_CLK_RXU17, "clk_gate_rxu17", "clk_gate_rp_cpu_normal",
+		0, 0x368, 17, 0 },
+	{ GATE_CLK_RXU18, "clk_gate_rxu18", "clk_gate_rp_cpu_normal",
+		0, 0x368, 18, 0 },
+	{ GATE_CLK_RXU19, "clk_gate_rxu19", "clk_gate_rp_cpu_normal",
+		0, 0x368, 19, 0 },
+	{ GATE_CLK_RXU20, "clk_gate_rxu20", "clk_gate_rp_cpu_normal",
+		0, 0x368, 20, 0 },
+	{ GATE_CLK_RXU21, "clk_gate_rxu21", "clk_gate_rp_cpu_normal",
+		0, 0x368, 21, 0 },
+	{ GATE_CLK_RXU22, "clk_gate_rxu22", "clk_gate_rp_cpu_normal",
+		0, 0x368, 22, 0 },
+	{ GATE_CLK_RXU23, "clk_gate_rxu23", "clk_gate_rp_cpu_normal",
+		0, 0x368, 23, 0 },
+	{ GATE_CLK_RXU24, "clk_gate_rxu24", "clk_gate_rp_cpu_normal",
+		0, 0x368, 24, 0 },
+	{ GATE_CLK_RXU25, "clk_gate_rxu25", "clk_gate_rp_cpu_normal",
+		0, 0x368, 25, 0 },
+	{ GATE_CLK_RXU26, "clk_gate_rxu26", "clk_gate_rp_cpu_normal",
+		0, 0x368, 26, 0 },
+	{ GATE_CLK_RXU27, "clk_gate_rxu27", "clk_gate_rp_cpu_normal",
+		0, 0x368, 27, 0 },
+	{ GATE_CLK_RXU28, "clk_gate_rxu28", "clk_gate_rp_cpu_normal",
+		0, 0x368, 28, 0 },
+	{ GATE_CLK_RXU29, "clk_gate_rxu29", "clk_gate_rp_cpu_normal",
+		0, 0x368, 29, 0 },
+	{ GATE_CLK_RXU30, "clk_gate_rxu30", "clk_gate_rp_cpu_normal",
+		0, 0x368, 30, 0 },
+	{ GATE_CLK_RXU31, "clk_gate_rxu31", "clk_gate_rp_cpu_normal",
+		0, 0x368, 31, 0 },
+	{ GATE_CLK_MP0, "clk_gate_mp0", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 },
+	{ GATE_CLK_MP1, "clk_gate_mp1", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 },
+	{ GATE_CLK_MP2, "clk_gate_mp2", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 },
+	{ GATE_CLK_MP3, "clk_gate_mp3", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 },
+	{ GATE_CLK_MP4, "clk_gate_mp4", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 },
+	{ GATE_CLK_MP5, "clk_gate_mp5", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 },
+	{ GATE_CLK_MP6, "clk_gate_mp6", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 },
+	{ GATE_CLK_MP7, "clk_gate_mp7", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 },
+	{ GATE_CLK_MP8, "clk_gate_mp8", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 },
+	{ GATE_CLK_MP9, "clk_gate_mp9", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 },
+	{ GATE_CLK_MP10, "clk_gate_mp10", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 },
+	{ GATE_CLK_MP11, "clk_gate_mp11", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 },
+	{ GATE_CLK_MP12, "clk_gate_mp12", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 },
+	{ GATE_CLK_MP13, "clk_gate_mp13", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 },
+	{ GATE_CLK_MP14, "clk_gate_mp14", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 },
+	{ GATE_CLK_MP15, "clk_gate_mp15", "clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 },
+};
+
+static const struct mango_divider_clock s1_div_clks[] = {
+	{ DIV_CLK_MPLL_RP_CPU_NORMAL_0, "s1_clk_div_rp_cpu_normal_0", "s1_clk_gate_rp_cpu_normal_div0",
+		0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_MPLL_AXI_DDR_0, "s1_clk_div_axi_ddr_0", "s1_clk_gate_axi_ddr_div0",
+		0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
+	{ DIV_CLK_FPLL_DDR01_1, "s1_clk_div_ddr01_1", "s1_clk_gate_ddr01_div1",
+		0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_FPLL_DDR23_1, "s1_clk_div_ddr23_1", "s1_clk_gate_ddr23_div1",
+		0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_FPLL_RP_CPU_NORMAL_1, "s1_clk_div_rp_cpu_normal_1", "s1_clk_gate_rp_cpu_normal_div1",
+		0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_50M_A53, "s1_clk_div_50m_a53", "s1_fpll_clock",
+		0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "s1_clk_div_top_rp_cmn_div2", "s1_clk_mux_rp_cpu_normal",
+		0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_UART_500M, "s1_clk_div_uart_500m", "s1_fpll_clock",
+		0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_AHB_LPC, "s1_clk_div_ahb_lpc", "s1_fpll_clock",
+		0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_EFUSE, "s1_clk_div_efuse", "s1_fpll_clock",
+		0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TX_ETH0, "s1_clk_div_tx_eth0", "s1_fpll_clock",
+		0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_PTP_REF_I_ETH0, "s1_clk_div_ptp_ref_i_eth0", "s1_fpll_clock",
+		0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_REF_ETH0, "s1_clk_div_ref_eth0", "s1_fpll_clock",
+		0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_EMMC, "s1_clk_div_emmc", "s1_fpll_clock",
+		0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_SD, "s1_clk_div_sd", "s1_fpll_clock",
+		0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_AXI0, "s1_clk_div_top_axi0", "s1_fpll_clock",
+		0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_TOP_AXI_HSPERI, "s1_clk_div_top_axi_hsperi", "s1_fpll_clock",
+		0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_AXI_DDR_1, "s1_clk_div_axi_ddr_1", "s1_clk_gate_axi_ddr_div1",
+		0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
+	{ DIV_CLK_FPLL_DIV_TIMER1, "s1_clk_div_timer1", "s1_clk_div_50m_a53",
+		0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER2, "s1_clk_div_timer2", "s1_clk_div_50m_a53",
+		0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER3, "s1_clk_div_timer3", "s1_clk_div_50m_a53",
+		0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER4, "s1_clk_div_timer4", "s1_clk_div_50m_a53",
+		0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER5, "s1_clk_div_timer5", "s1_clk_div_50m_a53",
+		0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER6, "s1_clk_div_timer6", "s1_clk_div_50m_a53",
+		0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER7, "s1_clk_div_timer7", "s1_clk_div_50m_a53",
+		0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_DIV_TIMER8, "s1_clk_div_timer8", "s1_clk_div_50m_a53",
+		0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_100K_EMMC, "s1_clk_div_100k_emmc", "s1_clk_div_top_axi0",
+		0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_100K_SD, "s1_clk_div_100k_sd", "s1_clk_div_top_axi0",
+		0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_FPLL_GPIO_DB, "s1_clk_div_gpio_db", "s1_clk_div_top_axi0",
+		0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
+	{ DIV_CLK_DPLL0_DDR01_0, "s1_clk_div_ddr01_0", "s1_clk_gate_ddr01_div0",
+		0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+	{ DIV_CLK_DPLL1_DDR23_0, "s1_clk_div_ddr23_0", "s1_clk_gate_ddr23_div0",
+		0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
+};
+
+static const struct mango_gate_clock s1_gate_clks[] = {
+	{ GATE_CLK_RP_CPU_NORMAL_DIV0, "s1_clk_gate_rp_cpu_normal_div1", "s1_mpll_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR_DIV0, "s1_clk_gate_axi_ddr_div1", "s1_mpll_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_DDR01_DIV0, "s1_clk_gate_ddr01_div0", "s1_fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23_DIV0, "s1_clk_gate_ddr23_div0", "s1_fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 },
+	{ GATE_CLK_RP_CPU_NORMAL_DIV1, "s1_clk_gate_rp_cpu_normal_div0", "s1_fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR_DIV1, "s1_clk_gate_axi_ddr_div0", "s1_fpll_clock",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_DDR01_DIV1, "s1_clk_gate_ddr01_div1", "s1_dpll0_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23_DIV1, "s1_clk_gate_ddr23_div1", "s1_dpll1_clock",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 },
+	{ GATE_CLK_A53_50M, "s1_clk_gate_a53_50m", "s1_clk_div_50m_a53",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 },
+	{ GATE_CLK_TOP_RP_CMN_DIV2, "s1_clk_gate_top_rp_cmn_div2", "s1_clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 },
+	{ GATE_CLK_AXI_PCIE0, "s1_clk_gate_axi_pcie0", "s1_clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 },
+	{ GATE_CLK_AXI_PCIE1, "s1_clk_gate_axi_pcie1", "s1_clk_gate_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 },
+	{ GATE_CLK_HSDMA, "s1_clk_gate_hsdma", "s1_clk_gate_top_rp_cmn_div2",
+		CLK_SET_RATE_PARENT, 0x2004, 10, 0 },
+	{ GATE_CLK_EMMC_100M, "s1_clk_gate_emmc", "s1_clk_div_emmc",
+		CLK_SET_RATE_PARENT, 0x2004, 3, 0 },
+	{ GATE_CLK_SD_100M, "s1_clk_gate_sd", "s1_clk_div_sd",
+		CLK_SET_RATE_PARENT, 0x2004, 6, 0 },
+	{ GATE_CLK_TX_ETH0, "s1_clk_gate_tx_eth0", "s1_clk_div_tx_eth0",
+		CLK_SET_RATE_PARENT, 0x2000, 30, 0 },
+	{ GATE_CLK_PTP_REF_I_ETH0, "s1_clk_gate_ptp_ref_i_eth0", "s1_clk_div_ptp_ref_i_eth0",
+		CLK_SET_RATE_PARENT, 0x2004, 0, 0 },
+	{ GATE_CLK_REF_ETH0, "s1_clk_gate_ref_eth0", "s1_clk_div_ref_eth0",
+		CLK_SET_RATE_PARENT, 0x2004, 1, 0 },
+	{ GATE_CLK_UART_500M, "s1_clk_gate_uart_500m", "s1_clk_div_uart_500m",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 },
+	{ GATE_CLK_AHB_LPC, "s1_clk_gate_ahb_lpc", "s1_clk_div_ahb_lpc",
+		CLK_SET_RATE_PARENT, 0x2000, 7, 0 },
+	{ GATE_CLK_EFUSE, "s1_clk_gate_efuse", "s1_clk_div_efuse",
+		CLK_SET_RATE_PARENT, 0x2000, 20, 0},
+	{ GATE_CLK_TOP_AXI0, "s1_clk_gate_top_axi0", "s1_clk_div_top_axi0",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 },
+	{ GATE_CLK_TOP_AXI_HSPERI, "s1_clk_gate_top_axi_hsperi", "s1_clk_div_top_axi_hsperi",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 },
+	{ GATE_CLK_AHB_ROM, "s1_clk_gate_ahb_rom", "s1_clk_gate_top_axi0",
+		0, 0x2000, 8, 0 },
+	{ GATE_CLK_AHB_SF, "s1_clk_gate_ahb_sf", "s1_clk_gate_top_axi0",
+		0, 0x2000, 9, 0 },
+	{ GATE_CLK_AXI_SRAM, "s1_clk_gate_axi_sram", "s1_clk_gate_top_axi0",
+		CLK_IGNORE_UNUSED, 0x2000, 10, 0 },
+	{ GATE_CLK_APB_TIMER, "s1_clk_gate_apb_timer", "s1_clk_gate_top_axi0",
+		CLK_IGNORE_UNUSED, 0x2000, 11, 0 },
+	{ GATE_CLK_APB_EFUSE, "s1_clk_gate_apb_efuse", "s1_clk_gate_top_axi0",
+		0, 0x2000, 21, 0 },
+	{ GATE_CLK_APB_GPIO, "s1_clk_gate_apb_gpio", "s1_clk_gate_top_axi0",
+		0, 0x2000, 22, 0 },
+	{ GATE_CLK_APB_GPIO_INTR, "s1_clk_gate_apb_gpio_intr", "s1_clk_gate_top_axi0",
+		0, 0x2000, 23, 0 },
+	{ GATE_CLK_APB_I2C, "s1_clk_gate_apb_i2c", "s1_clk_gate_top_axi0",
+		0, 0x2000, 26, 0 },
+	{ GATE_CLK_APB_WDT, "s1_clk_gate_apb_wdt", "s1_clk_gate_top_axi0",
+		0, 0x2000, 27, 0 },
+	{ GATE_CLK_APB_PWM, "s1_clk_gate_apb_pwm", "s1_clk_gate_top_axi0",
+		0, 0x2000, 28, 0 },
+	{ GATE_CLK_APB_RTC, "s1_clk_gate_apb_rtc", "s1_clk_gate_top_axi0",
+		0, 0x2000, 29, 0 },
+	{ GATE_CLK_SYSDMA_AXI, "s1_clk_gate_sysdma_axi", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 3, 0 },
+	{ GATE_CLK_APB_UART, "s1_clk_gate_apb_uart", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 5, 0 },
+	{ GATE_CLK_AXI_DBG_I2C, "s1_clk_gate_axi_dbg_i2c", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 6, 0 },
+	{ GATE_CLK_APB_SPI, "s1_clk_gate_apb_spi", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 25, 0 },
+	{ GATE_CLK_AXI_ETH0, "s1_clk_gate_axi_eth0", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2000, 31, 0 },
+	{ GATE_CLK_AXI_EMMC, "s1_clk_gate_axi_emmc", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2004, 2, 0 },
+	{ GATE_CLK_AXI_SD, "s1_clk_gate_axi_sd", "s1_clk_gate_top_axi_hsperi",
+		CLK_SET_RATE_PARENT, 0x2004, 5, 0 },
+	{ GATE_CLK_TIMER1, "s1_clk_gate_timer1", "s1_clk_div_timer1",
+		CLK_SET_RATE_PARENT, 0x2000, 12, 0 },
+	{ GATE_CLK_TIMER2, "s1_clk_gate_timer2", "s1_clk_div_timer2",
+		CLK_SET_RATE_PARENT, 0x2000, 13, 0 },
+	{ GATE_CLK_TIMER3, "s1_clk_gate_timer3", "s1_clk_div_timer3",
+		CLK_SET_RATE_PARENT, 0x2000, 14, 0 },
+	{ GATE_CLK_TIMER4, "s1_clk_gate_timer4", "s1_clk_div_timer4",
+		CLK_SET_RATE_PARENT, 0x2000, 15, 0 },
+	{ GATE_CLK_TIMER5, "s1_clk_gate_timer5", "s1_clk_div_timer5",
+		CLK_SET_RATE_PARENT, 0x2000, 16, 0 },
+	{ GATE_CLK_TIMER6, "s1_clk_gate_timer6", "s1_clk_div_timer6",
+		CLK_SET_RATE_PARENT, 0x2000, 17, 0 },
+	{ GATE_CLK_TIMER7, "s1_clk_gate_timer7", "s1_clk_div_timer7",
+		CLK_SET_RATE_PARENT, 0x2000, 18, 0 },
+	{ GATE_CLK_TIMER8, "s1_clk_gate_timer8", "s1_clk_div_timer8",
+		CLK_SET_RATE_PARENT, 0x2000, 19, 0 },
+	{ GATE_CLK_100K_EMMC, "s1_clk_gate_100k_emmc", "s1_clk_div_100k_emmc",
+		CLK_SET_RATE_PARENT, 0x2004, 4, 0 },
+	{ GATE_CLK_100K_SD, "s1_clk_gate_100k_sd", "s1_clk_div_100k_sd",
+		CLK_SET_RATE_PARENT, 0x2004, 7, 0 },
+	{ GATE_CLK_GPIO_DB, "s1_clk_gate_gpio_db", "s1_clk_div_gpio_db",
+		CLK_SET_RATE_PARENT, 0x2000, 24, 0 },
+	{ GATE_CLK_DDR01, "s1_clk_gate_ddr01", "s1_clk_mux_ddr01",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 },
+	{ GATE_CLK_DDR23, "s1_clk_gate_ddr23", "s1_clk_mux_ddr23",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 },
+	{ GATE_CLK_RP_CPU_NORMAL, "s1_clk_gate_rp_cpu_normal", "s1_clk_mux_rp_cpu_normal",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
+	{ GATE_CLK_AXI_DDR, "s1_clk_gate_axi_ddr", "s1_clk_mux_axi_ddr",
+		CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
+	{ GATE_CLK_RXU0, "s1_clk_gate_rxu0", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 0, 0 },
+	{ GATE_CLK_RXU1, "s1_clk_gate_rxu1", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 1, 0 },
+	{ GATE_CLK_RXU2, "s1_clk_gate_rxu2", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 2, 0 },
+	{ GATE_CLK_RXU3, "s1_clk_gate_rxu3", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 3, 0 },
+	{ GATE_CLK_RXU4, "s1_clk_gate_rxu4", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 4, 0 },
+	{ GATE_CLK_RXU5, "s1_clk_gate_rxu5", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 5, 0 },
+	{ GATE_CLK_RXU6, "s1_clk_gate_rxu6", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 6, 0 },
+	{ GATE_CLK_RXU7, "s1_clk_gate_rxu7", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 7, 0 },
+	{ GATE_CLK_RXU8, "s1_clk_gate_rxu8", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 8, 0 },
+	{ GATE_CLK_RXU9, "s1_clk_gate_rxu9", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 9, 0 },
+	{ GATE_CLK_RXU10, "s1_clk_gate_rxu10", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 10, 0 },
+	{ GATE_CLK_RXU11, "s1_clk_gate_rxu11", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 11, 0 },
+	{ GATE_CLK_RXU12, "s1_clk_gate_rxu12", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 12, 0 },
+	{ GATE_CLK_RXU13, "s1_clk_gate_rxu13", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 13, 0 },
+	{ GATE_CLK_RXU14, "s1_clk_gate_rxu14", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 14, 0 },
+	{ GATE_CLK_RXU15, "s1_clk_gate_rxu15", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 15, 0 },
+	{ GATE_CLK_RXU16, "s1_clk_gate_rxu16", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 16, 0 },
+	{ GATE_CLK_RXU17, "s1_clk_gate_rxu17", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 17, 0 },
+	{ GATE_CLK_RXU18, "s1_clk_gate_rxu18", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 18, 0 },
+	{ GATE_CLK_RXU19, "s1_clk_gate_rxu19", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 19, 0 },
+	{ GATE_CLK_RXU20, "s1_clk_gate_rxu20", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 20, 0 },
+	{ GATE_CLK_RXU21, "s1_clk_gate_rxu21", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 21, 0 },
+	{ GATE_CLK_RXU22, "s1_clk_gate_rxu22", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 22, 0 },
+	{ GATE_CLK_RXU23, "s1_clk_gate_rxu23", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 23, 0 },
+	{ GATE_CLK_RXU24, "s1_clk_gate_rxu24", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 24, 0 },
+	{ GATE_CLK_RXU25, "s1_clk_gate_rxu25", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 25, 0 },
+	{ GATE_CLK_RXU26, "s1_clk_gate_rxu26", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 26, 0 },
+	{ GATE_CLK_RXU27, "s1_clk_gate_rxu27", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 27, 0 },
+	{ GATE_CLK_RXU28, "s1_clk_gate_rxu28", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 28, 0 },
+	{ GATE_CLK_RXU29, "s1_clk_gate_rxu29", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 29, 0 },
+	{ GATE_CLK_RXU30, "s1_clk_gate_rxu30", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 30, 0 },
+	{ GATE_CLK_RXU31, "s1_clk_gate_rxu31", "s1_clk_gate_rp_cpu_normal",
+		0, 0x368, 31, 0 },
+	{ GATE_CLK_MP0, "s1_clk_gate_mp0", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 },
+	{ GATE_CLK_MP1, "s1_clk_gate_mp1", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 },
+	{ GATE_CLK_MP2, "s1_clk_gate_mp2", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 },
+	{ GATE_CLK_MP3, "s1_clk_gate_mp3", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 },
+	{ GATE_CLK_MP4, "s1_clk_gate_mp4", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 },
+	{ GATE_CLK_MP5, "s1_clk_gate_mp5", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 },
+	{ GATE_CLK_MP6, "s1_clk_gate_mp6", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 },
+	{ GATE_CLK_MP7, "s1_clk_gate_mp7", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 },
+	{ GATE_CLK_MP8, "s1_clk_gate_mp8", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 },
+	{ GATE_CLK_MP9, "s1_clk_gate_mp9", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 },
+	{ GATE_CLK_MP10, "s1_clk_gate_mp10", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 },
+	{ GATE_CLK_MP11, "s1_clk_gate_mp11", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 },
+	{ GATE_CLK_MP12, "s1_clk_gate_mp12", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 },
+	{ GATE_CLK_MP13, "s1_clk_gate_mp13", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 },
+	{ GATE_CLK_MP14, "s1_clk_gate_mp14", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 },
+	{ GATE_CLK_MP15, "s1_clk_gate_mp15", "s1_clk_gate_rp_cpu_normal",
+		CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 },
+};
+
+/* socket0 mux clocks */
+static const char *const clk_mux_ddr01_p[] = {
+			"clk_div_ddr01_0", "clk_div_ddr01_1"};
+static const char *const clk_mux_ddr23_p[] = {
+			"clk_div_ddr23_0", "clk_div_ddr23_1"};
+static const char *const clk_mux_rp_cpu_normal_p[] = {
+			"clk_div_rp_cpu_normal_0", "clk_div_rp_cpu_normal_1"};
+static const char *const clk_mux_axi_ddr_p[] = {
+			"clk_div_axi_ddr_0", "clk_div_axi_ddr_1"};
+
+struct mango_mux_clock s0_mux_clks[] = {
+	{
+		MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p,
+		ARRAY_SIZE(clk_mux_ddr01_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
+			CLK_MUX_READ_ONLY,
+		0x2020, 2, 1, 0,
+	},
+	{
+		MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p,
+		ARRAY_SIZE(clk_mux_ddr23_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
+			CLK_MUX_READ_ONLY,
+		0x2020, 3, 1, 0,
+	},
+	{
+		MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p,
+		ARRAY_SIZE(clk_mux_rp_cpu_normal_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		0x2020, 0, 1, 0,
+	},
+	{
+		MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p,
+		ARRAY_SIZE(clk_mux_axi_ddr_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		0x2020, 1, 1, 0,
+	},
+};
+
+/* socket1 mux clocks */
+static const char *const s1_clk_mux_ddr01_p[] = {
+			"s1_clk_div_ddr01_0", "s1_clk_div_ddr01_1"};
+static const char *const s1_clk_mux_ddr23_p[] = {
+			"s1_clk_div_ddr23_0", "s1_clk_div_ddr23_1"};
+static const char *const s1_clk_mux_rp_cpu_normal_p[] = {
+			"s1_clk_div_rp_cpu_normal_0", "s1_clk_div_rp_cpu_normal_1"};
+static const char *const s1_clk_mux_axi_ddr_p[] = {
+			"s1_clk_div_axi_ddr_0", "s1_clk_div_axi_ddr_1"};
+
+struct mango_mux_clock s1_mux_clks[] = {
+	{
+		MUX_CLK_DDR01, "s1_clk_mux_ddr01", s1_clk_mux_ddr01_p,
+		ARRAY_SIZE(s1_clk_mux_ddr01_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
+			CLK_MUX_READ_ONLY,
+		0x2020, 2, 1, 0,
+	},
+	{
+		MUX_CLK_DDR23, "s1_clk_mux_ddr23", s1_clk_mux_ddr23_p,
+		ARRAY_SIZE(s1_clk_mux_ddr23_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
+			CLK_MUX_READ_ONLY,
+		0x2020, 3, 1, 0,
+	},
+	{
+		MUX_CLK_RP_CPU_NORMAL, "s1_clk_mux_rp_cpu_normal", s1_clk_mux_rp_cpu_normal_p,
+		ARRAY_SIZE(s1_clk_mux_rp_cpu_normal_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		0x2020, 0, 1, 0,
+	},
+	{
+		MUX_CLK_AXI_DDR, "s1_clk_mux_axi_ddr", s1_clk_mux_axi_ddr_p,
+		ARRAY_SIZE(s1_clk_mux_axi_ddr_p),
+		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+		0x2020, 1, 1, 0,
+	},
+};
+
+struct mango_clk_table pll_clk_tables = {
+	.pll_clks_num = ARRAY_SIZE(mango_root_pll_clks),
+	.pll_clks = mango_root_pll_clks,
+};
+
+struct mango_clk_table div_clk_tables[] = {
+	{
+		.id = S0_DIV_CLK_TABLE,
+		.div_clks_num = ARRAY_SIZE(s0_div_clks),
+		.div_clks = s0_div_clks,
+		.gate_clks_num = ARRAY_SIZE(s0_gate_clks),
+		.gate_clks = s0_gate_clks,
+	},{
+		.id = S1_DIV_CLK_TABLE,
+		.div_clks_num = ARRAY_SIZE(s1_div_clks),
+		.div_clks = s1_div_clks,
+		.gate_clks_num = ARRAY_SIZE(s1_gate_clks),
+		.gate_clks = s1_gate_clks,
+	},
+};
+
+struct mango_clk_table mux_clk_tables[] = {
+	{
+		.id = S0_MUX_CLK_TABLE,
+		.mux_clks_num = ARRAY_SIZE(s0_mux_clks),
+		.mux_clks = s0_mux_clks,
+	},{
+		.id = S1_MUX_CLK_TABLE,
+		.mux_clks_num = ARRAY_SIZE(s1_mux_clks),
+		.mux_clks = s1_mux_clks,
+	},
+};
+
+static const struct of_device_id mango_clk_match_ids_tables[] = {
+	{
+		.compatible = "mango, pll-clock",
+		.data = &pll_clk_tables,
+	},
+	{
+		.compatible = "mango, pll-child-clock",
+		.data = div_clk_tables,
+	},
+	{
+		.compatible = "mango, pll-mux-clock",
+		.data = mux_clk_tables,
+	},
+	{
+		.compatible = "mango, clk-default-rates",
+	},
+	{
+		.compatible = "mango, dm-pll-clock",
+		.data = &pll_clk_tables,
+	},
+	{
+		.compatible = "mango, dm-pll-child-clock",
+		.data = div_clk_tables,
+	},
+	{
+		.compatible = "mango, dm-pll-mux-clock",
+		.data = mux_clk_tables,
+	},
+	{
+		.compatible = "mango, dm-clk-default-rates",
+	},
+	{}
+};
+
+static void __init mango_clk_init(struct device_node *node)
+{
+	struct device_node *np_top;
+	struct mango_clk_data *clk_data = NULL;
+	const struct mango_clk_table *dev_data;
+	struct regmap *syscon;
+	void __iomem *base;
+	int i, ret = 0;
+	unsigned int id;
+	const char *clk_name;
+	const struct of_device_id *match = NULL;
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	match = of_match_node(mango_clk_match_ids_tables, node);
+	if (match) {
+		dev_data = (struct mango_clk_table *)match->data;
+	} else {
+		pr_err("%s did't match node data\n", __func__);
+		ret = -ENODEV;
+		goto no_match_data;
+	}
+
+	np_top = of_parse_phandle(node, "subctrl-syscon", 0);
+	if (!np_top) {
+		pr_err("%s can't get subctrl-syscon node\n",
+			__func__);
+		ret = -EINVAL;
+		goto no_match_data;
+	}
+
+	syscon = device_node_to_regmap(np_top);
+	if (IS_ERR_OR_NULL(syscon)) {
+		pr_err("%s cannot get regmap %ld\n", __func__, PTR_ERR(syscon));
+		ret = -ENODEV;
+		goto no_match_data;
+	}
+	base = of_iomap(np_top, 0);
+
+	spin_lock_init(&clk_data->lock);
+	if (of_device_is_compatible(node, "mango, pll-clock") ||
+	    of_device_is_compatible(node, "mango, dm-pll-clock")) {
+		if (!dev_data->pll_clks_num) {
+			ret = -EINVAL;
+			goto no_match_data;
+		}
+
+		clk_data->table = dev_data;
+		clk_data->base = base;
+		clk_data->syscon_top = syscon;
+
+		if (of_property_read_string(node, "clock-output-names", &clk_name)) {
+			pr_err("%s cannot get pll name for %s\n",
+				__func__, node->full_name);
+			ret = -ENODEV;
+			goto no_match_data;
+		}
+		if (of_device_is_compatible(node, "mango, pll-clock"))
+			ret = mango_register_pll_clks(node, clk_data, clk_name);
+		else
+			ret = dm_mango_register_pll_clks(node, clk_data, clk_name);
+	}
+
+	if (of_device_is_compatible(node, "mango, pll-child-clock") ||
+	    of_device_is_compatible(node, "mango, dm-pll-child-clock")) {
+		ret = of_property_read_u32(node, "id", &id);
+		if (ret) {
+			pr_err("not assigned id for %s\n", node->full_name);
+			ret = -ENODEV;
+			goto no_match_data;
+		}
+
+		/* Below brute-force to check dts property "id"
+		 * whether match id of array
+		 */
+		for (i = 0; i < ARRAY_SIZE(div_clk_tables); i++) {
+			if (id == dev_data[i].id)
+				break; /* found */
+		}
+		clk_data->table = &dev_data[i];
+		clk_data->base = base;
+		clk_data->syscon_top = syscon;
+		if (of_device_is_compatible(node, "mango, pll-child-clock"))
+			ret = mango_register_div_clks(node, clk_data);
+		else
+			ret = dm_mango_register_div_clks(node, clk_data);
+	}
+
+	if (of_device_is_compatible(node, "mango, pll-mux-clock") ||
+	    of_device_is_compatible(node, "mango, dm-pll-mux-clock")) {
+		ret = of_property_read_u32(node, "id", &id);
+		if (ret) {
+			pr_err("not assigned id for %s\n", node->full_name);
+			ret = -ENODEV;
+			goto no_match_data;
+		}
+
+		/* Below brute-force to check dts property "id"
+		 * whether match id of array
+		 */
+		for (i = 0; i < ARRAY_SIZE(mux_clk_tables); i++) {
+			if (id == dev_data[i].id)
+				break; /* found */
+		}
+		clk_data->table = &dev_data[i];
+		clk_data->base = base;
+		clk_data->syscon_top = syscon;
+		if (of_device_is_compatible(node, "mango, pll-mux-clock"))
+			ret = mango_register_mux_clks(node, clk_data);
+		else
+			ret = dm_mango_register_mux_clks(node, clk_data);
+	}
+
+	if (of_device_is_compatible(node, "mango, clk-default-rates"))
+		ret = set_default_clk_rates(node);
+
+	if (of_device_is_compatible(node, "mango, dm-clk-default-rates"))
+		ret = dm_set_default_clk_rates(node);
+
+	if (!ret)
+		return;
+
+no_match_data:
+	kfree(clk_data);
+
+out:
+	pr_err("%s failed error number %d\n", __func__, ret);
+}
+
+CLK_OF_DECLARE(mango_clk_pll, "mango, pll-clock", mango_clk_init);
+CLK_OF_DECLARE(mango_clk_pll_child, "mango, pll-child-clock", mango_clk_init);
+CLK_OF_DECLARE(mango_clk_pll_mux, "mango, pll-mux-clock", mango_clk_init);
+CLK_OF_DECLARE(mango_clk_default_rate, "mango, clk-default-rates", mango_clk_init);
+CLK_OF_DECLARE(dm_mango_clk_pll, "mango, dm-pll-clock", mango_clk_init);
+CLK_OF_DECLARE(dm_mango_clk_pll_child, "mango, dm-pll-child-clock", mango_clk_init);
+CLK_OF_DECLARE(dm_mango_clk_pll_mux, "mango, dm-pll-mux-clock", mango_clk_init);
+CLK_OF_DECLARE(dm_mango_clk_default_rate, "mango, dm-clk-default-rates", mango_clk_init);
diff --git a/drivers/clk/sophgo/clk.c b/drivers/clk/sophgo/clk.c
new file mode 100644
index 000000000000..9ce4dc89ea9c
--- /dev/null
+++ b/drivers/clk/sophgo/clk.c
@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 2022 SOPHGO
+ *
+ * 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.
+ */
+
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/string.h>
+#include <linux/log2.h>
+
+#include "clk.h"
+
+/*
+ * @hw:		handle between common and hardware-specific interfaces
+ * @reg:	register containing divider
+ * @shift:	shift to the divider bit field
+ * @width:	width of the divider bit field
+ * @initial_val:initial value of the divider
+ * @table:	the div table that the divider supports
+ * @lock:	register lock
+ */
+struct mango_clk_divider {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+	u8		shift;
+	u8		width;
+	u8		flags;
+	u32		initial_val;
+	const struct clk_div_table *table;
+	spinlock_t	*lock;
+};
+
+static inline int mango_pll_enable(struct regmap *map,
+					struct mango_pll_clock *pll, bool en)
+{
+	unsigned int value;
+	unsigned long enter;
+	unsigned int id = pll->id;
+
+	if (en) {
+		/* wait pll lock */
+		enter = jiffies;
+		regmap_read(map, pll->status_offset, &value);
+		while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) {
+			regmap_read(map, pll->status_offset, &value);
+			if (time_after(jiffies, enter + HZ / 10))
+				pr_warn("%s not locked\n", pll->name);
+		}
+		/* wait pll updating */
+		enter = jiffies;
+		regmap_read(map, pll->status_offset, &value);
+		while (((value >> id) & 0x1)) {
+			regmap_read(map, pll->status_offset, &value);
+			if (time_after(jiffies, enter + HZ / 10))
+				pr_warn("%s still updating\n", pll->name);
+		}
+		/* enable pll */
+		regmap_read(map, pll->enable_offset, &value);
+		regmap_write(map, pll->enable_offset, value | (1 << id));
+	} else {
+		/* disable pll */
+		regmap_read(map, pll->enable_offset, &value);
+		regmap_write(map, pll->enable_offset, value & (~(1 << id)));
+	}
+
+	return 0;
+}
+
+static inline int mango_pll_write(struct regmap *map, int id, int value)
+{
+	return regmap_write(map, PLL_CTRL_OFFSET + (id << 2), value);
+}
+
+static inline int mango_pll_read(struct regmap *map, int id, unsigned int *pvalue)
+{
+	return regmap_read(map, PLL_CTRL_OFFSET + (id << 2), pvalue);
+}
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+				   unsigned int val)
+{
+	const struct clk_div_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val == val)
+			return clkt->div;
+	return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+			     unsigned int val, unsigned long flags, u8 width)
+{
+	if (flags & CLK_DIVIDER_ONE_BASED)
+		return val;
+	if (flags & CLK_DIVIDER_POWER_OF_TWO)
+		return 1 << val;
+	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
+		return val ? val : div_mask(width) + 1;
+	if (table)
+		return _get_table_div(table, val);
+	return val + 1;
+}
+
+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct mango_clk_divider *divider = to_mango_clk_divider(hw);
+	unsigned int val;
+
+	val = readl(divider->reg) >> divider->shift;
+	val &= div_mask(divider->width);
+
+#ifdef CONFIG_ARCH_BM1880
+	/* if select divide factor from initial value */
+	if (!(readl(divider->reg) & BIT(3)))
+		val = divider->initial_val;
+#endif
+
+	return divider_recalc_rate(hw, parent_rate, val, divider->table,
+				   divider->flags, divider->width);
+}
+
+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				      unsigned long *prate)
+{
+	int bestdiv;
+	struct mango_clk_divider *divider = to_mango_clk_divider(hw);
+
+	/* if read only, just return current value */
+	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+		bestdiv = readl(divider->reg) >> divider->shift;
+		bestdiv &= div_mask(divider->width);
+		bestdiv = _get_div(divider->table, bestdiv, divider->flags,
+				   divider->width);
+		return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
+	}
+
+	return divider_round_rate(hw, rate, prate, divider->table,
+				  divider->width, divider->flags);
+}
+
+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	unsigned int value;
+	unsigned int val;
+	unsigned long flags = 0;
+	struct mango_clk_divider *divider = to_mango_clk_divider(hw);
+
+	value = divider_get_val(rate, parent_rate, divider->table,
+				divider->width, divider->flags);
+
+	if (divider->lock)
+		spin_lock_irqsave(divider->lock, flags);
+	else
+		__acquire(divider->lock);
+
+	/* div assert */
+	val = readl(divider->reg);
+	val &= ~0x1;
+	writel(val, divider->reg);
+
+	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+		val = div_mask(divider->width) << (divider->shift + 16);
+	} else {
+		val = readl(divider->reg);
+		val &= ~(div_mask(divider->width) << divider->shift);
+	}
+
+	val |= value << divider->shift;
+	writel(val, divider->reg);
+
+	if (!(divider->flags & CLK_DIVIDER_READ_ONLY))
+		val |= 1 << 3;
+
+	/* de-assert */
+	val |= 1;
+	writel(val, divider->reg);
+	if (divider->lock)
+		spin_unlock_irqrestore(divider->lock, flags);
+	else
+		__release(divider->lock);
+
+	return 0;
+}
+
+/* Below array is the total combination lists of POSTDIV1 and POSTDIV2
+ * for example:
+ * postdiv1_2[0] = {1, 1, 1}
+ *           ==> div1 = 1, div2 = 1 , div1 * div2 = 1
+ * postdiv1_2[22] = {6, 7, 42}
+ *           ==> div1 = 6, div2 = 7 , div1 * div2 = 42
+ *
+ * And POSTDIV_RESULT_INDEX point to 3rd element in the array
+ */
+#define	POSTDIV_RESULT_INDEX	2
+int postdiv1_2[][3] = {
+	{2, 4,  8}, {3, 3,  9}, {2, 5, 10}, {2, 6, 12},
+	{2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18},
+	{4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25},
+	{4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36},
+	{6, 7, 42}, {7, 7, 49}
+};
+
+static inline unsigned long abs_diff(unsigned long a, unsigned long b)
+{
+	return (a > b) ? (a - b) : (b - a);
+}
+
+/*
+ * @reg_value: current register value
+ * @parent_rate: parent frequency
+ *
+ * This function is used to calculate below "rate" in equation
+ * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2
+ *      = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2)
+ */
+static unsigned long __pll_recalc_rate(unsigned int reg_value,
+				       unsigned long parent_rate)
+{
+	unsigned int fbdiv, refdiv;
+	unsigned int postdiv1, postdiv2;
+	u64 rate, numerator, denominator;
+
+	fbdiv = (reg_value >> 16) & 0xfff;
+	refdiv = reg_value & 0x3f;
+	postdiv1 = (reg_value >> 8) & 0x7;
+	postdiv2 = (reg_value >> 12) & 0x7;
+
+	numerator = parent_rate * fbdiv;
+	denominator = refdiv * postdiv1 * postdiv2;
+	do_div(numerator, denominator);
+	rate = numerator;
+
+	return rate;
+}
+
+/*
+ * @reg_value: current register value
+ * @rate: request rate
+ * @prate: parent rate
+ * @pctrl_table: use to save div1/div2/fbdiv/refdiv
+ *
+ * We use below equation to get POSTDIV1 and POSTDIV2
+ * POSTDIV = (parent_rate/REFDIV) x FBDIV/input_rate
+ * above POSTDIV = POSTDIV1*POSTDIV2
+ */
+static int __pll_get_postdiv_1_2(unsigned long rate, unsigned long prate,
+				 unsigned int fbdiv, unsigned int refdiv, unsigned int *postdiv1,
+				 unsigned int *postdiv2)
+{
+	int index = 0;
+	int ret = 0;
+	u64 tmp0;
+
+	/* calculate (parent_rate/refdiv)
+	 * and result save to prate
+	 */
+	tmp0 = prate;
+	do_div(tmp0, refdiv);
+
+	/* calcuate ((parent_rate/REFDIV) x FBDIV)
+	 * and result save to prate
+	 */
+	tmp0 *= fbdiv;
+
+	/* calcuate (((parent_rate/REFDIV) x FBDIV)/input_rate)
+	 * and result save to prate
+	 * here *prate is (POSTDIV1*POSTDIV2)
+	 */
+	do_div(tmp0, rate);
+
+	/* calculate div1 and div2 value */
+	if (tmp0 <= 7) {
+		/* (div1 * div2) <= 7, no need to use array search */
+		*postdiv1 = tmp0;
+		*postdiv2 = 1;
+	} else {
+		/* (div1 * div2) > 7, use array search */
+		for (index = 0; index < ARRAY_SIZE(postdiv1_2); index++) {
+			if (tmp0 > postdiv1_2[index][POSTDIV_RESULT_INDEX]) {
+				continue;
+			} else {
+				/* found it */
+				break;
+			}
+		}
+		if (index < ARRAY_SIZE(postdiv1_2)) {
+			*postdiv1 = postdiv1_2[index][1];
+			*postdiv2 = postdiv1_2[index][0];
+		} else {
+			pr_debug("%s out of postdiv array range!\n", __func__);
+			ret = -ESPIPE;
+		}
+	}
+
+	return ret;
+}
+
+static int __get_pll_ctl_setting(struct mango_pll_ctrl *best,
+			unsigned long req_rate, unsigned long parent_rate)
+{
+	int ret;
+	unsigned int fbdiv, refdiv, fref, postdiv1, postdiv2;
+	unsigned long tmp = 0, foutvco;
+
+	fref = parent_rate;
+
+	for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) {
+		for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) {
+			foutvco = fref * fbdiv / refdiv;
+			/* check fpostdiv pfd */
+			if (foutvco < PLL_FREQ_MIN || foutvco > PLL_FREQ_MAX
+					|| (fref / refdiv) < 10)
+				continue;
+
+			ret = __pll_get_postdiv_1_2(req_rate, fref, fbdiv,
+					refdiv, &postdiv1, &postdiv2);
+			if (ret)
+				continue;
+
+			tmp = foutvco / (postdiv1 * postdiv2);
+			if (abs_diff(tmp, req_rate) < abs_diff(best->freq, req_rate)) {
+				best->freq = tmp;
+				best->refdiv = refdiv;
+				best->fbdiv = fbdiv;
+				best->postdiv1 = postdiv1;
+				best->postdiv2 = postdiv2;
+				if (tmp == req_rate)
+					return 0;
+			}
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @hw: ccf use to hook get mango_pll_clock
+ * @parent_rate: parent rate
+ *
+ * The is function will be called through clk_get_rate
+ * and return current rate after decoding reg value
+ */
+static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	unsigned int value;
+	unsigned long rate;
+	struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw);
+
+	mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value);
+	rate = __pll_recalc_rate(value, parent_rate);
+	return rate;
+}
+
+static long mango_clk_pll_round_rate(struct clk_hw *hw,
+				  unsigned long req_rate, unsigned long *prate)
+{
+	unsigned int value;
+	struct mango_pll_ctrl pctrl_table;
+	struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw);
+	long proper_rate;
+
+	memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl));
+
+	/* use current setting to get fbdiv, refdiv
+	 * then combine with prate, and req_rate to
+	 * get postdiv1 and postdiv2
+	 */
+	mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value);
+	__get_pll_ctl_setting(&pctrl_table, req_rate, *prate);
+	if (!pctrl_table.freq) {
+		proper_rate = 0;
+		goto out;
+	}
+
+	value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1,
+			     pctrl_table.postdiv2, pctrl_table.refdiv);
+	proper_rate = (long)__pll_recalc_rate(value, *prate);
+
+out:
+	return proper_rate;
+}
+
+static int mango_clk_pll_determine_rate(struct clk_hw *hw,
+				     struct clk_rate_request *req)
+{
+	req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate),
+					  &req->best_parent_rate);
+	return 0;
+}
+
+static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	unsigned long flags;
+	unsigned int value;
+	int ret = 0;
+	struct mango_pll_ctrl pctrl_table;
+	struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw);
+
+	memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl));
+	spin_lock_irqsave(mango_pll->lock, flags);
+	if (mango_pll_enable(mango_pll->syscon_top, mango_pll, 0)) {
+		pr_warn("Can't disable pll(%s), status error\n", mango_pll->name);
+		goto out;
+	}
+	mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value);
+	__get_pll_ctl_setting(&pctrl_table, rate, parent_rate);
+	if (!pctrl_table.freq) {
+		pr_warn("%s: Can't find a proper pll setting\n", mango_pll->name);
+		goto out;
+	}
+
+	value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1,
+			     pctrl_table.postdiv2, pctrl_table.refdiv);
+
+	/* write the value to top register */
+	mango_pll_write(mango_pll->syscon_top, mango_pll->id, value);
+	mango_pll_enable(mango_pll->syscon_top, mango_pll, 1);
+out:
+	spin_unlock_irqrestore(mango_pll->lock, flags);
+	return ret;
+}
+
+const struct clk_ops mango_clk_divider_ops = {
+	.recalc_rate = mango_clk_divider_recalc_rate,
+	.round_rate = mango_clk_divider_round_rate,
+	.set_rate = mango_clk_divider_set_rate,
+};
+
+const struct clk_ops mango_clk_divider_ro_ops = {
+	.recalc_rate = mango_clk_divider_recalc_rate,
+	.round_rate = mango_clk_divider_round_rate,
+};
+
+const struct clk_ops mango_clk_pll_ops = {
+	.recalc_rate = mango_clk_pll_recalc_rate,
+	.round_rate = mango_clk_pll_round_rate,
+	.determine_rate = mango_clk_pll_determine_rate,
+	.set_rate = mango_clk_pll_set_rate,
+};
+
+const struct clk_ops mango_clk_pll_ro_ops = {
+	.recalc_rate = mango_clk_pll_recalc_rate,
+	.round_rate = mango_clk_pll_round_rate,
+};
+
+struct mux_cb_clk_name {
+	const char *name;
+	struct list_head node;
+};
+
+static struct list_head mux_cb_clk_name_list =
+	LIST_HEAD_INIT(mux_cb_clk_name_list);
+static int mux_notifier_cb(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	int ret = 0;
+	static unsigned char mux_id = 1;
+	struct clk_notifier_data *ndata = data;
+	struct clk_hw *hw = __clk_get_hw(ndata->clk);
+	const struct clk_ops *ops = &clk_mux_ops;
+	struct mux_cb_clk_name *cb_lsit;
+
+	if (event == PRE_RATE_CHANGE) {
+		struct clk_hw *hw_p = clk_hw_get_parent(hw);
+
+		cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL);
+		if (cb_lsit) {
+			INIT_LIST_HEAD(&cb_lsit->node);
+			list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list);
+		} else {
+			pr_err("mux cb kmalloc mem fail\n");
+			goto out;
+		}
+
+		cb_lsit->name = clk_hw_get_name(hw_p);
+		mux_id = ops->get_parent(hw);
+		if (mux_id > 1) {
+			ret = 1;
+			goto out;
+		}
+		ops->set_parent(hw, !mux_id);
+	} else if (event == POST_RATE_CHANGE) {
+		struct clk_hw *hw_p = clk_hw_get_parent(hw);
+
+		cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list,
+						typeof(*cb_lsit), node);
+		if (cb_lsit) {
+			const char *pre_name = cb_lsit->name;
+
+			list_del_init(&cb_lsit->node);
+			kfree(cb_lsit);
+			if (strcmp(clk_hw_get_name(hw_p), pre_name))
+				goto out;
+		}
+
+		ops->set_parent(hw, mux_id);
+	}
+
+out:
+	return notifier_from_errno(ret);
+}
+
+int set_default_clk_rates(struct device_node *node)
+{
+	struct of_phandle_args clkspec;
+	struct property *prop;
+	const __be32 *cur;
+	int rc, index = 0;
+	struct clk *clk;
+	u32 rate;
+
+	of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
+		if (rate) {
+			rc = of_parse_phandle_with_args(node, "clocks",
+							"#clock-cells", index, &clkspec);
+			if (rc < 0) {
+				/* skip empty (null) phandles */
+				if (rc == -ENOENT)
+					continue;
+				else
+					return rc;
+			}
+
+			clk = of_clk_get_from_provider(&clkspec);
+			if (IS_ERR(clk)) {
+				pr_warn("clk: couldn't get clock %d for %s\n",
+					index, node->full_name);
+				return PTR_ERR(clk);
+			}
+
+			rc = clk_set_rate(clk, rate);
+			if (rc < 0)
+				pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+				       __clk_get_name(clk), rate, rc,
+				       clk_get_rate(clk));
+			clk_put(clk);
+		}
+		index++;
+	}
+
+	return 0;
+}
+
+static struct clk *__register_divider_clks(struct device *dev, const char *name,
+					   const char *parent_name,
+					   unsigned long flags,
+					   void __iomem *reg, u8 shift,
+					   u8 width, u32 initial_val,
+					   u8 clk_divider_flags,
+					   const struct clk_div_table *table,
+					   spinlock_t *lock)
+{
+	struct mango_clk_divider *div;
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+		if (width + shift > 16) {
+			pr_warn("divider value exceeds LOWORD field\n");
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
+	/* allocate the divider */
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+		init.ops = &mango_clk_divider_ro_ops;
+	else
+		init.ops = &mango_clk_divider_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	/* struct mango_clk_divider assignments */
+	div->reg = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = clk_divider_flags;
+	div->lock = lock;
+	div->hw.init = &init;
+	div->table = table;
+	div->initial_val = initial_val;
+
+	/* register the clock */
+	hw = &div->hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(div);
+		hw = ERR_PTR(ret);
+		return ERR_PTR(-EBUSY);
+	}
+
+	return hw->clk;
+}
+
+static inline int register_provider_clks
+(struct device_node *node, struct mango_clk_data *clk_data, int clk_num)
+{
+	return of_clk_add_provider(node, of_clk_src_onecell_get,
+				   &clk_data->clk_data);
+}
+
+static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_gate_clock *gate_clks = table->gate_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->gate_clks_num;
+	int i;
+
+	for (i = 0; i < clk_num; i++) {
+		clk = clk_register_gate(
+			dev, gate_clks[i].name, gate_clks[i].parent_name,
+			gate_clks[i].flags, base + gate_clks[i].offset,
+			gate_clks[i].bit_idx, gate_clks[i].gate_flags,
+			&clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				gate_clks[i].name);
+			goto err;
+		}
+
+		if (gate_clks[i].alias)
+			clk_register_clkdev(clk, gate_clks[i].alias, NULL);
+
+		clk_data->clk_data.clks[gate_clks[i].id] = clk;
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_gate(clk_data->clk_data.clks[gate_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static int register_divider_clks(struct device *dev,
+				 struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_divider_clock *div_clks = table->div_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->div_clks_num;
+	int i, val;
+
+	for (i = 0; i < clk_num; i++) {
+		clk = __register_divider_clks(
+			NULL, div_clks[i].name, div_clks[i].parent_name,
+			div_clks[i].flags, base + div_clks[i].offset,
+			div_clks[i].shift, div_clks[i].width,
+			div_clks[i].initial_val,
+			(div_clks[i].initial_sel & MANGO_CLK_USE_INIT_VAL) ?
+				div_clks[i].div_flags | CLK_DIVIDER_READ_ONLY :
+				div_clks[i].div_flags,
+			div_clks[i].table, &clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				div_clks[i].name);
+			goto err;
+		}
+
+		clk_data->clk_data.clks[div_clks[i].id] = clk;
+
+		if (div_clks[i].initial_sel == MANGO_CLK_USE_REG_VAL) {
+			regmap_read(clk_data->syscon_top, div_clks[i].offset,
+				    &val);
+
+			/*
+			 * set a default divider factor,
+			 * clk driver should not select divider clock as the
+			 * clock source, before set the divider by right process
+			 * (assert div, set div factor, de assert div).
+			 */
+			if (div_clks[i].initial_val > 0)
+				val |= (div_clks[i].initial_val << 16 | 1 << 3);
+			else {
+				/*
+				 * the div register is config to use divider factor, don't change divider
+				 */
+				if (!(val >> 3 & 0x1))
+					val |= 1 << 16;
+			}
+
+			regmap_write(clk_data->syscon_top, div_clks[i].offset,
+				     val);
+		}
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_divider(clk_data->clk_data.clks[div_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data)
+{
+	struct clk *clk;
+	const struct mango_clk_table *table = clk_data->table;
+	const struct mango_mux_clock *mux_clks = table->mux_clks;
+	void __iomem *base = clk_data->base;
+	int clk_num = table->mux_clks_num;
+	int i;
+
+	for (i = 0; i < clk_num; i++) {
+		u32 mask = BIT(mux_clks[i].width) - 1;
+
+		clk = clk_register_mux_table(
+			dev, mux_clks[i].name, mux_clks[i].parent_names,
+			mux_clks[i].num_parents, mux_clks[i].flags,
+			base + mux_clks[i].offset, mux_clks[i].shift, mask,
+			mux_clks[i].mux_flags, mux_clks[i].table,
+			&clk_data->lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				mux_clks[i].name);
+			goto err;
+		}
+
+		clk_data->clk_data.clks[mux_clks[i].id] = clk;
+
+		if (!(mux_clks[i].flags & CLK_MUX_READ_ONLY)) {
+			struct clk *parent;
+			struct notifier_block *clk_nb;
+
+			/* set mux clock default parent here, it's parent index
+			 * value is read from the mux clock reg. dts can override
+			 * setting the mux clock parent later.
+			 */
+			parent = clk_get_parent(clk);
+			clk_set_parent(clk, parent);
+
+			/* add a notify callback function */
+			clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL);
+			if (!clk_nb)
+				goto err;
+			clk_nb->notifier_call = mux_notifier_cb;
+			if (clk_notifier_register(clk, clk_nb))
+				pr_err("%s: failed to register clock notifier for %s\n",
+					__func__, mux_clks[i].name);
+		}
+	}
+
+	return 0;
+
+err:
+	while (i--)
+		clk_unregister_mux(clk_data->clk_data.clks[mux_clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+/* pll clock init */
+int mango_register_pll_clks(struct device_node *node,
+			 struct mango_clk_data *clk_data, const char *clk_name)
+{
+	struct clk *clk = NULL;
+	struct mango_pll_clock *pll_clks;
+	int i, ret = 0;
+	const struct clk_ops *local_ops;
+
+	pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks;
+	for (i = 0; i < clk_data->table->pll_clks_num; i++) {
+		if (!strcmp(clk_name,  pll_clks[i].name)) {
+			/* have to assigne pll_clks.syscon_top first
+			 * since clk_register_composite will need it
+			 * to calculate current rate.
+			 */
+			pll_clks[i].syscon_top = clk_data->syscon_top;
+			pll_clks[i].lock = &clk_data->lock;
+			if (pll_clks[i].ini_flags & MANGO_CLK_RO)
+				local_ops = &mango_clk_pll_ro_ops;
+			else
+				local_ops = &mango_clk_pll_ops;
+			clk = clk_register_composite(
+				NULL, pll_clks[i].name, &pll_clks[i].parent_name,
+				1, NULL, NULL, &pll_clks[i].hw, local_ops,
+				NULL, NULL, pll_clks[i].flags);
+
+			if (IS_ERR(clk)) {
+				pr_err("%s: failed to register clock %s\n", __func__,
+					pll_clks[i].name);
+				ret = -EINVAL;
+				goto out;
+			}
+			ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+			if (ret)
+				clk_unregister(clk);
+		} else {
+			continue;
+		}
+	}
+
+out:
+	return ret;
+}
+
+/* mux clk init */
+int mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data)
+{
+	int ret;
+	int count;
+	struct clk **clk_table;
+
+	count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num;
+	clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table)
+		return -ENOMEM;
+
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = count;
+
+	ret = register_mux_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_gate_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_provider_clks(node, clk_data, count);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	kfree(clk_table);
+	return ret;
+}
+
+/* pll divider init */
+int mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data)
+{
+	int ret;
+	int count;
+
+	struct clk **clk_table;
+
+	count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num;
+	clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table)
+		return -ENOMEM;
+
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = count;
+
+	ret = register_divider_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_gate_clks(NULL, clk_data);
+	if (ret)
+		goto err;
+
+	ret = register_provider_clks(node, clk_data, count);
+	if (ret)
+		goto err;
+
+
+	return 0;
+err:
+	kfree(clk_table);
+	pr_err("%s error %d\n", __func__, ret);
+	return ret;
+}
diff --git a/drivers/clk/sophgo/clk.h b/drivers/clk/sophgo/clk.h
new file mode 100644
index 000000000000..81e9f9eb1b20
--- /dev/null
+++ b/drivers/clk/sophgo/clk.h
@@ -0,0 +1,152 @@
+#ifndef __SOPHGO_CLOCK__
+#define __SOPHGO_CLOCK__
+
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/clkdev.h>
+
+#include <dt-bindings/clock/sophgo.h>
+
+#define KHZ 1000L
+#define MHZ (KHZ * KHZ)
+
+#define MANGO_CLK_USE_INIT_VAL		BIT(0) /* use default value */
+#define MANGO_CLK_USE_REG_VAL		BIT(1) /* use reg divider value */
+#define MANGO_CLK_RO			BIT(2) /* use reg divider value */
+
+#define CLK_PLL	BIT(0)
+#define CLK_MUX	BIT(1)
+
+#define PLL_CTRL_OFFSET	0xE8
+#define PLL_STAT_LOCK_OFFSET	0x8
+#define CLK_MODE	0x4
+#define CLK_MODE_MASK	0x3
+
+#define REFDIV_MIN 1
+#define REFDIV_MAX 64
+#define FBDIV_MIN 16
+#define FBDIV_MAX 321
+
+#define PLL_FREQ_MIN (16 * MHZ)
+#define PLL_FREQ_MAX (3200 * MHZ)
+
+#define div_mask(width) ((1 << (width)) - 1)
+#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \
+	(((fbdiv & 0xfff) << 16) | ((p2 & 0x7) << 12) | ((p1 & 0x7) << 8) | (refdiv & 0x3f))
+
+struct mango_pll_ctrl {
+	unsigned int mode;
+	unsigned long freq;
+
+	unsigned int fbdiv;
+	unsigned int postdiv1;
+	unsigned int postdiv2;
+	unsigned int refdiv;
+};
+
+struct mango_pll_clock {
+	unsigned int id;
+	char *name;
+	const char *parent_name;
+	unsigned long flags;
+	struct clk_hw	hw;
+	struct regmap *syscon_top;
+
+	/* Below lock used to protect PLL top register during write */
+	spinlock_t *lock;
+	u32 ini_flags;
+
+	u32 status_offset;
+	u32 enable_offset;
+
+	struct mango_pll_ctrl pctrl_table[4];
+};
+
+#define to_mango_pll_clk(_hw) container_of(_hw, struct mango_pll_clock, hw)
+
+#define to_mango_clk_divider(_hw)	\
+	container_of(_hw, struct mango_clk_divider, hw)
+
+#define to_mango_clk_mux(nb) \
+	container_of(nb, struct mango_mux_clock, clk_nb)
+
+struct mango_divider_clock {
+	unsigned int id;
+	const char *name;
+	const char *parent_name;
+	unsigned long flags;
+	unsigned long offset;
+	u8 shift;
+	u8 width;
+	u8 div_flags;
+	u32 initial_sel;
+	u32 initial_val;
+	struct clk_div_table *table;
+};
+
+struct mango_mux_clock {
+	unsigned int id;
+	const char *name;
+	const char *const *parent_names;
+	u8 num_parents;
+	unsigned long flags;
+	unsigned long offset;
+	u8 shift;
+	u8 width;
+	u8 mux_flags;
+	u32 *table;
+
+	struct notifier_block clk_nb;
+};
+
+struct mango_gate_clock {
+	unsigned int id;
+	const char *name;
+	const char *parent_name;
+	unsigned long flags;
+	unsigned long offset;
+	u8 bit_idx;
+	u8 gate_flags;
+	const char *alias;
+};
+
+struct mango_clk_table {
+	u32 id;
+	u32 pll_clks_num;
+	u32 div_clks_num;
+	u32 gate_clks_num;
+	u32 mux_clks_num;
+
+	const struct mango_pll_clock *pll_clks;
+	const struct mango_divider_clock *div_clks;
+	const struct mango_gate_clock *gate_clks;
+	const struct mango_mux_clock *mux_clks;
+};
+
+struct mango_clk_data {
+	void __iomem *base;
+	spinlock_t lock;
+	struct regmap *syscon_top;
+	struct clk_onecell_data	clk_data;
+	const struct mango_clk_table *table;
+};
+
+int mango_register_mux_clks
+(struct device_node *node, struct mango_clk_data *clk_data);
+int mango_register_div_clks
+(struct device_node *node, struct mango_clk_data *clk_data);
+int mango_register_pll_clks
+(struct device_node *node, struct mango_clk_data *clk_data, const char *clk_name);
+int set_default_clk_rates(struct device_node *node);
+
+int dm_mango_register_mux_clks
+(struct device_node *node, struct mango_clk_data *clk_data);
+int dm_mango_register_div_clks
+(struct device_node *node, struct mango_clk_data *clk_data);
+int dm_mango_register_pll_clks
+(struct device_node *node, struct mango_clk_data *clk_data, const char *name);
+int dm_set_default_clk_rates(struct device_node *node);
+#endif
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index 3245eb0c602d..1ef476b80044 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -107,9 +107,30 @@ static int __init add_clockevent(struct device_node *event_timer)
 	return 0;
 }
 
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+void __iomem *sched_io_base;
+EXPORT_SYMBOL_GPL(sched_io_base);
+static struct dw_apb_clocksource *cs_g;
+#else
 static void __iomem *sched_io_base;
+#endif
 static u32 sched_rate;
 
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+u64 dw_timer_read_counter(void)
+{
+	return ~readl_relaxed(sched_io_base);
+}
+EXPORT_SYMBOL_GPL(dw_timer_read_counter);
+
+void dw_cs_get_mult_shift(u32 *mult, u32 *shift)
+{
+	*mult = cs_g->cs.mult;
+	*shift = cs_g->cs.shift;
+}
+EXPORT_SYMBOL_GPL(dw_cs_get_mult_shift);
+#endif
+
 static int __init add_clocksource(struct device_node *source_timer)
 {
 	void __iomem *iobase;
@@ -135,6 +156,9 @@ static int __init add_clocksource(struct device_node *source_timer)
 	 */
 	sched_io_base = iobase + 0x04;
 	sched_rate = rate;
+#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC
+	cs_g = cs;
+#endif
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f30f99166531..f676cba5978b 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -430,6 +430,8 @@ config DRM_HYPERV
 
 	 If M is selected the module will be called hyperv_drm.
 
+source "drivers/gpu/drm/smifb2/Kconfig"
+
 # Keep legacy drivers last
 
 menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 0b283e46f28b..5b2399759281 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -148,3 +148,4 @@ obj-y			+= gud/
 obj-$(CONFIG_DRM_HYPERV) += hyperv/
 obj-y			+= solomon/
 obj-$(CONFIG_DRM_SPRD) += sprd/
+obj-y			+= smifb2/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 6a4749c0c5a5..48e2469e252d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1213,6 +1213,8 @@ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev)
 	u16 cmd;
 	int r;
 
+	return 0;
+
 	if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
 		return 0;
 
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index f4f3d2665a6b..a011e7f36ad9 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -8,6 +8,7 @@ config DRM_AMD_DC
 	depends on BROKEN || !CC_IS_CLANG || X86_64 || SPARC64 || ARM64
 	select SND_HDA_COMPONENT if SND_HDA_CORE
 	select DRM_AMD_DC_DCN if (X86 || PPC_LONG_DOUBLE_128)
+	select DRM_AMD_DC_DCN if RISCV && FPU
 	help
 	  Choose this option if you want to use the new display engine
 	  support for AMDGPU. This adds required support for Vega and
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index ab0c6d191038..c4f702e3de96 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -31,6 +31,8 @@
 #elif defined(CONFIG_PPC64)
 #include <asm/switch_to.h>
 #include <asm/cputable.h>
+#elif defined(CONFIG_RISCV)
+#include <asm/switch_to.h>
 #endif
 
 /**
@@ -86,7 +88,7 @@ void dc_fpu_begin(const char *function_name, const int line)
 	*pcpu += 1;
 
 	if (*pcpu == 1) {
-#if defined(CONFIG_X86)
+#if defined(CONFIG_X86) || defined(CONFIG_RISCV)
 		kernel_fpu_begin();
 #elif defined(CONFIG_PPC64)
 		if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
@@ -123,7 +125,7 @@ void dc_fpu_end(const char *function_name, const int line)
 	pcpu = get_cpu_ptr(&fpu_recursion_depth);
 	*pcpu -= 1;
 	if (*pcpu <= 0) {
-#if defined(CONFIG_X86)
+#if defined(CONFIG_X86) || defined(CONFIG_RISCV)
 		kernel_fpu_end();
 #elif defined(CONFIG_PPC64)
 		if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index 6fdf87a6e240..27f95611a0c5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -33,6 +33,12 @@ ifdef CONFIG_PPC64
 dml_ccflags := -mhard-float -maltivec
 endif
 
+ifdef CONFIG_RISCV
+include $(srctree)/arch/riscv/Makefile.isa
+# Remove V from the ISA string, like in arch/riscv/Makefile, but keep F and D.
+dml_ccflags := -march=$(subst v0p7,,$(riscv-march-y))
+endif
+
 ifdef CONFIG_CC_IS_GCC
 ifneq ($(call gcc-min-version, 70100),y)
 IS_OLD_GCC = 1
diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c
index 928e08e0b5b8..340dcb4af122 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -881,7 +881,7 @@ static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,
 	if (!tt)
 		return NULL;
 
-	ret = ttm_tt_init(tt, bo, page_flags, ttm_cached, 0);
+	ret = ttm_tt_init(tt, bo, page_flags, ttm_write_combined, 0);
 	if (ret < 0)
 		goto err_ttm_tt_init;
 
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index f024dc93939e..7c42de20154d 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -69,7 +69,7 @@ static pgprot_t drm_io_prot(struct drm_local_map *map,
 	pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
-    defined(__mips__) || defined(__loongarch__)
+    defined(__mips__) || defined(__loongarch__) || defined(__riscv)
 	if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING))
 		tmp = pgprot_noncached(tmp);
 	else
@@ -93,6 +93,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma)
 #if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE)
 	tmp = pgprot_noncached_wc(tmp);
 #endif
+	tmp = pgprot_writecombine(tmp);
 	return tmp;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 6cbe1ab81aba..89bdac9c3aad 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -36,6 +36,7 @@
 #include <linux/vga_switcheroo.h>
 #include <linux/mmu_notifier.h>
 #include <linux/pci.h>
+#include <linux/kexec.h>
 
 #include <drm/drm_aperture.h>
 #include <drm/drm_crtc_helper.h>
@@ -363,10 +364,10 @@ radeon_pci_remove(struct pci_dev *pdev)
 static void
 radeon_pci_shutdown(struct pci_dev *pdev)
 {
-	/* if we are running in a VM, make sure the device
-	 * torn down properly on reboot/shutdown
+	/* if we are running in a VM or kexec another kernel,
+	 * make sure the device torn down properly on reboot/shutdown
 	 */
-	if (radeon_device_is_virtual())
+	if (radeon_device_is_virtual() || kexec_in_progress)
 		radeon_pci_remove(pdev);
 
 #if defined(CONFIG_PPC64) || defined(CONFIG_MACH_LOONGSON64)
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 6541c1f6fca6..7bbadd161588 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -251,10 +251,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev)
 	 * of address for "64-bit" MSIs which breaks on some platforms, notably
 	 * IBM POWER servers, so we limit them
 	 */
+#if 0
 	if (rdev->family < CHIP_BONAIRE) {
 		dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n");
 		rdev->pdev->no_64bit_msi = 1;
 	}
+#endif
 
 	/* force MSI on */
 	if (radeon_msi == 1)
diff --git a/drivers/gpu/drm/smifb2/Kconfig b/drivers/gpu/drm/smifb2/Kconfig
new file mode 100644
index 000000000000..27ba78742b0e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_SMI
+        tristate "SiliconMotion SM750/SM768 DRM driver"
+        depends on DRM && PCI && MMU && SND
+        select DRM_VRAM_HELPER
+        select DRM_KMS_HELPER
+        select DRM_TTM
+	select DRM_TTM_HELPER
+	select SND_PCM
+        help
+         Say yes for SiliconMotion SM750/SM768 DRM driver.
+         
+
+config DRM_SMI_HDMI
+        bool "Enable SM750 HDMI output"
+        depends on DRM_SMI
+        help
+          Compile in support for SM750 HDMI output(Using Sil9022).
+
+
+config DRM_SMI_PRIME
+        bool "enable SMI PRIME"
+        depends on DRM_SMI
+        help
+          Compile in support for PRIME(Mulit-card).
+
+
diff --git a/drivers/gpu/drm/smifb2/Makefile b/drivers/gpu/drm/smifb2/Makefile
new file mode 100644
index 000000000000..0e2585833c0c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/Makefile
@@ -0,0 +1,38 @@
+obj-$(CONFIG_DRM_SMI) := smifb.o
+smifb-objs :=smi_drv.o smi_main.o smi_mode.o smi_plane.o smi_ttm.o smi_prime.o hw750.o hw768.o smi_sysfs.o
+smifb-objs += ddk750/ddk750_help.o  ddk750/ddk750_chip.o  ddk750/ddk750_clock.o  ddk750/ddk750_mode.o ddk750/ddk750_power.o ddk750/ddk750_helper.o ddk750/ddk750_display.o ddk750/ddk750_2d.o ddk750/ddk750_edid.o ddk750/ddk750_swi2c.o ddk750/ddk750_hwi2c.o ddk750/ddk750_cursor.o
+
+
+
+
+
+
+ifeq ($(CONFIG_DRM_SMI_HDMI),y)
+EXTRA_CFLAGS += -DUSE_HDMICHIP
+smifb-y += ddk750/ddk750_sii9022.o
+smifb-y += ddk750/siHdmiTx_902x_TPI.o
+endif
+
+ifeq ($(CONFIG_DRM_SMI_EP952),y)
+EXTRA_CFLAGS += -DUSE_EP952
+smifb-y += ddk768/ddk768_ep952.o
+endif
+
+
+smifb-objs += ddk768/ddk768_help.o  ddk768/ddk768_chip.o  ddk768/ddk768_clock.o  ddk768/ddk768_mode.o ddk768/ddk768_power.o ddk768/ddk768_helper.o ddk768/ddk768_display.o ddk768/ddk768_2d.o \
+ddk768/ddk768_edid.o ddk768/ddk768_swi2c.o ddk768/ddk768_hwi2c.o ddk768/ddk768_cursor.o ddk768/ddk768_video.o ddk768/ddk768_hdmi.o ddk768/ddk768_pwm.o ddk768/ddk768_timer.o ddk768/ddk768_intr.o 
+
+
+
+smifb-y += smi_snd.o
+smifb-y += ddk768/ddk768_iis.o
+smifb-y += ddk768/uda1345.o
+smifb-y += ddk768/l3.o
+smifb-y += ddk768/wm8978.o
+
+
+ifeq ($(CONFIG_DRM_SMI_PRIME),y)
+EXTRA_CFLAGS += -DPRIME
+endif
+
+ccflags-y :=-O2 -fno-tree-scev-cprop -D_D_SMI -D_D_SMI_D -D__cdecl
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.c
new file mode 100644
index 000000000000..42163e0ebe10
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.c
@@ -0,0 +1,2957 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  2d.C --- SM750/SM718 DDK 
+*  This file contains the definitions for the 2D functions.
+* 
+*******************************************************************/
+
+
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_chip.h"
+#include "ddk750_power.h"
+#include "ddk750_sw2d.h"
+#include "ddk750_2d.h"
+#include "ddk750_help.h"
+#include "ddk750_regde.h"
+
+
+
+/* Flag to enable the 192 bytes patch to workaround the 2D errata, where the engine
+   will draws incorrectly for BITBLT function that involves READ from memory. 
+   Currently, this definition flag is only used for testing. */
+#define ENABLE_192_BYTES_PATCH
+
+/* Static macro */
+#define BYTE_PER_PIXEL(bpp)         (bpp / 8)
+
+/*
+ * 2D Engine Initialization.
+ * This function must be called before other 2D functions.
+ * Assumption: A specific video mode has been properly set up.
+ */
+void ddk750_deInit(void)
+{
+    enable2DEngine(1);
+
+    deReset(); /* Just be sure no left-over operations from other applications */
+
+    /* Set up 2D registers that won't change for a specific mode. */
+
+    /* Drawing engine bus and pixel mask, always want to enable. */
+    POKE_32(DE_MASKS, 0xFFFFFFFF);
+
+    /* Pixel format, which can be 8, 16 or 32.
+       Assuming setmode is call before 2D init, then pixel format
+       is available in reg 0x80000 (Panel Display Control)
+    */
+    POKE_32(DE_STRETCH_FORMAT,
+        FIELD_SET  (0, DE_STRETCH_FORMAT, PATTERN_XY,   NORMAL)  |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y,    0)       |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,    0)       |
+        FIELD_SET  (0, DE_STRETCH_FORMAT, ADDRESSING,   XY)      |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT,3));
+
+    /* Clipping and transparent are disable after INIT */
+    deSetClipping(0, 0, 0, 0, 0);
+    deSetTransparency(0, 0, 0, 0);
+}
+
+/*
+ * Reset 2D engine by 
+ * 1) Aborting the current 2D operation.
+ * 2) Re-enable 2D engine to normal state.
+ */
+void deReset()
+{
+    unsigned long sysCtrl;
+	logical_chip_type_t chipType = ddk750_getChipType();
+
+	if (chipType == SM750 || chipType == SM718)
+	{
+    	/* Abort current 2D operation */
+    	sysCtrl = PEEK_32(SYSTEM_CTRL);
+    	sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, ON);
+    	POKE_32(SYSTEM_CTRL, sysCtrl);
+
+    	/* Re-enable 2D engine to normal state */
+    	sysCtrl = PEEK_32(SYSTEM_CTRL);
+    	sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, OFF);
+    	POKE_32(SYSTEM_CTRL, sysCtrl);
+	}
+	else /* For SM750LE and SM750HS series */
+	{
+	    /* Abort current 2D operation */
+		sysCtrl = PEEK_32(DE_STATE1);
+		sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, ON);
+		POKE_32(DE_STATE1, sysCtrl);
+
+		/* Re-enable 2D engine to normal state */
+        sysCtrl = PEEK_32(DE_STATE1);
+		sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, OFF);
+		POKE_32(DE_STATE1, sysCtrl);
+	}
+}
+ 
+/*
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long deWaitForNotBusy(void)
+{
+	unsigned long dwVal;
+	logical_chip_type_t chipType;
+    unsigned long i = 0x100000;
+
+	chipType = ddk750_getChipType();
+
+	if (chipType == SM750 || chipType == SM718)
+	{
+    	while (i--)
+    	{
+    	    dwVal = PEEK_32(SYSTEM_CTRL);
+    	    if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS)      == SYSTEM_CTRL_DE_STATUS_IDLE) &&
+    	        (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO)        == SYSTEM_CTRL_DE_FIFO_EMPTY) &&
+    	        (FIELD_GET(dwVal, SYSTEM_CTRL, CSC_STATUS)     == SYSTEM_CTRL_CSC_STATUS_IDLE) &&
+    	        (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO)    == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
+    	    {
+    	        return 0; /* Return because engine idle */
+    	    }
+    	}
+
+    	return -1; /* Return because time out */
+	}
+    else /* For SM750LE & SM750HS */
+    {
+        while (i--)
+        {
+            dwVal = PEEK_32(DE_STATE2);
+            if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS)      == DE_STATE2_DE_STATUS_IDLE) &&
+                (FIELD_GET(dwVal, DE_STATE2, DE_FIFO)        == DE_STATE2_DE_FIFO_EMPTY) &&
+                (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO)    == DE_STATE2_DE_MEM_FIFO_EMPTY))
+            {
+                return 0; /* Return because engine idle */
+			}
+        }
+		return -1; /* Return because of timeout */
+    }
+}
+
+#if 0 /* Cheok_2013_0118: Delete this funciton since no other functions are calling it. */
+/* deWaitIdle() function.
+ *
+ * This function is same as deWaitForNotBusy(), except application can
+ * input the maximum number of times that this function will check 
+ * the idle register.
+ *
+ * Its usage is mainly for debugging purpose.
+ *
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long deWaitIdle(unsigned long i)
+{
+	unsigned long dwVal;
+
+    if (ddk750_getChipType() == SM750LE)
+    {
+#if 0
+		while (i--)
+		{
+			dwVal = PEEK_32(DE_CONTROL);
+			if (FIELD_GET(dwVal, DE_CONTROL, STATUS) == DE_CONTROL_STATUS_STOP)
+				return 0;
+		}
+		return -1;
+#else
+        while (i--)
+        {
+            dwVal = PEEK_32(DE_STATE2);
+            if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS)      == DE_STATE2_DE_STATUS_IDLE) && 
+                (FIELD_GET(dwVal, DE_STATE2, DE_FIFO)        == DE_STATE2_DE_FIFO_EMPTY) &&
+                (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO)    == DE_STATE2_DE_MEM_FIFO_EMPTY))
+            {
+                return 0; /* Return because engine idle */
+            }
+        }
+
+        return -1; /* Return because time out */
+#endif
+    }
+
+    while (i--)
+    {
+        dwVal = PEEK_32(SYSTEM_CTRL);
+        if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS)      == SYSTEM_CTRL_DE_STATUS_IDLE) &&
+            (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO)        == SYSTEM_CTRL_DE_FIFO_EMPTY) &&
+            (FIELD_GET(dwVal, SYSTEM_CTRL, CSC_STATUS)     == SYSTEM_CTRL_CSC_STATUS_IDLE) &&
+            (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO)    == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
+        {
+            return 0; /* Return because engine idle */
+        }
+    }
+
+    return -1; /* Return because time out */
+}
+#endif
+
+/*
+ * This function enable/disable clipping area for the 2d engine.
+ * Note that the clipping area is always rectangular.
+ * 
+ */
+long deSetClipping(
+unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */
+unsigned long x1,     /* x1, y1 is the upper left corner of the clipping area */
+unsigned long y1,     /* Note that the region includes x1 and y1 */
+unsigned long x2,     /* x2, y2 is the lower right corner of the clippiing area */
+unsigned long y2)     /* Note that the region will not include x2 and y2 */
+{
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Upper left corner and enable/disable bit
+       Note: This module defautls to clip outside region.
+       "Clip inside" is not a useful feature since nothing gets drawn.
+     */
+    POKE_32(DE_CLIP_TL,
+        FIELD_VALUE(0, DE_CLIP_TL, TOP, y1) |
+        ((enable)?
+          FIELD_SET(0, DE_CLIP_TL, STATUS, ENABLE)
+        : FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE))|
+        FIELD_SET  (0, DE_CLIP_TL, INHIBIT,OUTSIDE) |
+        FIELD_VALUE(0, DE_CLIP_TL, LEFT, x1));
+
+    /* Lower right corner */
+    POKE_32(DE_CLIP_BR,
+        FIELD_VALUE(0, DE_CLIP_BR, BOTTOM,y2) |
+        FIELD_VALUE(0, DE_CLIP_BR, RIGHT, x2));
+
+    return 0;
+}
+
+/* 
+ * Function description:
+ * When transparency is enable, the blt engine compares each pixel value 
+ * (either source or destination) with DE_COLOR_COMPARE register.
+ * If match, the destination pixel will NOT be updated.
+ * If not match, the destination pixel will be updated.
+ */
+long deSetTransparency(
+unsigned long enable,     /* 0 = disable, 1 = enable transparency feature */
+unsigned long tSelect,    /* 0 = compare source, 1 = compare destination */
+unsigned long tMatch,     /* 0 = Opaque mode, 1 = transparent mode */
+unsigned long ulColor)    /* Color to compare. */
+{
+    unsigned long de_ctrl;
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Set mask */
+    if (enable)
+    {
+        POKE_32(DE_COLOR_COMPARE_MASK, 0x00ffffff);
+
+        /* Set compare color */
+        POKE_32(DE_COLOR_COMPARE, ulColor);
+    }
+    else
+    {
+        POKE_32(DE_COLOR_COMPARE_MASK, 0x0);
+        POKE_32(DE_COLOR_COMPARE, 0x0);
+    }
+
+    /* Set up transparency control, without affecting other bits
+       Note: There are two operatiing modes: Transparent and Opague.
+       We only use transparent mode because Opaque mode may have bug.
+    */
+    de_ctrl = PEEK_32(DE_CONTROL)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT);
+
+    /* For DE_CONTROL_TRANSPARENCY_MATCH bit, always set it
+       to TRANSPARENT mode, OPAQUE mode don't seem working.
+    */
+    de_ctrl |=
+    ((enable)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY, ENABLE)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE))        |
+    ((tMatch)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, TRANSPARENT)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)) |
+    ((tSelect)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, DESTINATION)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE));
+
+    POKE_32(DE_CONTROL, de_ctrl);
+
+    return 0;
+}
+
+/*
+ * This function gets the transparency status from DE_CONTROL register.
+ * It returns a double word with the transparent fields properly set,
+ * while other fields are 0.
+ */
+unsigned long deGetTransparency(void)
+{
+    unsigned long de_ctrl;
+
+    de_ctrl = PEEK_32(DE_CONTROL);
+
+    de_ctrl &= 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+    return de_ctrl;
+}
+
+/*
+ * This function sets the pixel format that will apply to the 2D Engine.
+ */
+void deSetPixelFormat(
+    unsigned long bpp
+)
+{
+    unsigned long de_format;
+    
+    de_format = PEEK_32(DE_STRETCH_FORMAT);
+    
+    switch (bpp)
+    {
+        case 8:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
+            break;
+        default:
+        case 16:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
+            break;
+        case 32:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
+            break;
+    }
+    
+    POKE_32(DE_STRETCH_FORMAT, de_format);
+}
+
+/*
+ * This function uses 2D engine to fill a rectangular area with a specific color.
+ * The filled area includes the starting points.
+ */
+long deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/
+unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,      /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long color,  /* Color to be filled */
+unsigned long rop2)   /* ROP value */
+{
+    unsigned long de_ctrl, bytePerPixel;
+
+    bytePerPixel = bpp/8;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    POKE_32(DE_FOREGROUND, color);
+
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+#ifdef ENABLE_192_BYTES_PATCH
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if (((rop2 != ROP2_COPY) || (rop2 != ROP2_Sn) || (rop2 != ROP2_Dn) || 
+         (rop2 != ROP2_D) || (rop2 != ROP2_BLACK) || (rop2 != ROP2_WHITE)) && 
+        ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+//        DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            deWaitForNotBusy();
+            
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    x)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+                
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+                FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+                //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+                FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+                FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+                FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+            if (xChunk == width) break;
+
+            x += xChunk;
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+            FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+            //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+            FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+            FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+            FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+        POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    }
+    
+    return 0;
+}
+
+/*
+ * This function uses 2D engine to draw a trapezoid with a specific color.
+ * The filled area includes the starting points.
+ */
+long deStartTrapezoidFill(
+    unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,
+    unsigned long y,      /* Starting (X, Y) coordinate inside the polygon to be filled */
+    unsigned long length, /* Length of the line */
+    unsigned long color,  /* Color to be filled */
+    unsigned long rop2    /* ROP value */
+)
+{
+    unsigned long de_ctrl =
+        FIELD_SET  (0, DE_CONTROL, STATUS,      START)           |
+        FIELD_SET  (0, DE_CONTROL, QUICK_START, ENABLE)          |
+        FIELD_SET  (0, DE_CONTROL, LAST_PIXEL,  OFF)             |
+        FIELD_SET  (0, DE_CONTROL, DIRECTION,   LEFT_TO_RIGHT)   |
+        FIELD_SET  (0, DE_CONTROL, COMMAND,     TRAPEZOID_FILL)  |
+        FIELD_SET  (0, DE_CONTROL, ROP_SELECT,  ROP2)            |
+        FIELD_VALUE(0, DE_CONTROL, ROP,         rop2);
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Set the Line Color */
+    POKE_32(DE_FOREGROUND, color);
+    
+    /* Set the destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+    
+    /* Set the line length and width */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, 0));
+
+    /* Enable the 2D Engine. */
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    
+    return 0;
+}
+
+/* 
+ * Function to continue drawing a line using Trapezoid Fill method.
+ */
+long deNextTrapezoidFill(
+    unsigned long x,            /* Starting X location. */
+    unsigned long length        /* Line length */
+)
+{
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    /* Set the X destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_VALUE(PEEK_32(DE_DESTINATION), DE_DESTINATION, X,    x));
+        
+    /* Set the line length */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(PEEK_32(DE_DIMENSION), DE_DIMENSION, X,    length));
+        
+    return 0;
+}
+
+/* 
+ * Function to stop the Trapezoid Fill drawing.
+ * This function has to be called to end the Trapezoid Fill drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long deStopTrapezoidFill(void)
+{
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE));
+    
+    return 0;
+}
+
+/*
+ * Video Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk750_deVideoMem2VideoMemBlt(
+unsigned long sBase,  /* Address of source: offset in frame buffer */
+unsigned long sPitch, /* Pitch value of source surface in BYTE */
+unsigned long sx,
+unsigned long sy,     /* Starting coordinate of source surface */
+unsigned long dBase,  /* Address of destination: offset in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height, /* width and height of rectangle in pixel value */
+unsigned long rop2)   /* ROP value */
+{
+    unsigned long nDirection, de_ctrl, bytePerPixel;
+    long opSign;
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    nDirection = LEFT_TO_RIGHT;
+    opSign = 1;    /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
+    bytePerPixel = bpp/8;
+    de_ctrl = 0;
+
+    /* If source and destination are the same surface, need to check for overlay cases */
+    if (sBase == dBase && sPitch == dPitch)
+    {
+        /* Determine direction of operation */
+        if (sy < dy)
+        {
+            /* +----------+
+               |S         |
+               |   +----------+
+               |   |      |   |
+               |   |      |   |
+               +---|------+   |
+                   |         D|
+                   +----------+ */
+    
+            nDirection = BOTTOM_TO_TOP;
+        }
+        else if (sy > dy)
+        {
+            /* +----------+
+               |D         |
+               |   +----------+
+               |   |      |   |
+               |   |      |   |
+               +---|------+   |
+                   |         S|
+                   +----------+ */
+    
+            nDirection = TOP_TO_BOTTOM;
+        }
+        else
+        {
+            /* sy == dy */
+    
+            if (sx <= dx)
+            {
+                /* +------+---+------+
+                   |S     |   |     D|
+                   |      |   |      |
+                   |      |   |      |
+                   |      |   |      |
+                   +------+---+------+ */
+    
+                nDirection = RIGHT_TO_LEFT;
+            }
+            else
+            {
+                /* sx > dx */
+    
+                /* +------+---+------+
+                   |D     |   |     S|
+                   |      |   |      |
+                   |      |   |      |
+                   |      |   |      |
+                   +------+---+------+ */
+    
+                nDirection = LEFT_TO_RIGHT;
+            }
+        }
+    }
+
+    if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT))
+    {
+        sx += width - 1;
+        sy += height - 1;
+        dx += width - 1;
+        dy += height - 1;
+        opSign = (-1);
+    }
+
+    /* Note:
+       DE_FOREGROUND are DE_BACKGROUND are don't care.
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
+    */
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, sBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+    
+#ifdef ENABLE_192_BYTES_PATCH
+    /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. 
+       The Version AA also have this problem on higher clock with 32-bit memory data bus, 
+       therefore, it needs to be enabled here. 
+       In version AA, the problem happens on the following configurations:
+        1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp
+        2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp.
+       Somehow, the problem does not appears in 64-bit memory setting.
+     */
+
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            deWaitForNotBusy();
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+                FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+                ((nDirection == RIGHT_TO_LEFT) ? 
+                FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
+                : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
+                FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+            if (xChunk == width) break;
+
+            sx += (opSign * xChunk);
+            dx += (opSign * xChunk);
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        deWaitForNotBusy();
+
+        POKE_32(DE_SOURCE,
+            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+            FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+            FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+            ((nDirection == RIGHT_TO_LEFT) ? 
+            FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
+            : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
+            FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+        POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    }
+
+    return 0;
+}
+
+/*
+ * System Memory to Video Memory data transfer.
+ * Only works in D, S, ~D, and ~S ROP.
+ */
+long deSystemMem2VideoMemBusMasterBlt(
+    unsigned char *pSBase,  /* Address of source in the system memory.
+                               The memory must be a continuous physical address. */
+    unsigned long sPitch,   /* Pitch value of source surface in BYTE */
+    unsigned long sx,
+    unsigned long sy,       /* Starting coordinate of source surface */
+    unsigned long dBase,    /* Address of destination in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectangle in pixel value */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long de_ctrl, bytePerPixel;
+    unsigned long value, pciMasterBaseAddress;
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    bytePerPixel = bpp/8;
+    de_ctrl = 0;
+
+    /* Note:
+       DE_FOREGROUND are DE_BACKGROUND are don't care.
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
+    */
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the given PCI Master base address
+    */
+    /* Set 2D Source Base Address */
+    value = FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, (unsigned long)pSBase);        
+    pciMasterBaseAddress = ((unsigned long)pSBase & 0xFC000000) >> 24;
+    POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+    value = FIELD_SET(value, DE_WINDOW_SOURCE_BASE, EXT, EXTERNAL);
+    POKE_32(DE_WINDOW_SOURCE_BASE, value);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+    
+#ifdef ENABLE_192_BYTES_PATCH
+    /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. 
+       The Version AA also have this problem on higher clock with 32-bit memory data bus, 
+       therefore, it needs to be enabled here. 
+       In version AA, the problem happens on the following configurations:
+        1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp
+        2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp.
+       Somehow, the problem does not appears in 64-bit memory setting.
+     */
+
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            deWaitForNotBusy();
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+                
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+                
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+                FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+                FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+                FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+            if (xChunk == width) break;
+
+            sx += xChunk;
+            dx += xChunk;
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        deWaitForNotBusy();
+
+        POKE_32(DE_SOURCE,
+            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+            FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+            FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+            FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+            FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+        POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    }
+
+    return 0;
+}
+
+/* 
+ * System memory to Video memory data transfer
+ * Note: 
+ *         We also call it HOST Blt.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long deSystemMem2VideoMemBlt(
+    unsigned char *pSrcbuf, /* pointer to source data in system memory */
+    long srcDelta,          /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */
+    unsigned long dBase,    /* Address of destination: offset in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectange in pixel value */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long bytePerPixel;
+    unsigned long ulBytesPerScan;
+    unsigned long ul8BytesPerScan;
+    unsigned long ulBytesRemain;
+    unsigned long de_ctrl = 0;
+    unsigned char ajRemain[8];
+    long i, j;
+
+    bytePerPixel = bpp/8;
+
+    /* HOST blt data port must take multiple of 8 bytes as input.
+       If the source width does not match that requirement,
+       we need to split it into two portions. The first portion
+       is 8 byte multiple. The 2nd portion is the remaining bytes.
+       The remaining bytes will be buffered to an 8 byte array and
+       and send it to the host blt data port.
+    */
+    ulBytesPerScan = width * bpp / 8;
+    ul8BytesPerScan = ulBytesPerScan & ~7;
+    ulBytesRemain = ulBytesPerScan & 7;
+
+    /* Program 2D Drawing Engine */
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* 2D Source Base.
+       Use 0 for HOST Blt.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, 0);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Note: For 2D Source in Host Write, only X_K1 field is needed, and Y_K2 field is not used.
+             For 1 to 1 bitmap transfer, use 0 for X_K1 means source alignment from byte 0. */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, 0)       |
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+        
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    de_ctrl = 
+        FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
+        FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
+        FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+        FIELD_SET(0, DE_CONTROL, HOST, COLOR)         |
+        FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    /* Write bitmap/image data (line by line) to 2D Engine data port */
+    for (i = 0; i < height; i++)
+    {
+        /* For each line, send the data in chunks of 4 bytes. */
+        for (j=0; j < (ul8BytesPerScan/4);  j++)
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4)));
+
+        if (ulBytesRemain)
+        {
+            memcpy(ajRemain, pSrcbuf+ul8BytesPerScan, ulBytesRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(ajRemain+4));
+        }
+
+        pSrcbuf += srcDelta;
+    }
+
+    return 0;
+}
+
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is monochrome image in system memory.
+ * This function expands the monochrome data to color image in video memory.
+ */
+long deSystemMem2VideoMemMonoBlt(
+unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
+long srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
+unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2)     /* ROP value */
+{
+    unsigned long bytePerPixel;
+    unsigned long ulBytesPerScan;
+    unsigned long ul4BytesPerScan;
+    unsigned long ulBytesRemain;
+    unsigned long de_ctrl = 0;
+    unsigned char ajRemain[4];
+    long i, j;
+
+    bytePerPixel = bpp/8;
+
+    startBit &= 7; /* Just make sure the start bit is within legal range */
+    ulBytesPerScan = (width + startBit + 7) / 8;
+    ul4BytesPerScan = ulBytesPerScan & ~3;
+    ulBytesRemain = ulBytesPerScan & 3;
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* 2D Source Base.
+       Use 0 for HOST Blt.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, 0);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
+             For mono bitmap, use startBit for X_K1. */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE)       |
+        FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+    POKE_32(DE_FOREGROUND, fColor);
+    POKE_32(DE_BACKGROUND, bColor);
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
+              FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
+              FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+              FIELD_SET(0, DE_CONTROL, HOST, MONO)          |
+              FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    /* Write MONO data (line by line) to 2D Engine data port */
+    for (i=0; i<height; i++)
+    {
+        /* For each line, send the data in chunks of 4 bytes */
+        for (j=0; j<(ul4BytesPerScan/4); j++)
+        {
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4)));
+        }
+
+        if (ulBytesRemain)
+        {
+            memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain);
+        }
+
+        pSrcbuf += srcDelta;
+    }
+
+    return 0;
+}
+
+#if 0   /* Does not work. Errata. */
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in System memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deSystemMem2VideoMemMonoBusMasterBlt(
+    unsigned char *pSBase,  /* Address of mono-chrome source data in frame buffer */
+    unsigned long sPitch,   /* Pitch value (in bytes) of the source buffer. */
+    unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+    unsigned long dBase,    /* Base address of destination in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width,    /* width of mono-chrome picture in pixel value */
+    unsigned long height,   /* height of mono-chrome picture in pixel value */
+    unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+    unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long bytePerPixel, de_ctrl, packed;
+    unsigned long value, pciMasterBaseAddress;
+
+    bytePerPixel = bpp/8;
+
+    switch ( width )
+    {
+        case 8:
+            packed = DE_CONTROL_MONO_DATA_8_PACKED;
+            break;
+        case 16:
+            packed = DE_CONTROL_MONO_DATA_16_PACKED;
+            break;
+        case 32:
+            packed = DE_CONTROL_MONO_DATA_32_PACKED;
+            break;
+        default:
+            packed = DE_CONTROL_MONO_DATA_NOT_PACKED;
+    }
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Note:
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
+    */
+
+    /* Monochrome source data in system memory.
+       It is an address offset (128 bit aligned) from the given PCI Master base address
+    */
+    /* Set 2D Source Base Address */
+    value = FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, (unsigned long)pSBase);        
+    pciMasterBaseAddress = ((unsigned long)pSBase & 0xFC000000) >> 24;
+    POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+    value = FIELD_SET(value, DE_WINDOW_SOURCE_BASE, EXT, EXTERNAL);
+    POKE_32(DE_WINDOW_SOURCE_BASE, value);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel conversion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      1));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      0)); /* Source window width is don't care */
+
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, startBit)   |
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+    POKE_32(DE_FOREGROUND, fColor);
+    POKE_32(DE_BACKGROUND, bColor);
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    de_ctrl = 
+        FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+        FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+        FIELD_SET(0, DE_CONTROL, COMMAND, FONT) |
+        FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+        FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) |
+        FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    return 0;
+}
+#endif
+
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in Video memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deVideoMem2VideoMemMonoBlt(
+unsigned long sBase,  /* Address of mono-chrome source data in frame buffer */
+unsigned long dBase,  /* Base address of destination in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width,  /* width of mono-chrome picture in pixel value */
+unsigned long height, /* height of mono-chrome picture in pixel value */
+unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2)   /* ROP value */
+{
+    unsigned long bytePerPixel, de_ctrl, packed;
+
+    bytePerPixel = bpp/8;
+
+    switch ( width )
+    {
+        case 8:
+            packed = DE_CONTROL_MONO_DATA_8_PACKED;
+            break;
+        case 16:
+            packed = DE_CONTROL_MONO_DATA_16_PACKED;
+            break;
+        case 32:
+            packed = DE_CONTROL_MONO_DATA_32_PACKED;
+            break;
+        default:
+            packed = DE_CONTROL_MONO_DATA_NOT_PACKED;
+    }
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Note:
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
+    */
+
+    /* Monochrome source data in frame buffer.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, sBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      0));      /* Source pitch is don't care */
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      0 )); /* Source window width is don't care */
+
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, 0)   |
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));    /* Source data starts at location (0, 0) */
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+    POKE_32(DE_FOREGROUND, fColor);
+    POKE_32(DE_BACKGROUND, bColor);
+    POKE_32(DE_COLOR_COMPARE, bColor);
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    de_ctrl = 
+        FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+        FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+        FIELD_SET(0, DE_CONTROL, COMMAND, FONT) |
+        FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+        FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) |
+        FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    return 0;
+}
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * 
+ * Difference between this function and deVideoMem2VideoMemMonoBlt():
+ * 1) Input is base address of the whole font table.
+ * 2) An extra input about which character in the font table to display.
+ * 3) This function demos how to use registers DE_SOURCE and
+ *    DE_WINDOW_WIDTH, where they are set to 0 in deVideoMem2VideoMemMonoBlt().
+ */
+long deFontCacheTblMonoBlt(
+unsigned long fontTblBase,/* Base address of monochrome font table in frame buffer */
+unsigned long fontNumber, /* Which character in the font table, starting from 0 */
+unsigned long dBase,      /* Base address of destination in frame buffer */
+unsigned long dPitch,     /* Pitch value of destination surface in BYTE */
+unsigned long bpp,        /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,         /* Starting coordinate of destination surface */
+unsigned long width,      /* width of each monochrome font in pixel value */
+unsigned long height,     /* height of each monochrome font in pixel value */
+unsigned long fColor,     /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,     /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2)       /* ROP value */
+{
+    unsigned long bytePerPixel, distBetweenFont, de_ctrl, packed;
+
+    bytePerPixel = bpp/8;
+
+    /* Distance between fonts in pixel value */
+    distBetweenFont = width * height;
+
+    /* SM50x hardware requires each font character be a minimum of 128 
+       pixel value apart.
+       For 8x8 fonts, each font character is only 64 pixel apart.
+       However, if application uses deCacheFontToFrameBuffer()
+       to cache the font in video memory, each font character will be 
+       stored as 128 pixels apart.
+    */
+    if (distBetweenFont < 128)
+        distBetweenFont = 128;
+
+    switch ( width )
+    {
+        case 8:
+            packed = DE_CONTROL_MONO_DATA_8_PACKED;
+            break;
+        case 16:
+            packed = DE_CONTROL_MONO_DATA_16_PACKED;
+            break;
+        case 32:
+            packed = DE_CONTROL_MONO_DATA_32_PACKED;
+            break;
+        default:
+            packed = DE_CONTROL_MONO_DATA_NOT_PACKED;
+    }
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Note:
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
+    */
+
+    /* Base address of font table in frame buffer */
+    POKE_32(DE_WINDOW_SOURCE_BASE, fontTblBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      0));      /* Source pitch is don't care */
+
+    /* Pay attention how DE_WINDOW_WIDTH:SOURCE is different from
+       deVideoMem2VideoMemMonoBlt()
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      distBetweenFont));
+
+    /* Pay attention how DE_SOURCE:Y_K2 is different from 
+       deVideoMem2VideoMemMonoBlt()
+    */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, 0)   |
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, fontNumber));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+    POKE_32(DE_FOREGROUND, fColor);
+    POKE_32(DE_BACKGROUND, bColor);
+    POKE_32(DE_COLOR_COMPARE, bColor);
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    de_ctrl = 
+        FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+        FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+        FIELD_SET(0, DE_CONTROL, COMMAND, FONT) |
+        FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+        FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) |
+        FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    return 0;
+}
+
+
+/*
+ * Rotation helper function.
+ * 
+ * This function sets the source coordinate, destination coordinate, window
+ * dimension, and also the control register. This function is only used statically
+ * to simplify the deRotateBlt function.
+ *
+ */
+void deRotate(
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long dx,               /* X Coordinate of the destination */
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long width,            /* Width of the window */
+    unsigned long height,           /* Height of the window */
+    unsigned long de_ctrl           /* DE_CONTROL Control Value */
+)
+{
+    /* Wait until the engine is not busy */
+    deWaitForNotBusy();
+                
+    /* Set the source coordinate */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | 
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+        
+    /* Set the destination coordinate */    
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X, dx) | 
+        FIELD_VALUE(0, DE_DESTINATION, Y, dy));
+
+    /* Set the source width and height dimension */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X, width) | 
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+        
+    /* Start the DE Control */
+    POKE_32(DE_CONTROL, de_ctrl);
+}
+
+/*
+ * Rotation Blt.
+ * 
+ * This function rotates an image to the screen based on the given rotation direction
+ * (0, 90, 180, or 270 degree).
+ * 
+ * NOTE:
+ *      1. The function takes care of any coordinates that pass the top and left
+ *         boundary, but it does not take care of right and bottom boundary since
+ *         more information is needed in order to do so. However, it seems that
+ *         SM50x will take care the right and bottom by using wrap around.
+ *         Depending on the implementation, this function might be modified further.
+ *      2. There are 3 hardware bugs found on the rotation:
+ *         a. The rotated image sometimes is not correct when using some width number
+ *            due to FIFO bug. Therefore, the image is divided into segments and
+ *            rotated based on segment by segment using 32/byte per pixel as the width.
+ *            This value (32/byte per pixel) seems to be consistent in producing a good 
+ *            rotated image.
+ *         b. Rotating 0 degree using the actual Rotation BLT will have the same result
+ *            as rotation 270 degree.
+ *         c. Rotating 180 degree on some x destination coordinate will result in 
+ *            incorrect image. To workaround this problem, two 90 degree rotations are
+ *            used.
+ *      3. The rop parameter might not be necessary if only one ROP operation is used.
+ *         This might be deleted in the future as necessary.
+ */
+long deVideoMem2VideoMemRotateBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long width,            /* Width  of un-rotated image in pixel value */
+    unsigned long height,           /* Height of un-rotated image in pixel value */
+    rotate_dir_t rotateDirection,   /* Direction of the rotation */
+    unsigned long repeatEnable,     /* Enable repeat rotation control where the
+                                       drawing engine is started again every vsync */
+    unsigned long rop2              /* ROP control */
+)
+{
+    unsigned long de_ctrl = 0; 
+    unsigned long maxRotationWidth;
+    
+    /* Maximum rotation width BLT */
+    maxRotationWidth = 32 / BYTE_PER_PIXEL(bpp);
+
+    /* Wait for the engine to be idle */
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    } 
+
+    /* Return error if either the width or height is zero */ 
+    if ((width == 0) || (height == 0))
+        return -1;
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, sBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      sPitch / BYTE_PER_PIXEL(bpp)));
+        
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+       
+    /* Setup Control Register */
+    de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START)    |
+              FIELD_SET(0, DE_CONTROL, COMMAND, ROTATE)  |
+              FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+              FIELD_VALUE(0, DE_CONTROL, ROP, rop2)      |
+              ((repeatEnable == 1) ? 
+                    FIELD_SET(0, DE_CONTROL, REPEAT_ROTATE, ENABLE) :
+                    FIELD_SET(0, DE_CONTROL, REPEAT_ROTATE, DISABLE)) |
+              deGetTransparency();
+       
+    /* 501 Hardware cannot handle rotblits > 32 bytes. Therefore the rotation 
+       should be done part by part. Note on each rotation case. */
+    switch (rotateDirection)
+    {
+        case ROTATE_NORMAL:
+#if 0   /* Enable this on if the hardware 0 degree rotation bug has been fixed */
+
+            /* Setup rotation direction to 0 degree */
+            de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
+                        FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE));
+
+            deRotate(sx, sy, dx, dy, width, height, de_ctrl);                        
+#else
+            /* 
+             * Due to the hardware bug on the SM750, rotate normal is simply done
+             * by calling the normal bit BLT. Calling the rotation with 0 degree
+             * will cause the hardware to rotate it 270 degree. 
+             */
+            return(ddk750_deVideoMem2VideoMemBlt(
+                    sBase,
+                    sPitch,
+                    sx,
+                    sy,
+                    dBase,
+                    dPitch,
+                    bpp,
+                    dx,
+                    dy,
+                    width, 
+                    height,
+                    rop2));
+#endif
+            break;
+
+        case ROTATE_180_DEGREE:
+            /* The 180 degree rotation that has problem */
+
+            return -1; /* Don't do anything until there is a HW fix */
+            
+            de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
+                        FIELD_SET(0, DE_CONTROL, STEP_Y, NEGATIVE));
+
+            deRotate(sx, sy, dx, dy, width, height, de_ctrl);
+            break;
+
+        case ROTATE_90_DEGREE:
+            /* 90 degrees rotation.  Calculate destination
+			   coordinates:
+
+				*---+
+				|   |       +-----+
+				|   |       |     |
+				|   |  -->  |     |
+				|   |       |     |
+				|   |       *-----+
+				+---+
+			*/
+            /* Update the new width */
+            if (dy < width)
+                width = dy+1;
+                
+            /* Set up the rotation direction to 90 degree */                
+            de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
+                        FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE));
+
+#if 1   /* Disable this one if the hardware bug has been fixed */
+
+            /* Do rotation part by part based on the maxRotationWidth */
+            while (width > maxRotationWidth)
+	        {
+                deRotate(sx, sy, dx, dy, maxRotationWidth, height, de_ctrl);
+
+                width -= maxRotationWidth;
+                sx    += maxRotationWidth;
+                dy    -= maxRotationWidth;
+            }
+#endif
+            /* Rotate the rest of the segment */
+            if (width > 0)
+                deRotate(sx, sy, dx, dy, width, height, de_ctrl);
+                
+            break;
+        
+        case ROTATE_270_DEGREE:
+            /* 270 degrees (90 degree CW) rotation.  Calculate destination
+			   coordinates:
+
+				*---+
+				|   |       +-----*
+				|   |       |     |  
+				|   |  -->  |     | 
+				|   |       |     |
+				|   |       +-----+
+				+---+
+			*/
+            de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
+                        FIELD_SET(0, DE_CONTROL, STEP_Y, NEGATIVE));
+ 
+#if 1   /* Disable this one if the hardware bug has been fixed */
+
+            /* Do rotation part by part based on the maxRotationWidth */            
+            while (width > maxRotationWidth)
+	        {
+                deRotate(sx, sy, dx, dy, maxRotationWidth, height, de_ctrl);
+               
+                width -= maxRotationWidth;
+                sx    += maxRotationWidth;
+                dy    += maxRotationWidth;
+            }
+#endif            
+            /* Update the rest of the segment */
+            if (width > 0)
+                deRotate(sx, sy, dx, dy, width, height, de_ctrl);
+            break;
+    }
+
+    return 0;
+}
+
+/* 
+ * Function to draw a vertical line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deVerticalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long de_ctrl;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+    
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Set the Line Color */
+    POKE_32(DE_FOREGROUND, color);
+
+    /* Set the destination coordinate. */
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+
+    /* Set the line length and width */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    1) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, length));
+        
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    /* Set the control register. For the Vertical line Short Stroke, the Direction Control
+       should be set to 0 (which is defined as Left to Right). */
+    de_ctrl = 
+        FIELD_SET  (0, DE_CONTROL,  STATUS,     START)         |
+        FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT) |
+        FIELD_SET  (0, DE_CONTROL,  MAJOR,      Y)             |
+        FIELD_SET  (0, DE_CONTROL,  STEP_X,     NEGATIVE)      |
+        FIELD_SET  (0, DE_CONTROL,  STEP_Y,     NEGATIVE)      |
+        FIELD_SET  (0, DE_CONTROL,  LAST_PIXEL, OFF)           |
+        FIELD_SET  (0, DE_CONTROL,  COMMAND,    SHORT_STROKE)  |
+        FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)          |
+        FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+    return 0;
+}
+
+/* 
+ * Function to draw a horizontal line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deHorizontalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long de_ctrl;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+    
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+        
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Set the Line Color */
+    POKE_32(DE_FOREGROUND, color);
+
+    /* Set the destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+
+    /* Set the line length and width */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, 1));
+        
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+    /* Set the control register. For the Horizontal line Short Stroke, the Direction Control
+       should be set to 1 (which is defined as Right to Left). */
+    de_ctrl = 
+        FIELD_SET  (0, DE_CONTROL,  STATUS,     START)         |
+        FIELD_SET  (0, DE_CONTROL,  DIRECTION,  RIGHT_TO_LEFT) |
+        FIELD_SET  (0, DE_CONTROL,  MAJOR,      X)             |
+        FIELD_SET  (0, DE_CONTROL,  STEP_X,     NEGATIVE)      |
+        FIELD_SET  (0, DE_CONTROL,  STEP_Y,     NEGATIVE)      |
+        FIELD_SET  (0, DE_CONTROL,  LAST_PIXEL, OFF)           |
+        FIELD_SET  (0, DE_CONTROL,  COMMAND,    SHORT_STROKE)  |
+        FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)          |
+        FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    
+    return 0;
+}
+
+/* 
+ * Function to draw a line.
+ *
+ * Note:
+ *      This function is using Short Stroke Command for Vertical, Horizontal, and 
+ *      Diagonal line. Other line are drawn using the Line Draw Command.
+ */
+long deLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    long x0,                /* Starting X Coordinate */
+    long y0,                /* Starting Y Coordinate */
+    long x1,                /* Ending X Coordinate */
+    long y1,                /* Ending Y Coordinate */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long de_ctrl =
+        FIELD_SET  (0, DE_CONTROL, STATUS,     START)         |
+        FIELD_SET  (0, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT) |
+        FIELD_SET  (0, DE_CONTROL, MAJOR,      X)             |
+        FIELD_SET  (0, DE_CONTROL, STEP_X,     POSITIVE)      |
+        FIELD_SET  (0, DE_CONTROL, STEP_Y,     POSITIVE)      |
+        FIELD_SET  (0, DE_CONTROL, LAST_PIXEL, ON)            |
+        FIELD_SET  (0, DE_CONTROL, ROP_SELECT, ROP2)          |
+        FIELD_VALUE(0, DE_CONTROL, ROP,        rop2);
+
+    unsigned long dx, dy;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    //DDKDEBUGPRINT((DE_LEVEL, "x0=%d(%x), y0=%d(%0x)\n", x0, x0, y0, y0));
+    //DDKDEBUGPRINT((DE_LEVEL, "x1=%d(%x), y1=%d(%0x)\n", x1, x1, y1, y1));
+    
+    /* Return error if x0 and/or y0 are negative numbers. The hardware does not take
+       any negative values on these two origin line coordinate.
+       When drawing with a negative x0, the line might be drawn incorrectly.
+       When drawing with a negative y0, the system might reboot or hang.
+     */
+    if ((x0 < 0) || (y0 < 0))
+    {
+        //DDKDEBUGPRINT((ERROR_LEVEL, "Negative origin coordinates are not allowed (x0, y0) = (%d, %d).\n", x0, y0));
+        return (-1);
+    }
+
+    /* Calculate delta X */
+    if (x0 <= x1)
+    {
+        dx = x1 - x0;
+        de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+    }
+    else
+        dx = x0 - x1;
+
+    /* Calculate delta Y */
+    if (y0 <= y1)
+    {
+        dy = y1 - y0;
+        de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+    }
+    else
+        dy = y0 - y1;
+
+    /* Determine the major axis */
+    if (dx < dy)
+        de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);        
+
+    /*****************************************************
+     * Draw the line based on the calculated information *
+     *****************************************************/
+     
+    /* Vertical line? */
+    if (x0 == x1)
+        deVerticalLine(dBase, dPitch, bpp, x0, (y0 < y1) ? y0 : y1, dy + 1, color, rop2);
+
+    /* Horizontal line? */
+    else if (y0 == y1)
+        deHorizontalLine(dBase, dPitch, bpp, (x0 < x1) ? x0 : x1, y0, dx + 1, color, rop2);
+
+    else 
+    {
+        /****************************
+         * Set the common registers *
+         ****************************/
+         
+        /* 2D Destination Base.
+           It is an address offset (128 bit aligned) from the beginning of frame buffer.
+        */
+        POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+        /* Program pitch (distance between the 1st points of two adjacent lines).
+           Note that input pitch is BYTE value, but the 2D Pitch register uses
+           pixel values. Need Byte to pixel convertion.
+        */
+        POKE_32(DE_PITCH,
+            FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+            FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+    
+        /* Screen Window width in Pixels.
+           2D engine uses this value to calculate the linear address in frame buffer for a given point.
+        */
+        POKE_32(DE_WINDOW_WIDTH,
+            FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+            FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+        /* Set the Line Color */
+        POKE_32(DE_FOREGROUND, color);
+
+        /* Set the destination coordinate */
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    x0)      |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    y0));
+        
+        /* Set the pixel format of the destination */
+        deSetPixelFormat(bpp);
+    
+        /* Diagonal line? */
+        if (dx == dy)
+        {
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    1) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, dx + 1));
+
+            /* Set the command register. */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, COMMAND, SHORT_STROKE);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());            
+        }
+
+        /* Generic line */
+        else
+        {
+            long k1, k2, et, w;
+            
+            if (dx < dy)
+            {
+                k1 = 2 * dx;
+                et = k1 - dy;
+                k2 = et - dy;
+                w  = dy + 1;
+            } 
+            else 
+            {
+                k1 = 2 * dy;
+                et = k1 - dx;
+                k2 = et - dx;
+                w  = dx + 1;
+            }
+            
+            //DDKDEBUGPRINT((DE_LEVEL, "k1=%d(%x), k2=%d(%x)\n", k1, k1, k2, k2));
+            
+            /* Return error if the value of K1 and/or K2 is/are overflowed which is 
+               determined using the following condition:
+                        0 < k1 < (2^13 - 1)
+                    -2^13 < k2 < 0
+               Bit-14 is the sign bit.
+               
+               Failing to follow this guidance will result in incorrect line drawing.
+               On failure, please use software to draw the correct line.
+             */             
+            if ((k1 > 8191) || (k2 < (0 - 8192)))
+            {
+                //DDKDEBUGPRINT((ERROR_LEVEL, "K1=%d(0x%04x) and/or K2=%d(0x%04x) is/are overflowed.\n", k1, k1, k2, k2));
+                return (-1);
+            }
+        
+            /* Set the k1 and k2 */
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1_LINE, k1) |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2_LINE, k2));
+
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    w) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
+
+            /* Set the control register. */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, COMMAND, LINE_DRAW);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+        }
+    }
+    
+    return 0;
+}
+
+#if 0   /* These RLE functions are not working. */
+/*
+ *  The following functions, that uses to draw line using RLE Strip command, are not working,
+ *  as described in the following:
+ *      1. Line strips can not be used to draw line vertically.
+ *      2. Origin Y automatic update is not work. Only Origin X automatic update is working.
+ *      3. Line counter to accelerate drawing multiple strip of the same characteristics does
+ *         not work.
+ *  For more information about RLE Line Strips, please refer to "Programmer's Guide to the EGA,
+ *  VGA, and Super VGA Cards", third edition, page 727-730.
+ */
+ 
+/* 
+ * Function to draw a line using RLE line strip method.
+ */
+long deStartLineStrip(
+    unsigned long dBase,        /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,       /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,          /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,            /* X Coordinate */
+    unsigned long y,            /* Y Coordinate */
+    unsigned long length,       /* Length of the line */
+    unsigned long lineCounter,  /* Line Counter */
+    unsigned long direction,    /* Direction:   0 - Left to Right
+                                                1 - Right to Left
+                                                2 - Top to Bottom
+                                                3 - Bottom to Top
+                                */
+    unsigned long color,        /* Color of the line */
+    unsigned long rop2          /* ROP value */
+)
+{
+    unsigned long dx, dy;
+    unsigned long de_ctrl =
+        FIELD_SET  (0, DE_CONTROL, STATUS,      START)      |
+        FIELD_SET  (0, DE_CONTROL, QUICK_START, ENABLE)     |
+        FIELD_SET  (0, DE_CONTROL, LAST_PIXEL,  OFF)        |
+        FIELD_SET  (0, DE_CONTROL, COMMAND,     RLE_STRIP)  |
+        FIELD_SET  (0, DE_CONTROL, ROP_SELECT,  ROP2)       |
+        FIELD_VALUE(0, DE_CONTROL, ROP,         rop2);
+
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Set the Line Color */
+    POKE_32(DE_FOREGROUND, color);
+    
+    /* Set the destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+#if 1   /* Testing if any of the configuration combination of the following have
+           any differences. */
+    switch (direction)
+    {
+        case 0:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 1:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 2:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 3:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 4:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 5:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 6:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 7:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 8:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 9:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 10:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 11:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 12:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 13:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+        case 14:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            break;
+        case 15:
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            break;
+    }
+    
+    /* Set the line length and width */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    lineCounter) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, length));
+#else
+    /* Determine the x & y steps direction control and major axis */
+    switch (direction)
+    {
+        case 0:
+            /* Left to Right */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter));
+            break;
+            
+        case 1:
+            /* Right to Left */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter));
+            break;
+            
+        case 2:
+            /* Top to Bottom */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  LEFT_TO_RIGHT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE);
+            
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    lineCounter) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, length));
+            break;
+            
+        case 3:
+            /* Bottom to Top */
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION,  RIGHT_TO_LEFT);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE);
+            de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE);
+            
+            /* Set the line length and width */
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    lineCounter) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, length));
+            break;
+    }
+#endif
+
+    /* Enable the 2D Engine. */
+    POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    
+    return 0;
+}
+
+/* 
+ * Function to continue drawing a line using RLE line strip method.
+ */
+long deNextLineStrip(
+    unsigned long length,       /* Line strip length */
+    unsigned long lineCounter   /* Line Counter */
+)
+{
+    unsigned long de_ctrl;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    de_ctrl = PEEK_32(DE_CONTROL);
+    
+    if (FIELD_GET(de_ctrl, DE_CONTROL, MAJOR) == DE_CONTROL_MAJOR_X)
+    {
+        /* Set the line length and width */
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter));
+    }
+    else
+    {
+        /* Set the line length and width */
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    lineCounter) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, length));
+    }
+    
+    return 0;
+}
+
+/* 
+ * Function to stop the RLE line strip drawing.
+ * This function has to be called to end the Line Strip drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long deStopLineStrip()
+{
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+    
+    POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE));
+    
+    return 0;
+}
+#endif
+
+/* Define this definition to block transparency in Alpha Blend blt since
+   transparency does not work with alpha blend. */
+//#define ALPHA_BLEND_BLOCK_TRANSPARENCY
+
+/*
+ * Alpha Blend Blt.
+ * 
+ * This function blends the source with the destination image.
+ */
+long deVideoMem2VideoMemAlphaBlendBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long sWidth,           /* Source Width */
+    unsigned long sHeight,          /* Source Height */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long dHeight,          /* Destination Height (only height stretch is supported) */
+    unsigned long alphaValue,       /* Alpha value for Alpha Blend*/
+    unsigned long rop2              /* ROP control */
+)
+{
+    unsigned long de_ctrl = 0, bytePerPixel;
+#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY
+    unsigned long transparency = 0;
+#endif
+
+    bytePerPixel = bpp/8; 
+    
+    /* Wait for the engine to be idle */
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* Return error if either the width or height is zero */ 
+    if ((sWidth == 0) || (sHeight == 0) || (dHeight == 0))
+        return -1;
+    
+#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY
+    /* Get the transparency settings. The transparency does not work with Alpha Blend,
+       therefore, save the transparency setting, disable, and restore it back later. */
+    transparency = deGetTransparency();
+#endif
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, sBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel conversion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      sPitch / BYTE_PER_PIXEL(bpp)));
+        
+    /* Set the Source Height */
+    POKE_32(DE_STRETCH_FORMAT, 
+        FIELD_VALUE(PEEK_32(DE_STRETCH_FORMAT), DE_STRETCH_FORMAT, SOURCE_HEIGHT, sHeight));
+        
+    /* Set the alpha blend value */
+    POKE_32(DE_ALPHA,
+        FIELD_VALUE(0, DE_ALPHA, VALUE, alphaValue));
+
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+#ifdef ENABLE_192_BYTES_PATCH
+    /* Workaround for 192 byte requirement */
+    if ((sWidth * bytePerPixel) > 192)
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "width * bytePerPixel = %x (> 192 bytes)\n", sWidth * bytePerPixel));
+
+        while (1)
+        {
+            deWaitForNotBusy();
+            
+            /* Set the source coordinate */    
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+
+            /* Set the destination coordinate */        
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+            /* Set the Destination Dimension */    
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, dHeight));
+
+            /* Setup Control Register */
+            de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START)    |
+                      FIELD_SET(0, DE_CONTROL, COMMAND, ALPHA_BLEND)  |
+                      FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                      FIELD_VALUE(0, DE_CONTROL, ROP, rop2)      |
+                      ((sHeight < dHeight) ?
+                            FIELD_SET(0, DE_CONTROL, STRETCH, ENABLE) :
+                            FIELD_SET(0, DE_CONTROL, STRETCH, DISABLE));
+
+            POKE_32(DE_CONTROL, de_ctrl);
+
+            if (xChunk == sWidth)
+                break;
+
+            sx += xChunk;
+            dx += xChunk;
+            sWidth -= xChunk;
+
+            if (xChunk > sWidth)
+            {
+                /* This is the last chunk. */
+                xChunk = sWidth;
+            }
+        }
+    }
+    else
+#endif
+    {
+        deWaitForNotBusy();
+            
+        /* Set the source coordinate */    
+        POKE_32(DE_SOURCE,
+            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+
+        /* Set the destination coordinate */        
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+        /* Set the Destination Dimension */    
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    sWidth) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, dHeight));
+
+        /* Setup Control Register */
+        de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START)    |
+                  FIELD_SET(0, DE_CONTROL, COMMAND, ALPHA_BLEND)  |
+                  FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                  FIELD_VALUE(0, DE_CONTROL, ROP, rop2)      |
+                  ((sHeight < dHeight) ?
+                        FIELD_SET(0, DE_CONTROL, STRETCH, ENABLE) :
+                        FIELD_SET(0, DE_CONTROL, STRETCH, DISABLE));
+
+        POKE_32(DE_CONTROL, de_ctrl);
+    }
+
+#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY
+    /* Restore back the transparency */
+    deWaitForNotBusy();
+    de_ctrl = PEEK_32(de_ctrl) | transparency;
+    POKE_32(DE_CONTROL, de_ctrl);
+#endif
+
+    return 0;
+}
+
+/*
+ * This function sets the monochrome pattern on the pattern registers.
+ */
+void deSetPattern(
+    unsigned long monoPatternLow,
+    unsigned long monoPatternHigh
+)
+{
+    POKE_32(DE_MONO_PATTERN_LOW, monoPatternLow);
+    POKE_32(DE_MONO_PATTERN_HIGH, monoPatternHigh);
+}
+
+/*
+ * This function uses 2D engine to fill a rectangular area with a specific pattern.
+ * The filled area includes the starting points.
+ */
+long deRectPatternFill(
+    unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,
+    unsigned long y,      /* Upper left corner (X, Y) of rectangle in pixel value */
+    unsigned long width, 
+    unsigned long height, /* width and height of rectange in pixel value */
+    unsigned long color,  /* Color to be filled */
+    unsigned long rop3)   /* ROP value */
+{
+    unsigned long de_ctrl, bytePerPixel;
+
+    bytePerPixel = bpp/8;
+    
+    if (deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* deReset(); */
+    }
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    POKE_32(DE_FOREGROUND, color);
+    
+    /* Set the pixel format of the destination */
+    deSetPixelFormat(bpp);
+
+#ifdef ENABLE_192_BYTES_PATCH
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if (((rop3 != ROP2_COPY) || (rop3 != ROP2_Sn) || (rop3 != ROP2_Dn) || 
+         (rop3 != ROP2_D) || (rop3 != ROP2_BLACK) || (rop3 != ROP2_WHITE)) && 
+        ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            deWaitForNotBusy();
+            
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    x)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+                
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+                FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+                //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+                FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+                FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+                FIELD_VALUE(0, DE_CONTROL,  ROP,        rop3);
+
+            POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+
+            if (xChunk == width) break;
+
+            x += xChunk;
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+            FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+            //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+            FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+            FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+            FIELD_VALUE(0, DE_CONTROL,  ROP,        rop3);
+
+        POKE_32(DE_CONTROL, de_ctrl | deGetTransparency());
+    }
+    
+    return 0;
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.h
new file mode 100644
index 000000000000..00c937350c1b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_2d.h
@@ -0,0 +1,480 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  2d.h --- SM750/SM718 DDK 
+*  This file contains the definitions for the 2D Engine interrupt.
+* 
+*******************************************************************/
+#ifndef _2D_H_
+#define _2D_H_
+
+//#include "csc.h"
+
+#define POKE_8(address, value)          pokeRegisterByte(address, value)
+#define POKE_16(address, value)         pokeRegisterWord(address, value)
+#define POKE_32(address, value)         pokeRegisterDWord(address, value)
+#define PEEK_8(address)                 peekRegisterByte(address)
+#define PEEK_16(address)                peekRegisterWord(address)
+#define PEEK_32(address)                peekRegisterDWord(address)
+
+/* Rotation Direction */
+typedef enum _rotate_dir_t
+{
+    ROTATE_NORMAL = 0,
+    ROTATE_90_DEGREE,
+    ROTATE_180_DEGREE,
+    ROTATE_270_DEGREE
+}
+rotate_dir_t;
+
+/*
+ * 2D Engine Initialization.
+ * This function must be called before other 2D functions.
+ * Assumption: A specific vidoe mode has been properly set up.
+ */
+void ddk750_deInit(void);
+
+/*
+ * Reset 2D engine by 
+ * 1) Aborting the current 2D operation.
+ * 2) Re-enable 2D engine to normal state.
+ */
+void deReset(void);
+ 
+/*
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long deWaitForNotBusy(void);
+
+/* deWaitIdle() function.
+ *
+ * This function is same as deWaitForNotBusy(), except application can
+ * input the maximum number of times that this function will check 
+ * the idle register.
+ *
+ * Its usage is mainly for debugging purpose.
+ *
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long deWaitIdle(unsigned long i);
+
+/*
+ * This function enable/disable clipping area for the 2d engine.
+ * Note that the clipping area is always rectangular.
+ * 
+ */
+long deSetClipping(
+unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */
+unsigned long x1,     /* x1, y1 is the upper left corner of the clipping area */
+unsigned long y1,     /* Note that the region includes x1 and y1 */
+unsigned long x2,     /* x2, y2 is the lower right corner of the clippiing area */
+unsigned long y2);    /* Note that the region will not include x2 and y2 */
+
+/* 
+ * Function description:
+ * When transparency is enable, the blt engine compares each pixel value 
+ * (either source or destination) with DE_COLOR_COMPARE register.
+ * If match, the destination pixel will NOT be updated.
+ * If not match, the destination pixel will be updated.
+ */
+long deSetTransparency(
+unsigned long enable,     /* 0 = disable, 1 = enable transparency feature */
+unsigned long tSelect,    /* 0 = compare source, 1 = compare destination */
+unsigned long tMatch,     /* 0 = Opaque mode, 1 = transparent mode */
+unsigned long ulColor);   /* Color to compare. */
+
+/*
+ * This function uses 2D engine to fill a rectangular area with a specific color.
+ * The filled area includes the starting points.
+ */
+long deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/
+unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,      /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long color,  /* Color to be filled */
+unsigned long rop2);  /* ROP value */
+
+/*
+ * Video Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk750_deVideoMem2VideoMemBlt(
+unsigned long sBase,  /* Address of source: offset in frame buffer */
+unsigned long sPitch, /* Pitch value of source surface in BYTE */
+unsigned long sx,
+unsigned long sy,     /* Starting coordinate of source surface */
+unsigned long dBase,  /* Address of destination: offset in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long rop2);  /* ROP value */
+
+/*
+ * System Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long deSystemMem2VideoMemBusMasterBlt(
+    unsigned char *pSBase,  /* Address of source: offset in frame buffer */
+    unsigned long sPitch,   /* Pitch value of source surface in BYTE */
+    unsigned long sx,
+    unsigned long sy,       /* Starting coordinate of source surface */
+    unsigned long dBase,    /* Address of destination: offset in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectangle in pixel value */
+    unsigned long rop2      /* ROP value */
+);
+
+/* 
+ * System memory to Video memory data transfer
+ * Note: 
+ *         We also call it HOST Blt.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long deSystemMem2VideoMemBlt(
+unsigned char *pSrcbuf, /* pointer to source data in system memory */
+long srcDelta,          /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long rop2);    /* ROP value */
+
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is monochrome image in system memory.
+ * This function expands the monochrome data to color image in video memory.
+ */
+long deSystemMem2VideoMemMonoBlt(
+unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
+long srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
+unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);    /* ROP value */
+
+#if 0
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in System memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deSystemMem2VideoMemMonoBusMasterBlt(
+    unsigned char *pSBase,  /* Address of mono-chrome source data in frame buffer */
+    unsigned long sPitch,   /* Pitch value (in bytes) of the source buffer. */
+    unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+    unsigned long dBase,    /* Base address of destination in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width,    /* width of mono-chrome picture in pixel value */
+    unsigned long height,   /* height of mono-chrome picture in pixel value */
+    unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+    unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+    unsigned long rop2      /* ROP value */
+);
+#endif
+
+/*
+ * This function cache font table into frame buffer.
+ *
+ * Inputs:
+ *      Pointer to font table in system memory.
+ *      Charcter size in byte: How many bytes are used to store the font for one characer.
+ *      As an example: For 8x8 mono font, the size is 8 bytes; 
+ *                     For 8x16 mono font, the size is 16 bytes.
+ *                     For 16x32 mono font, the size is 64 bytes.
+ *      Number of characters in the font table.
+ *      Pointer to location of frame buffer to store the font: This is an offset from the beginning of frame buffer.
+ *  
+ * Rules for storing fonts in off-screen.
+ *     1) Base address of font table must be 16 byte (or 128 bit) aligned.
+ *     2) Each font character must be stored in a 16 byte (128 bit) aligned
+ *        location.
+ *
+ */
+long deCacheFontToFrameBuffer(
+unsigned char *fontTable,   /* Pointer to font table in system memory */
+unsigned long sizeOfChar,   /* How many bytes for one monochrome character */
+unsigned long numberOfChar, /* Number of characters in the font table */
+unsigned long fbAddr);      /* Destination in Video memory to store the font */
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in Video memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deVideoMem2VideoMemMonoBlt(
+unsigned long sBase,  /* Address of mono-chrome source data in frame buffer */
+unsigned long dBase,  /* Base address of destination in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width,  /* width of mono-chrome picture in pixel value */
+unsigned long height, /* height of mono-chrome picture in pixel value */
+unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);  /* ROP value */
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * 
+ * Difference between this function and deVideoMem2VideoMemMonoBlt():
+ * 1) Input is base address of the whole font table.
+ * 2) An extra input about which character in the font table to display.
+ * 3) This function demos how to use registers DE_SOURCE and
+ *    DE_WINDOW_WIDTH, where they are set to 0 in deVideoMem2VideoMemMonoBlt().
+ */
+long deFontCacheTblMonoBlt(
+unsigned long fontTblBase,/* Base address of monochrome font table in frame buffer */
+unsigned long fontNumber, /* Which character in the font table, starting from 0 */
+unsigned long dBase,      /* Base address of destination in frame buffer */
+unsigned long dPitch,     /* Pitch value of destination surface in BYTE */
+unsigned long bpp,        /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,         /* Starting coordinate of destination surface */
+unsigned long width,      /* width of each monochrome font in pixel value */
+unsigned long height,     /* height of each monochrome font in pixel value */
+unsigned long fColor,     /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,     /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);      /* ROP value */
+
+/*
+ * Stretch Blt.
+ * 
+ * The stretch blt is done by using the CSC engine.
+ */
+long deStretchBlt(
+    unsigned long sBase,    /* Source Base address */
+    unsigned long sPitch,   /* Source pitch value in bytes */
+    unsigned long sbpp,     /* Source bits per pixel */
+    unsigned long sx,       /* Source x coordinate */            
+    unsigned long sy,       /* Source y coordinate */
+    unsigned long sWidth,   /* Width of source in pixel */
+    unsigned long sHeight,  /* Height of source in lines */
+    unsigned long dBase,    /* Destination base address */
+    unsigned long dPitch,   /* Destination pitch value in bytes */
+    unsigned long dbpp,     /* Destination bits per pixel */
+    unsigned long dx,       /* Destination x coordinate */
+    unsigned long dy,       /* Destination y coordinate */
+    unsigned long dWidth,   /* Width of the destination display */
+    unsigned long dHeight   /* Height of the destination display */
+);
+
+/*
+ * Rotation Blt.
+ * 
+ * This function rotates an image to the screen based on the given rotation direction
+ * (0, 90, 180, or 270 degree).
+ * 
+ */
+long deVideoMem2VideoMemRotateBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long width,            /* Width  of un-rotated image in pixel value */
+    unsigned long height,           /* Height of un-rotated image in pixel value */
+    rotate_dir_t rotateDirection,   /* Direction of the rotation */
+    unsigned long repeatEnable,     /* Enable repeat rotation control where the
+                                       drawing engine is started again every vsync */
+    unsigned long rop2              /* ROP control */
+);
+
+/* 
+ * Function to draw a vertical line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deVerticalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/* 
+ * Function to draw a horizontal line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deHorizontalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/* 
+ * Function to draw a line.
+ *
+ * Note:
+ *      This function is using Short Stroke Command for Vertical, Horizontal, and 
+ *      Diagonal line. Other line are drawn using the Line Draw Command.
+ */
+long deLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    long x0,                /* Starting X Coordinate */
+    long y0,                /* Starting Y Coordinate */
+    long x1,                /* Ending X Coordinate */
+    long y1,                /* Ending Y Coordinate */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/*
+ * Alpha Blend Blt.
+ * 
+ * This function blends the source with the destination image.
+ */
+long deVideoMem2VideoMemAlphaBlendBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long sWidth,           /* Source Width */
+    unsigned long sHeight,          /* Source Height */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long dHeight,          /* Destination Height (only height stretch is supported) */
+    unsigned long alphaValue,       /* Alpha value for Alpha Blend*/
+    unsigned long rop2              /* ROP control */
+);
+
+#if 0   /* These RLE functions are not working. */
+/* 
+ * Function to draw a line using RLE line strip method.
+ */
+long deStartLineStrip(
+    unsigned long dBase,        /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,       /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,          /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,            /* X Coordinate */
+    unsigned long y,            /* Y Coordinate */
+    unsigned long length,       /* Length of the line */
+    unsigned long lineCounter,  /* Line Counter */
+    unsigned long direction,    /* Direction:   0 - Left to Right
+                                                1 - Right to Left
+                                                2 - Top to Bottom
+                                                3 - Bottom to Top
+                                */
+    unsigned long color,        /* Color of the line */
+    unsigned long rop2          /* ROP value */
+);
+
+/* 
+ * Function to continue drawing a line using RLE line strip method.
+ */
+long deNextLineStrip(
+    unsigned long length,       /* Line strip length */
+    unsigned long lineCounter   /* Line Counter */
+);
+
+/* 
+ * Function to stop the RLE line strip drawing.
+ * This function has to be called to end the Line Strip drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long deStopLineStrip();
+#endif
+
+
+/*
+ * This function uses 2D engine to draw a trapezoid with a specific color.
+ * The filled area includes the starting points.
+ */
+long deStartTrapezoidFill(
+    unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,
+    unsigned long y,      /* Starting (X, Y) coordinate inside the polygon to be filled */
+    unsigned long length, /* Length of the line */
+    unsigned long color,  /* Color to be filled */
+    unsigned long rop2);
+
+/* 
+ * Function to continue drawing a line using Trapezoid Fill method.
+ */
+long deNextTrapezoidFill(
+    unsigned long x,            /* Starting X location. */
+    unsigned long length        /* Line length */
+);
+
+/* 
+ * Function to stop the Trapezoid Fill drawing.
+ * This function has to be called to end the Trapezoid Fill drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long deStopTrapezoidFill(void);
+
+#endif /* _2D_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.c
new file mode 100644
index 000000000000..ce2aaeedaa2d
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.c
@@ -0,0 +1,234 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CHIP.C --- SMI DDK 
+*  This file contains the source code for the mode table.
+* 
+*******************************************************************/
+#include "ddk750_defs.h"
+#include "ddk750_regdc.h"
+#include "ddk750_helper.h"
+#include "ddk750_power.h"
+#include "ddk750_clock.h"
+#include "ddk750_chip.h"
+#include "ddk750_help.h"
+
+/*
+ *  Get the default memory clock value used by this DDK
+ */
+unsigned long ddk750_getDefaultMemoryClock(void)
+{
+    switch(ddk750_getChipType())
+    {
+        case SM718:
+            return DEFAULT_SM718_MEMORY_CLK;
+            break;
+        case SM750:
+        	return DEFAULT_SM750_MEMORY_CLK;
+            break;
+		case SM750LE:
+        	return SM750LE_MEMORY_CLK;
+			break;
+		case SM750HS_F:
+			return SM750HS_F_MEMORY_CLK;
+			break;
+		case SM750HS_A:
+			return SM750HS_A_MEMORY_CLK;
+			break;
+		case SM750HS:
+        default:
+			return SM750HS_MEMORY_CLK;
+			break;
+    }
+}
+
+/*
+ * This function returns frame buffer memory size in Byte units.
+ */
+unsigned long ddk750_getFrameBufSize(void)
+{
+    unsigned long sizeSymbol, memSize;
+
+	sizeSymbol = FIELD_GET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, LOCALMEM_SIZE);
+	switch(sizeSymbol)
+	{
+    	case MISC_CTRL_LOCALMEM_SIZE_8M:  memSize = MB(8);  break; /* 8  Mega byte */
+    	case MISC_CTRL_LOCALMEM_SIZE_16M: memSize = MB(16); break; /* 16 Mega byte */
+    	case MISC_CTRL_LOCALMEM_SIZE_32M: memSize = MB(32); break; /* 32 Mega byte */
+    	case MISC_CTRL_LOCALMEM_SIZE_64M: memSize = MB(64); break; /* 64 Mega byte */
+    	default:                          memSize = MB(0);  break; /* 0  Mege byte */
+	}
+
+    return memSize;
+}
+
+
+/*
+ * This function returns the logical chip type defined in chip.h
+ * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or
+ * SM_UNKNOWN.
+ */
+logical_chip_type_t ddk750_getChipType()
+{
+    return SM750;
+}
+
+/*
+ *  ddk750_resetFrameBufferMemory
+ *      This function resets the Frame Buffer Memory
+ */
+void ddk750_resetFrameBufferMemory()
+{
+    unsigned long ulReg;
+	logical_chip_type_t chipType = ddk750_getChipType();
+    
+
+	/* Only SM718 and SM750 has register to reset video memory */
+	if (chipType == SM718 || chipType == SM750)
+	{        
+    	ulReg = peekRegisterDWord(MISC_CTRL);
+    	ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, RESET);
+    	pokeRegisterDWord(MISC_CTRL, ulReg);
+
+    	ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, NORMAL);
+    	pokeRegisterDWord(MISC_CTRL, ulReg);
+	}
+}
+
+/*
+ * Initialize a single chip and environment according to input parameters.
+ *
+ * Input: initchip_param_t structure.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ * Note:
+ *      Caller needs to call the detectDevice and setCurrentDevice
+ *      to set the device before calling this initChipParamEx.
+ */
+long ddk750_initChipParamEx(initchip_param_t * pInitParam)
+{
+    unsigned long ulReg;
+
+
+    /* Set power mode.
+       Check parameter validity first.
+       If calling function didn't set it up properly or set to some
+       weird value, always default it to 0.
+     */
+    if (pInitParam->powerMode > 1) 
+        pInitParam->powerMode = 0;
+    setPowerMode(pInitParam->powerMode);
+    
+    /* Set the Main Chip Clock */
+    setChipClock(MHz(pInitParam->chipClock));
+
+    /* Set up memory clock. */
+    setMemoryClock(MHz(pInitParam->memClock));
+
+    /* Set up master clock */
+    setMasterClock(MHz(pInitParam->masterClock));    
+    
+    /* Reset the memory controller. If the memory controller is not reset in SM750, 
+       the system might hang when sw accesses the memory. 
+       The memory should be resetted after changing the MXCLK.
+     */
+    if (pInitParam->resetMemory == 1)
+        ddk750_resetFrameBufferMemory();    
+    
+    if (pInitParam->setAllEngOff == 1)
+    {
+        enable2DEngine(0);
+
+        /* Disable Overlay, if a former application left it on */
+        ulReg = peekRegisterDWord(VIDEO_DISPLAY_CTRL);
+        ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); 
+        pokeRegisterDWord(VIDEO_DISPLAY_CTRL, ulReg);
+
+        /* Disable video alpha, if a former application left it on */
+        ulReg = peekRegisterDWord(VIDEO_ALPHA_DISPLAY_CTRL);
+        ulReg = FIELD_SET(ulReg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE); 
+        pokeRegisterDWord(VIDEO_ALPHA_DISPLAY_CTRL, ulReg);
+
+        /* Disable alpha plane, if a former application left it on */
+        ulReg = peekRegisterDWord(ALPHA_DISPLAY_CTRL);
+        ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); 
+        pokeRegisterDWord(ALPHA_DISPLAY_CTRL, ulReg);
+
+        /* Disable Primary hardware cursor, if a former application left it on */
+        ulReg = peekRegisterDWord(PRIMARY_HWC_ADDRESS);
+        ulReg = FIELD_SET(ulReg, PRIMARY_HWC_ADDRESS, ENABLE, DISABLE); 
+        pokeRegisterDWord(PRIMARY_HWC_ADDRESS, ulReg);
+
+        /* Disable Secondary hardware cursor, if a former application left it on */
+        ulReg = peekRegisterDWord(SECONDARY_HWC_ADDRESS);
+        ulReg = FIELD_SET(ulReg, SECONDARY_HWC_ADDRESS, ENABLE, DISABLE); 
+        pokeRegisterDWord(SECONDARY_HWC_ADDRESS, ulReg);
+#if 0
+        /* Disable ZV Port 0, if a former application left it on */
+        ulReg = peekRegisterDWord(ZV0_CAPTURE_CTRL);
+        ulReg = FIELD_SET(ulReg, ZV0_CAPTURE_CTRL, CAP, DISABLE); 
+        pokeRegisterDWord(ZV0_CAPTURE_CTRL, ulReg);
+
+        /* Disable ZV Port 1, if a former application left it on */
+        ulReg = peekRegisterDWord(ZV1_CAPTURE_CTRL);
+        ulReg = FIELD_SET(ulReg, ZV1_CAPTURE_CTRL, CAP, DISABLE); 
+        pokeRegisterDWord(ZV1_CAPTURE_CTRL, ulReg);
+       
+        /* Disable ZV Port Power, if a former application left it on */
+        enableZVPort(0);
+        
+        /* Disable i2c */
+        enableI2C(0);
+        
+        /* Disable DMA Channel, if a former application left it on */
+        ulReg = peekRegisterDWord(DMA_ABORT_INTERRUPT);
+        ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT);
+        pokeRegisterDWord(DMA_ABORT_INTERRUPT, ulReg);
+        
+        /* Disable DMA Power, if a former application left it on */
+        enableDMA(0);
+#endif 		
+    }
+
+    /* We can add more initialization as needed. */
+        
+    return 0;
+}
+
+/*
+ * Initialize chip with default parameters.
+ *
+ * Input: none.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ * Note:
+ *      This function initialize with a default set of parameters.
+ *      Use initChipParam() if you don't want default parameters.
+ */
+long ddk750_initChip()
+{
+    initchip_param_t initParam;
+    
+    /* Check if any SMI VGX family chip exist and alive */
+//	if (detectDevices() == 0)
+//        return (-1);
+
+    /* Initialize the chip with some default parameters */
+    initParam.powerMode = 0;
+    initParam.memClock = ddk750_getDefaultMemoryClock();
+    initParam.chipClock = initParam.memClock;
+    initParam.masterClock = initParam.chipClock/3;
+
+    initParam.setAllEngOff = 1;
+    initParam.resetMemory = 1;
+    
+    return(ddk750_initChipParamEx(&initParam));
+}
\ No newline at end of file
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.h
new file mode 100644
index 000000000000..94e54d75894c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_chip.h
@@ -0,0 +1,194 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CHIP.H --- SMI DDK 
+*  This file contains the source code for the SM750/SM718 chip.
+* 
+*******************************************************************/
+#ifndef _CHIP_H_
+#define _CHIP_H_
+
+/* This is all the chips recognized by this library */
+typedef enum _logical_chip_type_t
+{
+    SM_UNKNOWN = 0,
+    SM718 = 1,
+    SM750 = 2,
+    SM750LE = 3,
+	/* There will 3 versions of SM750HS because of different interfaces connected to the Graphic IP.
+	   The major difference between them are the methods to set up the PLL for pixel clock. */
+	SM750HS = 4,	/* SMI FPGA verification version */
+	SM750HS_F = 5,  /* HiS FPGA verification version */
+	SM750HS_A = 6	/* HiS ASIC version */
+}
+logical_chip_type_t;
+
+/* input struct to initChipParam() function */
+typedef struct _initchip_param_t
+{
+    unsigned short powerMode;    /* Use power mode 0 or 1 */
+    unsigned short chipClock;    /* Speed of main chip clock in MHz unit
+                                    0 = keep the current clock setting
+                                    Others = the new main chip clock
+                                  */
+    unsigned short memClock;     /* Speed of memory clock in MHz unit
+                                    0 = keep the current clock setting
+                                    Others = the new memory clock
+                                  */
+    unsigned short masterClock;  /* Speed of master clock in MHz unit 
+                                    0 = keep the current clock setting
+                                    Others = the new master clock
+                                  */
+    unsigned short setAllEngOff; /* 0 = leave all engine state untouched.
+                                    1 = make sure they are off: 2D, Overlay,
+                                    video alpha, alpha, hardware cursors
+                                 */
+    unsigned char resetMemory;   /* 0 = Do not reset the memory controller
+                                    1 = Reset the memory controller
+                                  */
+
+    /* More initialization parameter can be added if needed */
+}
+initchip_param_t;
+
+/*
+ *  Get the default memory clock value used by this DDK
+ */
+unsigned long ddk750_getDefaultMemoryClock(void);
+
+/*
+ * This function returns frame buffer memory size in Byte units.
+ */
+unsigned long ddk750_getFrameBufSize(void);
+
+/*
+ * This function gets the Frame buffer location.
+ */
+unsigned char ddk750_getFrameBufLocation(void);
+
+/*
+ * This function returns the logical chip type defined in chip.h
+ * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or
+ * SM_UNKNOWN.
+ */
+logical_chip_type_t ddk750_getChipType(void);
+
+/*
+ * Return a char string name of the current chip.
+ * It's convenient for application need to display the chip name.
+ */
+char * ddk750_getChipTypeString(void);
+
+/*
+ *  resetFrameBufferMemory
+ *      This function resets the Frame Buffer Memory
+ */
+void ddk750_resetFrameBufferMemory(void);
+
+/*
+ * Initialize a single chip and environment according to input parameters.
+ *
+ * Input: initchip_param_t structure.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ * Note:
+ *      Caller needs to call the detectDevice and setCurrentDevice
+ *      to set the device before calling this initChipParamEx.
+ */
+long ddk750_initChipParamEx(initchip_param_t * pInitParam);
+
+/*
+ * Initialize every chip and environment according to input parameters. 
+ * (Obsolete)
+ *
+ * Input: initchip_param_t structure.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ */
+long ddk750_initChipParam(initchip_param_t * pInitParam);
+
+/*
+ * Initialize a single chip with default parameters.
+ *
+ * Input: none.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ * Note:
+ *      Caller needs to call the detectDevice and setCurrentDevice
+ *      to set the device before calling this initChipEx.
+ */
+long ddk750_initChipEx(void);
+
+/*
+ * Initialize the chip with default parameters.
+ *
+ * Input: none.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ */
+long ddk750_initChip(void);
+
+/*******************************************************************
+ * Scratch Data implementation (To be used by DDK library only)
+ *******************************************************************/
+ 
+/*
+ * Set Scratch Data
+ */
+void setScratchData(
+    unsigned long dataFlag,
+    unsigned long data
+);
+
+/*
+ * Get Scratch Data
+ */
+unsigned long getScratchData(
+    unsigned long dataFlag
+);
+
+
+#define MB(x) (x*0x100000) /* Don't use this macro if x is fraction number */
+
+/* Memory Clock Default Values */
+#define DEFAULT_SM750_MEMORY_CLK        290
+#define DEFAULT_SM718_MEMORY_CLK        290
+
+/* Cheok_0509: Define some fixed values for SM750LE */
+#define SM750LE_REVISION_ID 0XFE
+#define SM750LE_MEMORY_CLK  333    /* In MHz */
+#define SM750LE_MASTER_CLK  130    /* in MHz */
+#define SM750LE_MEM_SIZE    MB(16) /* SP605 has 64M, but Huawei's actual system has only 16M */
+#define SM750LE_I2C_SCL     0      /* GPIO 0 is used as I2C clk */
+#define SM750LE_I2C_SDA     1      /* GPIO 1 is used as I2C data */
+#define CH7301_I2C_ADDRESS  0xEC /* I2C address of CH7301 in Xilinx SP605 */
+
+/* Cheok_2012_1211: Define some fixed values for SM750HS */
+/* The following values are fixed in FPGA and cannot be adjusted */
+#define SM750HS_REVISION_ID 0XE0
+#define SM750HS_MEMORY_CLK  333    /* In MHz */
+#define SM750HS_MASTER_CLK  100    /* in MHz */
+#define SM750HS_MEM_SIZE    MB(16) /* Actual size unknown at the moment */
+
+#define SM750HS_F_REVISION_ID 0X00
+#define SM750HS_F_MEMORY_CLK  333    /* In MHz */
+#define SM750HS_F_MASTER_CLK  100    /* in MHz */
+#define SM750HS_F_MEM_SIZE    MB(16) /* Actual size unknown at the moment */
+
+#define SM750HS_A_REVISION_ID 0X10
+#define SM750HS_A_MEMORY_CLK  333    /* In MHz */
+#define SM750HS_A_MASTER_CLK  100    /* in MHz */
+#define SM750HS_A_MEM_SIZE    MB(16) /* Actual size unknown at the moment */
+
+#endif /* _CHIP_H_ */
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.c
new file mode 100644
index 000000000000..565af8b37063
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.c
@@ -0,0 +1,564 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CLOCK.C --- Voyager GX DDK 
+*  This file contains source code for the Voyager Family PLL's
+* 
+*******************************************************************/
+#include "ddk750_defs.h"
+//#include "ddk750_hardware.h"
+#include "ddk750_helper.h"
+#include "ddk750_power.h"
+#include "ddk750_clock.h"
+#include "ddk750_chip.h"
+#include "ddk750_helper.h"
+#include "ddk750_help.h"
+
+//#include "ddkdebug.h"
+
+static unsigned char g_ucMemoryClockDivider[] = { 1, 2, 3, 4 };
+static unsigned char g_ucMasterClockDivider[] = { 3, 4, 6, 8 };
+
+/*
+ * A local function to calculate the clock value of the given PLL.
+ *
+ * Input:
+ *      Pointer to a PLL structure to be calculated based on the
+ *      following formula:
+ *      inputFreq * M / N / (2 to the power of OD) / (2 to the power of POD)
+ */
+unsigned long calcPLL(pll_value_t *pPLL)
+{
+    return (pPLL->inputFreq * pPLL->M / pPLL->N / twoToPowerOfx(pPLL->OD) / twoToPowerOfx(pPLL->POD));
+}
+
+/*
+ * Given a requested clock frequency, this function calculates the 
+ * best M, N & OD values for the PLL.
+ * 
+ * Input: Requested pixel clock in Hz unit.
+ *        The followiing fields of PLL has to be set up properly:
+ *        pPLL->clockType, pPLL->inputFreq.
+ *
+ * Output: Update the PLL structure with the proper M, N and OD values
+ * Return: The actual clock in Hz that the PLL is able to set up.
+ *
+ * The PLL uses this formula to operate: 
+ * requestClk = inputFreq * M / N / (2 to the power of OD) / (2 to the power of POD)
+ *
+ * The PLL specification mention the following restrictions:
+ *      1 MHz <= inputFrequency / N <= 25 MHz
+ *      200 MHz <= outputFrequency <= 1000 MHz --> However, it seems that it can 
+ *                                                 be set to lower than 200 MHz.
+ */
+unsigned long calcPllValue(
+unsigned long ulRequestClk, /* Required pixel clock in Hz unit */
+pll_value_t *pPLL           /* Structure to hold the value to be set in PLL */
+)
+{
+    unsigned long M, N, OD, POD = 0, diff, pllClk, odPower, podPower, tempRequestClk;
+    unsigned long bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */
+
+    /* Init PLL structure to know states */
+    pPLL->M = 0;
+    pPLL->N = 0;
+    pPLL->OD = 0;
+    pPLL->POD = 0;
+
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+    {
+        /* SM750LE don't have prgrammable PLL and M/N values to work on.
+           Just return the requested clock. */
+        return ulRequestClk;
+    }
+
+    /* Convert everything in Khz range in order to avoid calculation overflow */
+    pPLL->inputFreq /= 1000;
+    tempRequestClk = ulRequestClk / 1000;
+
+    /* If the requested clock is higher than 1 GHz, then set it to the maximum, which is
+       1 GHz. */
+    if (tempRequestClk > MHz(1))
+        tempRequestClk = MHz(1);
+
+    /* The maximum of post divider is 8. */
+    for (POD=0; POD<=3; POD++)
+    {
+        /* MXCLK_PLL does not have post divider. */
+        if ((POD > 0) && (pPLL->clockType == MXCLK_PLL))
+            break;
+    
+        /* Work out 2 to the power of POD */
+        podPower = twoToPowerOfx(POD);
+        
+        /* OD has only 2 bits [15:14] and its value must between 0 to 3 */
+        for (OD=0; OD<=3; OD++)
+        {
+            /* Work out 2 to the power of OD */
+            odPower = twoToPowerOfx(OD);            
+
+            /* N has 4 bits [11:8] and its value must between 2 and 15. 
+               The N == 1 will behave differently --> Result is not correct. */
+            for (N=2; N<=15; N++)
+            {
+                /* The formula for PLL is ulRequestClk = inputFreq * M / N / (2^OD)
+                   In the following steps, we try to work out a best M value given the others are known.
+                   To avoid decimal calculation, we use 1000 as multiplier for up to 3 decimal places of accuracy.
+                */
+                M = tempRequestClk * N * odPower * podPower / pPLL->inputFreq;
+
+                /* M field has only 8 bits, reject value bigger than 8 bits */
+                if (M < 256)
+                {
+                    /* Calculate the actual clock for a given M & N */        
+                    pllClk = pPLL->inputFreq * M / N / odPower / podPower;
+
+                    /* How much are we different from the requirement */
+                    diff = absDiff(pllClk, tempRequestClk);
+        
+                    if (diff < bestDiff)
+                    {
+                        bestDiff = diff;
+
+                        /* Store M and N values */
+                        pPLL->M  = M;
+                        pPLL->N  = N;
+                        pPLL->OD = OD;
+                        pPLL->POD = POD;
+                    }
+                }
+            }
+        }
+    }
+    
+    /* Restore input frequency from Khz to hz unit */
+    pPLL->inputFreq *= 1000;
+
+    /* Output debug information */
+//    DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk));
+//    DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, M=%d, N=%d, OD=%d, POD=%d\n", pPLL->inputFreq, pPLL->M, pPLL->N, pPLL->OD, pPLL->POD));
+
+    /* Return actual frequency that the PLL can set */
+    return calcPLL(pPLL);
+}
+
+/*
+ * Set up the corresponding bit field of the programmable PLL register.
+ *
+ * Input: Pointer to PLL structure with type and values set up properly.
+ *        Usually, calcPllValue() function will be called before this to calculate the values first.
+ *
+ */
+unsigned long formatPllReg(pll_value_t *pPLL)
+{
+    unsigned long ulPllReg = 0;
+
+    /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter
+       to work out the bit fields in the register.
+       On returning a 32 bit number, the value can be applied to any PLL in the calling function.
+    */
+    ulPllReg =
+        FIELD_SET(  0, PRIMARY_PLL_CTRL, BYPASS, OFF)
+      | FIELD_SET(  0, PRIMARY_PLL_CTRL, POWER,  ON)
+      | FIELD_SET(  0, PRIMARY_PLL_CTRL, INPUT,  OSC)
+      | FIELD_VALUE(0, PRIMARY_PLL_CTRL, POD,    pPLL->POD)      
+      | FIELD_VALUE(0, PRIMARY_PLL_CTRL, OD,     pPLL->OD)
+      | FIELD_VALUE(0, PRIMARY_PLL_CTRL, N,      pPLL->N)
+      | FIELD_VALUE(0, PRIMARY_PLL_CTRL, M,      pPLL->M);
+
+ //   DDKDEBUGPRINT((DISPLAY_LEVEL, "formatPllReg: PLL register value = 0x%08x\n", ulPllReg));
+
+    return(ulPllReg);
+}
+
+/*
+ * Get the programmable PLL register value.
+ *
+ * Input:
+ *      clockType   - The clock Type that the PLL is associated with.
+ *      pPLL        - Pointer to a PLL structure to be filled with the
+ *                    PLL value read from the register.
+ * Output:
+ *      The actual clock value calculated, together with the values of
+ *      PLL register stored in the pPLL pointer.
+ */
+unsigned long getPllValue(clock_type_t clockType, pll_value_t *pPLL)
+{
+    unsigned long ulPllReg = 0;
+    
+    pPLL->inputFreq = DEFAULT_INPUT_CLOCK;
+    pPLL->clockType = clockType;
+    
+    switch (clockType)
+    {
+        case MXCLK_PLL:
+            ulPllReg = peekRegisterDWord(MXCLK_PLL_CTRL);
+            break;
+        case PRIMARY_PLL:
+            ulPllReg = peekRegisterDWord(PRIMARY_PLL_CTRL);
+            break;
+        case SECONDARY_PLL:
+            ulPllReg = peekRegisterDWord(SECONDARY_PLL_CTRL);
+            break;
+        case VGA0_PLL:
+            ulPllReg = peekRegisterDWord(VGA_PLL0_CTRL);
+            break;
+        case VGA1_PLL:
+            ulPllReg = peekRegisterDWord(VGA_PLL1_CTRL);
+            break;
+    }
+    
+    pPLL->M = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, M);
+    pPLL->N = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, N);
+    pPLL->OD = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, OD);
+    pPLL->POD = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, POD);    
+
+    return calcPLL(pPLL);
+}
+
+/*
+ * This function set up the main chip clock.
+ *
+ * Input: Frequency to be set.
+ */
+void setChipClock(unsigned long frequency)
+{
+    pll_value_t pll;
+    unsigned long ulActualMxClk;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return;
+#endif 
+
+    if (frequency != 0)
+    {
+        /*
+         * Set up PLL, a structure to hold the value to be set in clocks.
+         */
+        pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
+        pll.clockType = MXCLK_PLL;
+
+        /* 
+         * Call calcPllValue() to fill up the other fields for PLL structure.
+         * Sometime, the chip cannot set up the exact clock required by User.
+         * Return value from calcPllValue() gives the actual possible clock.
+         */
+ //       DDKDEBUGPRINT((INIT_LEVEL, "setMemoryClock: frequency = 0x%08x\n", frequency));
+        ulActualMxClk = calcPllValue(frequency, &pll);
+ //       DDKDEBUGPRINT((INIT_LEVEL, "setMemoryClock: Current Clock = 0x%08x\n", ulActualMxClk));
+
+        /* Master Clock Control: MXCLK_PLL */
+        pokeRegisterDWord(MXCLK_PLL_CTRL, formatPllReg(&pll));
+    }
+}
+
+/*
+ * This function gets the Main Chip Clock value.
+ *
+ * Output:
+ *      The Actual Main Chip clock value.
+ */
+unsigned long getChipClock()
+{
+    pll_value_t pll;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the chip clock is fixed */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return (MHz(SM750LE_MASTER_CLK));
+#endif 
+
+    return getPllValue(MXCLK_PLL, &pll);
+}
+
+/*
+ * This function set up the memory clock.
+ *
+ * Input: Frequency to be set.
+ *
+ * NOTE:
+ *      The maximum frequency that the DDR Memory clock can be set is 336MHz.
+ */
+void setMemoryClock(unsigned long frequency)
+{
+    unsigned long ulReg, divisor;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return;
+#endif 
+    
+    if (frequency != 0)        
+    {
+        /* Set the frequency to the maximum frequency that the DDR Memory can take
+           which is 336MHz. */
+        if (frequency > MHz(336))
+            frequency = MHz(336);
+        
+        /* Calculate the divisor */
+        divisor = (unsigned long) roundedDiv(getChipClock(), frequency);
+        
+        /* Set the corresponding divisor in the register. */
+        ulReg = peekRegisterDWord(CURRENT_GATE);
+        switch(divisor)
+        {   
+            default:
+            case 1:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_1);
+                break;
+            case 2:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_2);
+                break;
+            case 3:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_3);
+                break;
+            case 4:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_4);
+                break;
+        }
+        
+        setCurrentGate(ulReg);
+    }
+}
+
+/*
+ * This function set up the master clock (MCLK).
+ *
+ * Input: Frequency to be set.
+ *
+ * NOTE:
+ *      The maximum frequency the engine can run is 168MHz.
+ */
+void setMasterClock(unsigned long frequency)
+{
+    unsigned long ulReg, divisor;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the master clock is fixed. Nothing to set. */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return;
+#endif 
+    
+    if (frequency != 0)
+    {
+        /* Set the frequency to the maximum frequency that the SM750 engine can
+           run, which is about 190 MHz. */
+        if (frequency > MHz(190))
+            frequency = MHz(190);
+               
+        /* Calculate the divisor */
+        divisor = (unsigned long) roundedDiv(getChipClock(), frequency);
+        
+        /* Set the corresponding divisor in the register. */
+        ulReg = peekRegisterDWord(CURRENT_GATE);
+        switch(divisor)
+        {
+            default:
+            case 3:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_3);
+                break;
+            case 4:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_4);
+                break;
+            case 6:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_6);
+                break;
+            case 8:
+                ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_8);
+                break;
+        }
+        
+        setCurrentGate(ulReg);
+    }
+}
+
+/*
+ * This function get the Primary Display Control Pixel Clock value.
+ *
+ * Output:
+ *      The Primary Display Control Pixel Clock value in whole number.
+ */
+unsigned long getPrimaryDispCtrlClock()
+{
+    pll_value_t pll;
+    return getPllValue(PRIMARY_PLL, &pll);
+}
+
+/*
+ * This function get the Secondary Display Control Pixel Clock value.
+ *
+ * Output:
+ *      The Secondary Display Control Pixel Clock value in whole number.
+ */
+unsigned long getSecondaryDispCtrlClock()
+{
+    pll_value_t pll;
+    return getPllValue(SECONDARY_PLL, &pll);
+}
+
+/*
+ * This function gets the Master Clock value.
+ *
+ * Output:
+ *      The Master Clock value in whole number.
+ */
+unsigned long getMasterClock()
+{
+    unsigned long value, divisor;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the chip clock is fixed */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return(MHz(SM750LE_MASTER_CLK));
+#endif 
+    
+    /* Get the divisor */
+    value = peekRegisterDWord(CURRENT_GATE);
+    switch (FIELD_GET(value, CURRENT_GATE, MCLK))
+    {
+        case CURRENT_GATE_MCLK_DIV_3:
+            divisor = 3;
+            break;
+        case CURRENT_GATE_MCLK_DIV_4:
+            divisor = 4;
+            break;
+        case CURRENT_GATE_MCLK_DIV_6:
+            divisor = 6;
+            break;
+        case CURRENT_GATE_MCLK_DIV_8:
+            divisor = 8;
+            break;
+    }
+
+    return (getChipClock() / divisor);
+}
+
+/*
+ * This function gets the Memory Clock value.
+ *
+ * Output:
+ *      The Memory Clock value in whole number.
+ */
+unsigned long getMemoryClock()
+{
+    unsigned long value, divisor;
+
+#if 1
+	/* Cheok_0509: For SM750LE, the memory clock is fixed. */
+	//if (getChipType() == SM750LE)
+	if (ddk750_getChipType() >= SM750LE)
+		return (MHz(SM750LE_MEMORY_CLK));
+#endif 
+    
+    /* Get the divisor */
+    value = peekRegisterDWord(CURRENT_GATE);
+    switch (FIELD_GET(value, CURRENT_GATE, M2XCLK))
+    {
+        case CURRENT_GATE_M2XCLK_DIV_1:
+            divisor = 1;
+            break;
+        case CURRENT_GATE_M2XCLK_DIV_2:
+            divisor = 2;
+            break;
+        case CURRENT_GATE_M2XCLK_DIV_3:
+            divisor = 3;
+            break;
+        case CURRENT_GATE_M2XCLK_DIV_4:
+            divisor = 4;
+            break;
+    }
+
+    return (getChipClock() / divisor);
+}
+
+/*
+ * This function gets the Master Clock Divider Values List.
+ *
+ * Output:
+ *      The list of Master Clock divider values.
+ */
+unsigned char *getMasterClockDivider()
+{
+    return g_ucMasterClockDivider;
+}
+
+/*
+ * This function gets the total number of Master Clock Divider Values.
+ */
+unsigned long getTotalMasterClockDivider()
+{
+    return (sizeof(g_ucMasterClockDivider)/sizeof(unsigned char));
+}
+
+/*
+ * This function gets the Memory Clock Divider Values List.
+ *
+ * Output:
+ *      The list of Memory Clock divider values.
+ */
+unsigned char *getMemoryClockDivider()
+{
+    return g_ucMemoryClockDivider;
+}
+
+/*
+ * This function gets the total number of Memory Clock Divider Values.
+ */
+unsigned long getTotalMemoryClockDivider()
+{
+    return (sizeof(g_ucMemoryClockDivider)/sizeof(unsigned char));
+}
+
+/*
+ * This function uses the Master Clock PLL clock counter to provide some delay in ms.
+ */
+void waitMasterClock(
+    unsigned long miliseconds
+)
+{
+    unsigned long totalClockCount, startCount, endCount, diff, value;
+    
+    /* Calculate the clock counter needed for the delay */
+    totalClockCount = roundedDiv(getMasterClock(), 1000) * miliseconds;
+    
+    /* Enable PLL Clock Count*/
+    pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, PLL_CLK_COUNT, ON));
+    
+    /* Start the counter */
+    endCount = 0;
+    while (totalClockCount > 0)
+    {
+        startCount = endCount;
+        value = FIELD_GET(peekRegisterDWord(PLL_CLK_COUNT), PLL_CLK_COUNT, COUNTER);
+        endCount = value;
+        
+        /* Check if the counter has overflown */
+        if (startCount > endCount)
+            endCount += 0x10000;
+        
+        /* Find the counter difference from last to start counter. */
+        diff = endCount - startCount;
+        
+        /* Decrement the total clock counter with the difference until it reaches 0. */
+        if (totalClockCount > diff)
+            totalClockCount -= diff;
+        else
+            totalClockCount = 0;
+    }
+    
+    /* Disable the PLL Clock Count to reset the counter the next time this function is called. */
+    pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, PLL_CLK_COUNT, OFF));
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.h
new file mode 100644
index 000000000000..6c880450526d
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_clock.h
@@ -0,0 +1,178 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CLOCK.H --- Voyager GX DDK 
+* 
+*******************************************************************/
+#ifndef _CLOCK_H_
+#define _CLOCK_H_
+
+#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */
+#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */
+
+/* The following maximum value is not the optimum value. */
+/* Maximum Master Clock is about 190MHz */
+#define MAXIMUM_MASTER_CLOCK        MHz(190)
+
+/* Maximum Chip Clock (MXCLK) is 1 GHz */
+#define MAXIMUM_CHIP_CLOCK          MHz(1000)
+
+typedef enum _clock_type_t
+{
+    MXCLK_PLL,      /* Programmable Master clock */
+    PRIMARY_PLL,    /* Programmable Primary pixel clock */
+    SECONDARY_PLL,  /* Programmable Secondary pixel clock */
+    VGA0_PLL,
+    VGA1_PLL,
+}
+clock_type_t;
+
+typedef struct pll_value_t
+{
+    clock_type_t clockType;
+    unsigned long inputFreq; /* Input clock frequency to the PLL */
+    unsigned long M;
+    unsigned long N;
+    unsigned long OD;
+    unsigned long POD;
+}
+pll_value_t;
+
+/*
+ * Given a requested clock frequency, this function calculates the 
+ * best M, N & OD values for the PLL.
+ * 
+ * Input: Requested pixel clock in Hz unit.
+ *        The followiing fields of PLL has to be set up properly:
+ *        pPLL->clockType, pPLL->inputFreq.
+ *
+ * Output: Update the PLL structure with the proper N, N and OD values
+ * Return: The actual clock in Hz that the PLL is able to set up.
+ *
+ * The PLL uses this formula to operate: 
+ * requestClk = inputFreq * M / N / (2 to the power of OD)
+ *
+ */
+unsigned long calcPllValue(
+unsigned long ulRequestClk, /* Required pixel clock in Hz unit */
+pll_value_t *pPLL           /* Structure to hold the value to be set in PLL */
+);
+
+/*
+ * Set up the corresponding bit field of the programmable PLL register.
+ *
+ * Input: Pointer to PLL structure with type and values set up properly.
+ *        Usually, calcPllValue() function will be called before this to calculate the values first.
+ *
+ */
+unsigned long formatPllReg(pll_value_t *pPLL);
+
+/*
+ * This function set up the main chip clock.
+ *
+ * Input: Frequency to be set.
+ */
+void setChipClock(unsigned long frequency);
+
+/*
+ * This function gets the Main Chip Clock value.
+ *
+ * Output:
+ *      The Actual Main Chip clock value.
+ */
+unsigned long getChipClock(void);
+
+/*
+ * This function set up the memory clock.
+ *
+ * Input: Frequency to be set.
+ */
+void setMemoryClock(unsigned long frequency);
+
+/*
+ *  getMemoryClock
+ *      This function gets the Memory Clock value.
+ *
+ *  Output:
+ *      The Memory Clock value in whole number.
+ */
+unsigned long getMemoryClock(void);
+
+/*
+ * This function set up the master clock (MCLK).
+ *
+ * Input: Frequency to be set.
+ */
+void setMasterClock(unsigned long frequency);
+
+/*
+ *  getMasterClock
+ *      This function gets the Master Clock value.
+ *
+ *  Output:
+ *      The Master Clock value in whole number.
+ */
+unsigned long getMasterClock(void);
+
+/*
+ * This function get the Primary display control Pixel Clock value.
+ *
+ * Output:
+ *      The Primary display control Pixel Clock value in whole number.
+ */
+unsigned long getPrimaryDispCtrlClock(void);
+
+/*
+ * This function get the Secondary display control Pixel Clock value.
+ *
+ * Output:
+ *      The Secondary display control Pixel Clock value in whole number.
+ */
+unsigned long getSecondaryDispCtrlClock(void);
+
+/*
+ * This function gets the Master Clock Divider Values List.
+ *
+ * Output:
+ *      The list of Master Clock divider values.
+ */
+unsigned char *getMasterClockDivider(void);
+
+/*
+ * This function gets the total number of Master Clock Divider Values.
+ */
+unsigned long getTotalMasterClockDivider(void);
+
+/*
+ * This function gets the Memory Clock Divider Values List.
+ *
+ * Output:
+ *      The list of Memory Clock divider values.
+ */
+unsigned char *getMemoryClockDivider(void);
+
+/*
+ * This function gets the total number of Memory Clock Divider Values.
+ */
+unsigned long getTotalMemoryClockDivider(void);
+
+/*
+ * This function uses the Master Clock PLL clock counter to provide some delay in ms.
+ */
+void waitMasterClock(
+    unsigned long miliseconds
+);
+
+/*
+  * This function provides new logic to program the PLL registers for HiSilicon ASIC. 
+  *
+  * Input: 
+  *	The value of HiSilicon PLL register. 
+  */
+void setVclock_HiSilicon(unsigned long pll);
+
+#endif /*_CLOCK_H_*/
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.c
new file mode 100644
index 000000000000..672cd51f1809
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.c
@@ -0,0 +1,104 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CURSOR.C --- Voyager GX SDK 
+*  This file contains the definitions for the Panel cursor functions.
+* 
+*******************************************************************/
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_cursor.h"
+#include "ddk750_help.h"
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk750_initCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+)
+{
+    /*
+     * 1. Set the cursor source address 
+     */
+    pokeRegisterDWord(
+        (dispControl == PRIMARY_CTRL) ? PRIMARY_HWC_ADDRESS : SECONDARY_HWC_ADDRESS,
+        FIELD_SET(0, PRIMARY_HWC_ADDRESS, EXT, LOCAL) |
+        FIELD_VALUE(0, PRIMARY_HWC_ADDRESS, ADDRESS, base));
+        
+    /*
+     * 2. Set the cursor color composition 
+     */
+    pokeRegisterDWord(
+        (dispControl == PRIMARY_CTRL) ? PRIMARY_HWC_COLOR_12 : SECONDARY_HWC_COLOR_12, 
+        FIELD_VALUE(0, PRIMARY_HWC_COLOR_12, 1_RGB565, color1) |
+        FIELD_VALUE(0, PRIMARY_HWC_COLOR_12, 2_RGB565, color2) );
+
+    pokeRegisterDWord(
+        (dispControl == PRIMARY_CTRL) ? PRIMARY_HWC_COLOR_3 : SECONDARY_HWC_COLOR_3,
+        FIELD_VALUE(0, PRIMARY_HWC_COLOR_3, RGB565, color3));
+}
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk750_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+)
+{  
+    unsigned long value;
+
+    /* Set the XY coordinate */
+    value = FIELD_VALUE(0, PRIMARY_HWC_LOCATION, X, dx) |
+            FIELD_VALUE(0, PRIMARY_HWC_LOCATION, Y, dy);
+    
+    /* Set the top boundary select either partially outside the top boundary
+       screen or inside */
+    if (topOutside)
+        value = FIELD_SET(value, PRIMARY_HWC_LOCATION, TOP, OUTSIDE);
+    else         
+        value = FIELD_SET(value, PRIMARY_HWC_LOCATION, TOP, INSIDE);
+
+    /* Set the left boundary select either partially outside the left boundary
+       screen or inside */
+    if (leftOutside)
+        value = FIELD_SET(value, PRIMARY_HWC_LOCATION, LEFT, OUTSIDE);
+    else        
+        value = FIELD_SET(value, PRIMARY_HWC_LOCATION, LEFT, INSIDE);
+
+    /* Set the register accordingly, either Panel cursor or CRT cursor */
+    pokeRegisterDWord((dispControl == PRIMARY_CTRL) ? PRIMARY_HWC_LOCATION : SECONDARY_HWC_LOCATION, value);
+}
+
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk750_enableCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long enable
+)
+{
+    unsigned long cursorRegister, value;
+
+    cursorRegister = (dispControl == PRIMARY_CTRL) ? PRIMARY_HWC_ADDRESS : SECONDARY_HWC_ADDRESS;
+    
+	value = peekRegisterDWord(cursorRegister);
+    if (enable) 
+        value = FIELD_SET(value, PRIMARY_HWC_ADDRESS, ENABLE, ENABLE);
+    else
+        value = FIELD_SET(value, PRIMARY_HWC_ADDRESS, ENABLE, DISABLE);
+    
+    pokeRegisterDWord(cursorRegister, value);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.h
new file mode 100644
index 000000000000..c2adebaca9c8
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_cursor.h
@@ -0,0 +1,48 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  cursor.h --- SMI DDK 
+*  This file contains the definitions for the cursor functions.
+* 
+*******************************************************************/
+#ifndef _CURSOR_H_
+#define _CURSOR_H_
+
+#include "ddk750_mode.h"
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk750_initCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+);
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk750_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+);
+
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk750_enableCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long enable
+);
+
+#endif /* _CURSOR_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_defs.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_defs.h
new file mode 100644
index 000000000000..78a12f069cec
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_defs.h
@@ -0,0 +1,83 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  DEFS.H (The name of this file is defs.h in 718 DDK)
+*  This file contains register and common macro definitions.
+* 
+*******************************************************************/
+#ifndef _DEFS_H_
+#define _DEFS_H_
+
+/* For validation purpose only */
+/*#define SM750_AA*/
+//#include "ddk750_help.h"
+#include "ddk750_regsc.h"
+#include "ddk750_reggpio.h"
+//#include "ddk750_regpwm.h"
+//#include "ddk750_regssp.h"
+#include "ddk750_regdc.h"
+//#include "ddk750_regdma.h"
+//#include "ddk750_regde.h"
+//#include "ddk750_regzv.h"
+#include "ddk750_regi2c.h"
+
+/* Internal macros */
+#define _F_START(f)             (0 ? f)
+#define _F_END(f)               (1 ? f)
+#define _F_SIZE(f)              (1 + _F_END(f) - _F_START(f))
+#define _F_MASK(f)              (((1 << _F_SIZE(f)) - 1) << _F_START(f))
+#define _F_NORMALIZE(v, f)      (((v) & _F_MASK(f)) >> _F_START(f))
+#define _F_DENORMALIZE(v, f)    (((v) << _F_START(f)) & _F_MASK(f))
+
+/* Global macros */
+#define FIELD_GET(x, reg, field) \
+( \
+    _F_NORMALIZE((x), reg ## _ ## field) \
+)
+
+#define FIELD_SET(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
+)
+
+#define FIELD_VALUE(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(value, reg ## _ ## field) \
+)
+
+#define FIELD_CLEAR(reg, field) \
+( \
+    ~ _F_MASK(reg ## _ ## field) \
+)
+
+/* FIELD MACROS */
+#define FIELD_START(field)              (0 ? field)
+#define FIELD_END(field)                (1 ? field)
+#define FIELD_SIZE(field)               (1 + FIELD_END(field) - FIELD_START(field))
+#define FIELD_MASK(field)               (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field))
+#define FIELD_NORMALIZE(reg, field)     (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
+#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field))
+#define FIELD_INIT(reg, field, value)   FIELD_DENORMALIZE(reg ## _ ## field, \
+                                                          reg ## _ ## field ## _ ## value)
+#define FIELD_INIT_VAL(reg, field, value) \
+                                        (FIELD_DENORMALIZE(reg ## _ ## field, value))
+#define FIELD_VAL_SET(x, r, f, v)       x = x & ~FIELD_MASK(r ## _ ## f) \
+                                              | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v)
+
+#define RGB(r, g, b) \
+( \
+    (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define RGB16(r, g, b) \
+( \
+    (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \
+)
+
+#endif /* _DEFS_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_display.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_display.c
new file mode 100644
index 000000000000..9369b746e410
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_display.c
@@ -0,0 +1,1702 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  DISPLAY.C --- Voyager GX SDK 
+*  This file contains the source code for the panel and CRT functions.
+* 
+*******************************************************************/
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_chip.h"
+//#include "ddk750/ddk750_swi2c.h"
+#include "ddk750_display.h"
+//#include "ddk750/ddk750_dvi.h"
+#include "ddk750_power.h"
+#include "ddk750_help.h"
+
+#define Validate_718_AA     1
+
+/* When use actual Panel, then do not need to turn on the DAC. */
+#define ENABLE_PANEL_DAC 
+
+/* Monitor Detection RGB Default Threshold values */
+#define DEFAULT_MON_DETECTION_THRESHOLD         0x64
+
+
+/*
+ * This function checks whether dual panel is enabled or not
+ *
+ * Output:
+ *      0   - Not Enable
+ *      1   - Enable  
+ */
+unsigned char isDualPanelEnable(void)
+{
+    unsigned long value;
+
+    value = FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY);
+    
+    return ((value == PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_ENABLE) ? 1 : 0);
+}
+
+/*
+ * This function gets the panel type
+ *
+ * Output:
+ *      panelType   - The type of the panel to be set  
+ */
+panel_type_t getPanelType(void)
+{
+    if (FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL) == 
+        PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_ENABLE)
+    {
+        return TFT_36BIT;
+    }
+    else if (isDualPanelEnable() == 1)
+        return TFT_18BIT;
+    else
+        return TFT_24BIT;
+}
+
+/*
+ * This function sets the panel type
+ *
+ * Input:
+ *      panelType   - The type of the panel to be set  
+ */
+long setPanelType(
+    panel_type_t panelType
+)
+{
+    unsigned long value;
+            
+    /* Set the panel type. */
+    value = peekRegisterDWord(PRIMARY_DISPLAY_CTRL);
+    switch (panelType)
+    {
+        case TFT_18BIT:
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, ENABLE);
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, DISABLE);
+            break;
+        case TFT_24BIT:
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, DISABLE);
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, DISABLE);
+            break;
+        case TFT_36BIT:
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, DISABLE);
+            value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, ENABLE);
+            break;
+        default:
+            return (-1);
+    }
+    pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, value);
+    
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPanelType)PRIMARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL)));
+    
+    return 0;
+}
+
+/*
+ * Use vertical sync as time delay function.
+ *
+ * Input:
+ *          dispControl - Display Control (either panel or crt) 
+ *          vsync_count - Number of vertical sync to wait.
+ *
+ * Note:
+ *      This function is waiting for the next vertical sync.         
+ */
+void waitNextVerticalSync(disp_control_t dispControl, unsigned long vsync_count)
+{
+    unsigned long status;
+    unsigned long ulLoopCount = 0;
+    static unsigned long ulDeadLoopCount = 10000;
+    
+    if (dispControl == PRIMARY_CTRL)
+    {
+        /* Do not wait when the Primary PLL is off or display control is already off. 
+           This will prevent the software to wait forever. */
+        if ((FIELD_GET(peekRegisterDWord(PRIMARY_PLL_CTRL), PRIMARY_PLL_CTRL, POWER) ==
+             PRIMARY_PLL_CTRL_POWER_OFF) ||
+            (FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, TIMING) ==
+             PRIMARY_DISPLAY_CTRL_TIMING_DISABLE))
+        {
+            return;
+        }
+
+        while (vsync_count-- > 0)
+        {
+            ulLoopCount = 0;
+            /* Wait for end of vsync. */
+            do
+            {
+                status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL),
+                                   SYSTEM_CTRL,
+                                   PRIMARY_VSYNC);
+                if(ulLoopCount++ > ulDeadLoopCount)
+                    break;
+            }
+            while (status == SYSTEM_CTRL_PRIMARY_VSYNC_ACTIVE);
+
+            ulLoopCount = 0;
+            /* Wait for start of vsync. */
+            do
+            {
+                status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL),
+                                   SYSTEM_CTRL, 
+                                   PRIMARY_VSYNC);
+                if(ulLoopCount++ > ulDeadLoopCount)
+                    break;
+            }
+            while (status == SYSTEM_CTRL_PRIMARY_VSYNC_INACTIVE);
+        }
+    }
+    else
+    {
+        /* Do not wait when the display control is already off. This will prevent
+           the software to wait forever. */
+        if ((FIELD_GET(peekRegisterDWord(SECONDARY_PLL_CTRL), SECONDARY_PLL_CTRL, POWER) ==
+             SECONDARY_PLL_CTRL_POWER_OFF) ||
+            (FIELD_GET(peekRegisterDWord(SECONDARY_DISPLAY_CTRL), SECONDARY_DISPLAY_CTRL, TIMING) ==
+             SECONDARY_DISPLAY_CTRL_TIMING_DISABLE))
+        {
+            return;
+        }
+
+        while (vsync_count-- > 0)
+        {
+            ulLoopCount = 0;
+            /* Wait for end of vsync. */
+            do
+            {
+                status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL),
+                                   SYSTEM_CTRL,
+                                   SECONDARY_VSYNC);
+                if(ulLoopCount++ > ulDeadLoopCount)
+                    break;                
+            }
+            while (status == SYSTEM_CTRL_SECONDARY_VSYNC_ACTIVE);
+
+            ulLoopCount = 0;
+            /* Wait for start of vsync. */
+            do
+            {
+                status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL),
+                                   SYSTEM_CTRL, 
+                                   SECONDARY_VSYNC);
+                if(ulLoopCount++ > ulDeadLoopCount)
+                    break;                
+            }
+            while (status == SYSTEM_CTRL_SECONDARY_VSYNC_INACTIVE);
+        }
+    }
+}
+
+/*
+ * Use Primary vertical sync as time delay function.
+ * Input: Number of vertical sync to wait.
+ */
+void primaryWaitVerticalSync(unsigned long vsync_count)
+{
+    waitNextVerticalSync(PRIMARY_CTRL, vsync_count);
+}
+
+/*
+ * Use crt vertical sync as time delay function.
+ * Input: Number of vertical sync to wait.
+ */
+void secondaryWaitVerticalSync(unsigned long vsync_count)
+{
+    waitNextVerticalSync(SECONDARY_CTRL, vsync_count);
+}
+
+/*
+ * Use panel vertical sync line as time delay function.
+ * This function does not wait for the next VSync. Instead, it will wait
+ * until the current line reaches the Vertical Sync line.
+ * This function is really useful when flipping display to prevent tearing.
+ *
+ * Input: display control (PRIMARY_CTRL or SECONDARY_CTRL)
+ */
+void waitVSyncLine(disp_control_t dispControl)
+{
+    unsigned long value;
+    mode_parameter_t modeParam;
+    
+    /* Get the current mode parameter of the specific display control */
+    modeParam = getCurrentModeParam(dispControl);
+    
+    do
+    {
+        if (dispControl == PRIMARY_CTRL)
+            value = FIELD_GET(peekRegisterDWord(PRIMARY_CURRENT_LINE), PRIMARY_CURRENT_LINE, LINE);
+        else
+            value = FIELD_GET(peekRegisterDWord(SECONDARY_CURRENT_LINE), SECONDARY_CURRENT_LINE, LINE);
+    }
+    while (value < modeParam.vertical_sync_start);
+}
+
+
+void swPanelPowerSequence_SM750LE(disp_state_t dispState, unsigned long vsync_delay)
+{
+    unsigned long ulDispControl, ulMask;
+
+    ulDispControl = peekRegisterDWord(DISPLAY_CONTROL_750LE);
+
+    if (dispState == DISP_ON)
+    {
+        ulMask = FIELD_SET(0, DISPLAY_CONTROL_750LE, EN,   HIGH) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, BIAS, HIGH) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, DATA, ENABLE) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, VDD,  HIGH);
+        
+        pokeRegisterDWord(DISPLAY_CONTROL_750LE, (ulDispControl | ulMask));
+    }
+    else
+    {
+        ulMask = FIELD_SET(0, DISPLAY_CONTROL_750LE, EN,   LOW) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, BIAS, LOW) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, DATA, DISABLE) |
+                 FIELD_SET(0, DISPLAY_CONTROL_750LE, VDD,  LOW);
+        
+        pokeRegisterDWord(DISPLAY_CONTROL_750LE, (ulDispControl & ulMask));
+    }
+}
+
+/*
+ * This functions uses software sequence to turn on/off the panel.
+ */
+void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay)
+{
+    unsigned long primaryControl = peekRegisterDWord(PRIMARY_DISPLAY_CTRL);
+
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "swPanelPowerSequence +\n"));
+
+    if (dispState == DISP_ON)
+    {
+        /* Turn on FPVDDEN. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPVDDEN, HIGH);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn on FPDATA. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, DATA, ENABLE);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn on FPVBIAS. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, VBIASEN, HIGH);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn on FPEN. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPEN, HIGH);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+    }
+
+    else
+    {
+        /* Turn off FPEN. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPEN, LOW);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn off FPVBIASEN. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, VBIASEN, LOW);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn off FPDATA. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, DATA, DISABLE);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+        primaryWaitVerticalSync(vsync_delay);
+
+        /* Turn off FPVDDEN. */
+        primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPVDDEN, LOW);
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl);
+    }
+    
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "swPanelPowerSequence -\n"));
+}
+
+/* 
+ * This function turns on/off the DAC for CRT display control.
+ * Input: On or off
+ */
+void setDAC(disp_state_t state)
+{
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "setDAC: %s\n", (state == DISP_ON) ? "on" : "off"));
+
+    if (state == DISP_ON)
+    {
+        pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL),
+                                               MISC_CTRL,
+                                               DAC_POWER,
+                                               ON));
+    }
+    else
+    {
+        pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL),
+                                               MISC_CTRL,
+                                               DAC_POWER,
+                                               OFF));
+    }
+}
+
+/*
+ * This function turns on/off the display control.
+ * Currently, it for CRT and Panel controls only.
+ * Input: Panel or CRT, or ...
+ *        On or Off.
+ *
+ * This function manipulate the physical display channels 
+ * and devices.
+ *
+ * Note:
+ *      Turning on/off the timing and the plane requires programming sequence.
+ *      The plane can not be changed without turning on the timing. However,
+ *      changing the plane has no effect when the timing (clock) is off. Below,
+ *      is the description of the timing and plane combination setting.
+ *
+ *      +-----------+-----------+-----------------------------------------------+
+ *      |  Timing   |   Plane   |                    Description                |
+ *      +-----------+-----------+-----------------------------------------------+
+ *      |    ON     |    OFF    | no Display but clock is on (consume power)    |
+ *      |    ON     |    ON     | normal display                                |
+ *      |    OFF    |    OFF    | no display and no clock (power down)          |
+ *      |    OFF    |    ON     | no display and no clock (same as power down)  |
+ *      +-----------+-----------+-----------------------------------------------+
+ */
+void setDisplayControl(disp_control_t dispControl, disp_state_t dispState)
+{
+    unsigned long ulDisplayCtrlReg, ulReservedBits;
+
+    /* Set the primary display control */
+    if (dispControl == PRIMARY_CTRL)
+    {
+        ulDisplayCtrlReg = peekRegisterDWord(PRIMARY_DISPLAY_CTRL);
+
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) PRIMARY_DISPLAY_CTRL before set: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL)));
+
+        /* Turn on/off the Panel display control */
+        if (dispState == DISP_ON)
+        {
+            /* Timing should be enabled first before enabling the plane because changing at the
+               same time does not guarantee that the plane will also enabled or disabled. 
+             */
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, TIMING, ENABLE);
+            pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+            
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, PLANE, ENABLE);
+            
+            /* Added some masks to mask out the reserved bits. 
+             * Sometimes, the reserved bits are set/reset randomly when 
+             * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
+             * reserved bits are needed to be masked out.
+             */
+            ulReservedBits = FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
+                             FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
+                             FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE);
+                             
+            /* Somehow the register value on the plane is not set until a few delay. Need to write
+               and read it a couple times*/
+            pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+            primaryWaitVerticalSync(2);
+        }
+        else
+        {
+            /* When turning off, there is no rule on the programming sequence since whenever the
+               clock is off, then it does not matter whether the plane is enabled or disabled.
+               Note: Modifying the plane bit will take effect on the next vertical sync. Need to
+                     find out if it is necessary to wait for 1 vsync before modifying the timing
+                     enable bit. 
+             */
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, PLANE, DISABLE);
+            pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, TIMING, DISABLE);
+            pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+        }
+
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) PRIMARY_DISPLAY_CTRL after set: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL)));
+    }
+    /* Set the secondary display control */
+    else if(dispControl == SECONDARY_CTRL)
+    {
+        ulDisplayCtrlReg = peekRegisterDWord(SECONDARY_DISPLAY_CTRL);
+
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) SECONDARY_DISPLAY_CTRL before set: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL)));
+
+        if (dispState == DISP_ON)
+        {
+            /* Timing should be enabled first before enabling the plane because changing at the
+               same time does not guarantee that the plane will also enabled or disabled. 
+             */
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, TIMING, ENABLE);
+            pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+                        
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, PLANE, ENABLE);
+            
+            /* Added some masks to mask out the reserved bits. 
+             * Sometimes, the reserved bits are set/reset randomly when 
+             * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
+             * reserved bits are needed to be masked out.
+             */
+            ulReservedBits = FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
+                             FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
+                             FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) |
+                             FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_4_MASK, ENABLE);
+            
+            
+            pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+            secondaryWaitVerticalSync(2);
+        }
+        else
+        {
+            /* When turning off, there is no rule on the programming sequence since whenever the
+               clock is off, then it does not matter whether the plane is enabled or disabled.
+               Note: Modifying the plane bit will take effect on the next vertical sync. Need to
+                     find out if it is necessary to wait for 1 vsync before modifying the timing
+                     enable bit.
+             */
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, PLANE, DISABLE);
+            pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+
+            ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, TIMING, DISABLE);
+            pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg);
+        }
+
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) SECONDARY_DISPLAY_CTRL after set: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL)));
+    }
+}
+
+/*
+ * This function set the display path together with the HSync and VSync.
+ *
+ * Note:
+ *     This function has to be called last after setting all the display Control
+ *     and display output. 
+ */
+void setPath(
+    disp_path_t dispPath, 
+    disp_control_t dispControl, 
+    disp_state_t dispState
+)
+{
+    unsigned long control;
+    mode_parameter_t modeParam;
+    unsigned long clock0, clock1, MiscControl;    
+
+    /* Get the current mode parameter of the specific display control */
+    modeParam = getCurrentModeParam(dispControl);
+    
+    if (dispPath == PANEL_PATH)
+    {
+        control = peekRegisterDWord(PRIMARY_DISPLAY_CTRL);
+        if (dispState == DISP_ON)
+        {
+            /* Adjust the Clock polarity */
+            if (modeParam.clock_phase_polarity == POS)
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW);
+                        
+            /* Adjust the VSync polarity */
+            if (modeParam.vertical_sync_polarity == POS)
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW);
+
+            /* Adjust the HSync polarity */
+            if (modeParam.horizontal_sync_polarity == POS)
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW);
+
+            /* Display control is not swapped, so use the normal display data flow */
+            if (dispControl == PRIMARY_CTRL)
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, SELECT, PRIMARY);                    
+            else    /* Secondary Control */
+                control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, SELECT, SECONDARY);
+        }
+
+#if Validate_718_AA
+        //if (hwDeviceExtension1[0]->ChipID==0x718 ||
+        //    hwDeviceExtension1[1]->ChipID==0x718)
+        {
+            //patch for sm718aa, when set 80028[28] from 0 to 1, failed some time. needs to set the master
+            //clock to 56mhz.
+            clock0 = peekRegisterDWord(MODE0_GATE);
+            pokeRegisterDWord(MODE0_GATE, FIELD_SET(clock0, MODE0_GATE, MCLK, 42MHZ)); 
+            clock1 = peekRegisterDWord(MODE1_GATE);
+            pokeRegisterDWord(MODE1_GATE, FIELD_SET(clock1, MODE1_GATE, MCLK, 42MHZ));                 
+        }
+#endif
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, control);
+#if Validate_718_AA
+        //if (hwDeviceExtension1[0]->ChipID==0x718 ||
+        //    hwDeviceExtension1[1]->ChipID==0x718)
+        {
+             //patch for sm718aa, restore mclk.
+            pokeRegisterDWord(MODE0_GATE, clock0); 
+            pokeRegisterDWord(MODE1_GATE, clock1); 
+
+            //Reset video memory, otherwise, screen would show garbage.
+            MiscControl= peekRegisterDWord(MISC_CTRL);
+            MiscControl= FIELD_SET(MiscControl, MISC_CTRL, LOCALMEM_RESET, RESET);
+            pokeRegisterDWord(MISC_CTRL, MiscControl);
+            MiscControl= FIELD_SET(MiscControl, MISC_CTRL, LOCALMEM_RESET, NORMAL);
+            pokeRegisterDWord(MISC_CTRL, MiscControl);            
+        }
+#endif
+
+       // DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPath) PRIMARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL)));
+    }
+    else if(dispPath == CRT_PATH)   /* CRT Path */
+    {
+        control = peekRegisterDWord(SECONDARY_DISPLAY_CTRL);
+    
+        if (dispState == DISP_ON)
+        {
+            /* Adjust the Clock polarity */
+            if (modeParam.clock_phase_polarity == POS)
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW);
+                
+            /* Adjust the VSync polarity */
+            if (modeParam.vertical_sync_polarity == POS)
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW);
+    
+            /* Adjust the HSync polarity */
+            if (modeParam.horizontal_sync_polarity == POS)
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH);
+            else
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW);
+
+            /* Display control is not swapped, so use the normal display data flow */
+            if (dispControl == PRIMARY_CTRL)
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, SELECT, PRIMARY);
+            else
+                control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, SELECT, SECONDARY);
+            
+            /* Enable the CRT Pixel */
+            control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, BLANK, OFF);
+        }
+        else
+        {
+            /* Disable the CRT Pixel */
+            control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, BLANK, ON);
+        }    
+
+        pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, control);
+
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPath) SECONDARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL)));
+    }
+}
+
+/*
+ * This function gets the CRT2 Monitor Detection Threshold value.
+ *
+ * Input:
+ *      pRedValue   - Pointer to a variable to store the Red color threshold
+ *                    value.
+ *      pGreenValue - Pointer to a variable to store the Green color threshold
+ *                    value.
+ *      pBlueValue  - Pointer to a variable to store the Blue color threshold
+ *                    value. 
+ */
+void getCRTDetectThreshold(
+    unsigned char *pRedValue,
+    unsigned char *pGreenValue,
+    unsigned char *pBlueValue
+)
+{
+    unsigned long value;
+    
+    value = peekRegisterDWord(SECONDARY_MONITOR_DETECT);
+
+    if (pRedValue != (unsigned char *)0)
+        *pRedValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, RED);
+        
+    if (pGreenValue != (unsigned char *)0)
+        *pGreenValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, GREEN);
+        
+    if (pBlueValue != (unsigned char *)0)
+        *pBlueValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, BLUE);
+}
+
+/*
+ * This function detects if the CRT monitor is attached.
+ *
+ * Input:
+ *      redValue    - Threshold value to be detected on the red color.
+ *      greenValue  - Threshold value to be detected on the green color.
+ *      blueValue   - Threshold value to be detected on the blue color.
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long ddk750_detectCRTMonitor(
+    unsigned char redValue,
+    unsigned char greenValue,
+    unsigned char blueValue
+)
+{
+    unsigned long value, red, green, blue;
+    long result = (-1);
+    
+    /* Use the given red, green, and blue threshold value to detect the monitor or
+       default. */
+    if (redValue != 0)
+        red = redValue;
+    else
+        red = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    if (greenValue != 0)
+        green = greenValue;
+    else
+        green = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    if (blueValue != 0)
+        blue = blueValue;
+    else
+        blue = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    /* Set the RGB Threshold value and enable the monitor detection. */
+    value = ((unsigned long)red << 16) |
+            ((unsigned long)green << 8) |
+            ((unsigned long)blue);
+    value = FIELD_SET(value, SECONDARY_MONITOR_DETECT, ENABLE, ENABLE);
+    pokeRegisterDWord(SECONDARY_MONITOR_DETECT, value);
+    
+    /* Add some delay here. Otherwise, the detection is not stable. */
+    value = 0xFFFF;
+    while (value--);
+    
+    /* Check if the monitor is detected. */
+    if (FIELD_GET(peekRegisterDWord(SECONDARY_MONITOR_DETECT), SECONDARY_MONITOR_DETECT, VALUE) ==
+        SECONDARY_MONITOR_DETECT_VALUE_ENABLE)
+    {
+        result = 0;
+    }
+    
+    /* Disable the Monitor Detect Enable bit. Somehow, enabling this bit will 
+       cause the CRT to lose display. */
+    value = peekRegisterDWord(SECONDARY_MONITOR_DETECT);
+    value = FIELD_SET(value, SECONDARY_MONITOR_DETECT, ENABLE, DISABLE);
+    pokeRegisterDWord(SECONDARY_MONITOR_DETECT, value);
+
+    return result;
+}
+
+/*
+ * This function set the logical display output.
+ *
+ * The output is called logical because it is independent of physical implementation.
+ * For example, CRT2 only mode is not using the internal secondary control. It uses the
+ * Primary Control with its output directed to CRT DAC.
+ *
+ * Input:
+ *      output          - Logical Display output
+ *      dispCtrlUsage   - Display Control Flag Usage:
+ *                          0 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              primary output (LCD1 & CRT1) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control secondary output 
+ *                              (CRT2 & LCD2)
+ *                          1 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              secondary output (LCD2 & CRT2) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control primary output 
+ *                              (LCD1 & CRT1)
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long setLogicalDispOutput(
+
+    disp_output_t output,
+    unsigned char dispCtrlUsage
+)
+{
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "setLogicalDispOutput\n"));
+
+    switch (output)
+    {
+        case NO_DISPLAY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "NO_DISPLAY\n"));
+        
+            /* In here, all the display device has to be turned off first before the
+               the display control. */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel */
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+    
+            setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Panel control */
+            setDisplayControl(SECONDARY_CTRL, DISP_OFF);        /* Turn off CRT control */
+
+            setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn off Panel path */
+            setPath(CRT_PATH, PRIMARY_CTRL, DISP_OFF);          /* Turn off CRT path */
+            break;
+        }    
+        case LCD1_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_ONLY\n"));
+
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                /* Turn on Primary control */
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on CRT control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off CRT control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use panel data */
+                }
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_OFF);          /* Turn off CRT Path */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_OFF);        /* Turn off CRT Path */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }    
+        case LCD2_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD2_ONLY\n"));
+
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable LCD22 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary control */                
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use primary data */
+                }
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn off Panel Path */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary control */                
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn off CRT Path and use secondary data */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel 1 */
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }
+        case CRT2_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_ONLY\n"));
+
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_OFF);        /* Turn off Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);           /* Turn off CRT Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn off CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+        case LCD1_CRT2_SIMUL: /* Panel and CRT same content */
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_SIMUL\n"));
+            
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                } 
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);           /* Turn on CRT Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {    
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }    
+        case CRT2_LCD2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_LCD2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn on Panel Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn on Panel Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_CRT2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {            
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+        case LCD1_CRT2_DUAL: /* Panel and CRT different content */
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */
+            /* This combination is not valid if panel 1 requires scaling and display
+               control is not swapped. */
+          //  if (isScalingEnabled(PRIMARY_CTRL) == 1)
+          //      return (-1);
+
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+
+
+            if (dispCtrlUsage == 0)
+            {
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+
+
+            }
+            else
+            {
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+
+
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_DUAL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */    
+            /* This combination is not valid if panel requires scaling and display
+               control is not swapped. */
+           // if (isScalingEnabled(PRIMARY_CTRL) == 1)
+           //     return (-1);
+                
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+            if (dispCtrlUsage == 0)
+            {
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+            }
+            else
+            {
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS to drive CRT */
+            break;
+        }
+        case LCD1_LCD2_CRT2_DUAL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */    
+            /* This combination is not valid if panel requires scaling and display
+               control is not swapped. */
+            //if (isScalingEnabled(PRIMARY_CTRL) == 1)
+              //  return (-1);
+                
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */            
+            if (dispCtrlUsage == 0)
+            {
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+            }
+            else
+            {
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+    }
+    
+    return 0;
+}
+
+/*
+ * This function set the logical display output.
+ *
+ * The output is called logical because it is independent of physical implementation.
+ * For example, CRT2 only mode is not using the internal secondary control. It uses the
+ * Primary Control with its output directed to CRT DAC.
+ *
+ * Input:
+ *		isSnd	   		- is or not the second view
+ *      output          - Logical Display output
+ *      dispCtrlUsage   - Display Control Flag Usage:
+ *                          0 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              primary output (LCD1 & CRT1) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control secondary output 
+ *                              (CRT2 & LCD2)
+ *                          1 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              secondary output (LCD2 & CRT2) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control primary output 
+ *                              (LCD1 & CRT1)
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long setLogicalDispOutputExt(
+    long isSecondDisplay, 
+    disp_output_t output,
+    unsigned char dispCtrlUsage
+)
+{
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "setLogicalDispOutputExt\n"));
+
+    switch (output)
+    {
+        case NO_DISPLAY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "NO_DISPLAY\n"));
+        
+            /* In here, all the display device has to be turned off first before the
+               the display control. */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel */
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+    
+            setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Panel control */
+            setDisplayControl(SECONDARY_CTRL, DISP_OFF);        /* Turn off CRT control */
+
+            setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn off Panel path */
+            setPath(CRT_PATH, PRIMARY_CTRL, DISP_OFF);          /* Turn off CRT path */
+            break;
+        }    
+        case LCD1_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_ONLY\n"));
+
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                /* Turn on Primary control */
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on CRT control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off CRT control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use panel data */
+                }
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_OFF);          /* Turn off CRT Path */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_OFF);        /* Turn off CRT Path */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }    
+        case LCD2_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD2_ONLY\n"));
+
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable LCD22 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary control */                
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use primary data */
+                }
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn off Panel Path */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary control */                
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn off CRT Path and use secondary data */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel 1 */
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }
+        case CRT2_ONLY:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_ONLY\n"));
+
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_OFF);        /* Turn off Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);           /* Turn off CRT Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn off Panel Path */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn off CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_OFF, 4);                  /* Turn off Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+        case LCD1_CRT2_SIMUL: /* Panel and CRT same content */
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_SIMUL\n"));
+            
+            /* 
+             * 1. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                }            
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);           /* Turn on CRT Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 2. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {    
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS */
+            break;
+        }    
+        case CRT2_LCD2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_LCD2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions 
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_OFF);        /* Turn on Panel Path and use Primary data */
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_OFF);      /* Turn on Panel Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_CRT2_SIMUL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_SIMUL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if (dispCtrlUsage == 0)
+            {            
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+                if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_ON);     /* Turn on Secondary control */
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+                }
+                else
+                {
+                    setDisplayControl(SECONDARY_CTRL, DISP_OFF);    /* Turn off Secondary control */
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+                }
+            }
+            else
+            {
+                setDisplayControl(PRIMARY_CTRL, DISP_OFF);          /* Turn off Primary Control */
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);       /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);         /* Turn on CRT Path and use Secondary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+        case LCD1_CRT2_DUAL: /* Panel and CRT different content */
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */
+            /* This combination is not valid if panel 1 requires scaling and display
+               control is not swapped. */
+            if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                return (-1);
+
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            if(!isSecondDisplay) 
+                setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            else
+                setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+            if (dispCtrlUsage == 0)
+            {
+                if(!isSecondDisplay) 
+                    setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                else
+                    setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+            }
+            else
+            {
+                if(isSecondDisplay)             
+                    setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                else
+                    setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+            }
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }    
+        case LCD1_LCD2_DUAL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */    
+            /* This combination is not valid if panel requires scaling and display
+               control is not swapped. */
+            if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                return (-1);
+                
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */
+            if (dispCtrlUsage == 0)
+            {
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+            }
+            else
+            {
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+#ifdef ENABLE_PANEL_DAC
+            /* When using Analog CRT connected to the DVI channel, the DAC needs
+               to be turned on. The power is using the same power as CRT DAC. */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+#else
+            setDAC(DISP_OFF);                                   /* Turn off DAC */
+#endif
+            setDPMS(DPMS_OFF);                                  /* Turn off DPMS to drive CRT */
+            break;
+        }
+        case LCD1_LCD2_CRT2_DUAL:
+        {
+            //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_DUAL\n"));
+            
+            /* 
+             * 1. Check the conditions
+             */    
+            /* This combination is not valid if panel requires scaling and display
+               control is not swapped. */
+            if (isScalingEnabled(PRIMARY_CTRL) == 1)
+                return (-1);
+                
+            /* Can not enable PANEL2 when the panel type is not 18-bit panel. */            
+            if (getPanelType() != TFT_18BIT)
+                return (-1);
+            
+            /* 
+             * 2. Set all the display control and the display path 
+             */
+            setDisplayControl(PRIMARY_CTRL, DISP_ON);           /* Turn on Primary Control */
+            setDisplayControl(SECONDARY_CTRL, DISP_ON);         /* Turn on Secondary control */            
+            if (dispCtrlUsage == 0)
+            {
+                setPath(PANEL_PATH, PRIMARY_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+                setPath(CRT_PATH, SECONDARY_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+            }
+            else
+            {
+                setPath(PANEL_PATH, SECONDARY_CTRL, DISP_ON);   /* Turn on Panel Path and use Secondary data */
+                setPath(CRT_PATH, PRIMARY_CTRL, DISP_ON);       /* Turn on CRT Path and use Primary data */
+            }
+            
+            /* 
+             * 3. Enable/disable the display devices. 
+             */
+            swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+            setDAC(DISP_ON);                                    /* Turn on DAC */
+            setDPMS(DPMS_ON);                                   /* Turn on DPMS to drive CRT */
+            break;
+        }
+    }
+    
+    return 0;
+}
+
+/*
+ * This function checks whether the scaling is enabled.
+ *
+ * Input:
+ *      dispCtrl    - Display control to be checked.
+ *
+ * Output:
+ *      0   - Scaling is not enabled
+ *      1   - Scaling is enabled
+ */
+unsigned char isScalingEnabled(
+    disp_control_t dispCtrl
+)
+{
+    unsigned long value;
+    
+    /* If display control is not swapped, then check the expansion bit for PRIMARY_CTRL 
+       and SECONDARY_SCALE register for SECONDARY_CTRL. */
+    if (dispCtrl == PRIMARY_CTRL)
+    {
+        value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL);
+        if (FIELD_GET(value, SECONDARY_DISPLAY_CTRL, EXPANSION) == SECONDARY_DISPLAY_CTRL_EXPANSION_ENABLE)
+            return 1;
+    }
+    else
+    {
+        value = peekRegisterDWord(SECONDARY_SCALE);
+        if ((FIELD_GET(value, SECONDARY_SCALE, VERTICAL_SCALE) != 0) ||
+            (FIELD_GET(value, SECONDARY_SCALE, HORIZONTAL_SCALE) != 0))
+            return 1;
+    }
+    
+    return 0;
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_display.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_display.h
new file mode 100644
index 000000000000..d06d3ec43293
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_display.h
@@ -0,0 +1,226 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  display.h --- SM750/SM718 DDK
+*  This file contains the function prototypes for the display.
+* 
+*******************************************************************/
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_
+
+#include "ddk750_mode.h"
+
+typedef enum _disp_path_t
+{
+    PANEL_PATH = 0,
+    CRT_PATH   = 1,
+}
+disp_path_t;
+
+typedef enum _disp_state_t
+{
+    DISP_OFF = 0,
+    DISP_ON  = 1,
+}
+disp_state_t;
+
+typedef enum _disp_output_t
+{
+    NO_DISPLAY,             /* All display off. */
+    LCD1_ONLY,              /* LCD1 only */
+    LCD2_ONLY,              /* LCD2 only */
+    CRT2_ONLY,              /* CRT2 only */
+    LCD1_CRT2_SIMUL,        /* Both LCD1 and CRT2 displaying the same content. */
+    LCD1_LCD2_SIMUL,        /* Both LCD1 and LCD2 displaying the same content. */
+    CRT2_LCD2_SIMUL,        /* CRT2 and LCD2 displaying the same content. */
+    LCD1_LCD2_CRT2_SIMUL,   /* LCD1, LCD2, and CRT2 displaying the same content. */
+    LCD1_CRT2_DUAL,         /* LCD1 and CRT2 displaying different contents. */
+    LCD1_LCD2_DUAL,         /* LCD1 and LCD2 displaying different contents. */
+    LCD1_LCD2_CRT2_DUAL     /* LCD2 and CRT2 displaying the same content while
+                               the Panel displaying different content. */
+}
+disp_output_t;
+
+typedef enum _panel_type_t
+{
+    TFT_18BIT = 0,
+    TFT_24BIT,
+    TFT_36BIT
+}
+panel_type_t;
+
+void setPath(
+    disp_path_t dispPath, 
+    disp_control_t dispControl, 
+    disp_state_t dispState
+);
+/*
+ * This functions sets the CRT Path.
+ */
+void setCRTPath(disp_control_t dispControl);
+
+/*
+ * This functions uses software sequence to turn on/off the panel.
+ */
+void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay);
+
+/* 
+ * This function turns on/off the DAC for CRT display control.
+ * Input: On or off
+ */
+void setDAC(disp_state_t state);
+
+/*
+ * This function turns on/off the display control.
+ * Currently, it for CRT and Panel controls only.
+ * Input: Panel or CRT, or ...
+ *        On or Off.
+ */
+void setDisplayControl(disp_control_t dispControl, disp_state_t dispState);
+
+/*
+ * This function set the logical display output.
+ *
+ * The output is called logical because it is independent of physical implementation.
+ * For example, CRT2 only mode is not using the internal secondary control. It uses the
+ * Primary Control with its output directed to CRT DAC.
+ *
+ * Input:
+ *      output          - Logical Display output
+ *      dispCtrlUsage   - Display Control Flag Usage:
+ *                          0 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              primary output (LCD1 & CRT1) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control secondary output 
+ *                              (CRT2 & LCD2)
+ *                          1 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              secondary output (LCD2 & CRT2) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control primary output 
+ *                              (LCD1 & CRT1)
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long setLogicalDispOutput(
+    disp_output_t output,
+    unsigned char dispCtrlUsage
+);
+
+/*
+ * This function set the logical display output.
+ *
+ * The output is called logical because it is independent of physical implementation.
+ * For example, CRT2 only mode is not using the internal secondary control. It uses the
+ * Primary Control with its output directed to CRT DAC.
+ *
+ * Input:
+ *		isSecondDispay  - Enable primary or secondary control
+ *							0 : Enable primary display control
+ *							1 : Enable secondary display control
+ *      output          - Logical Display output
+ *      dispCtrlUsage   - Display Control Flag Usage:
+ *                          0 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              primary output (LCD1 & CRT1) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control secondary output 
+ *                              (CRT2 & LCD2)
+ *                          1 : Use primary display control (PRIMARY_CTRL) to control 
+ *                              secondary output (LCD2 & CRT2) and use secondary display 
+ *                              control (SECONDARY_CTRL) to control primary output 
+ *                              (LCD1 & CRT1)
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long setLogicalDispOutputExt(
+    long isSecondDisplay,
+    disp_output_t output,
+    unsigned char dispCtrlUsage
+);
+/*
+ * Use vertical sync as time delay function.
+ * Input:
+ *          dispControl - Display Control (PRIMARY_CTRL or SECONDARY_CTRL) 
+ *          vsync_count - Number of vertical sync to wait.
+ *
+ * Note:
+ *      This function is waiting for the next vertical sync.
+ */
+void waitNextVerticalSync(disp_control_t dispControl, unsigned long vsync_count);
+
+/*
+ * Use panel vertical sync line as time delay function.
+ * This function does not wait for the next VSync. Instead, it will wait
+ * until the current line reaches the Vertical Sync line.
+ * This function is really useful when flipping display to prevent tearing.
+ *
+ * Input: display control (PRIMARY_CTRL or SECONDARY_CTRL)
+ */
+void waitVSyncLine(disp_control_t dispControl);
+
+/*
+ * This function gets the panel type
+ *
+ * Output:
+ *      panelType   - The type of the panel to be set  
+ */
+panel_type_t getPanelType(void);
+
+long setPanelType(panel_type_t panelType);
+
+
+/*
+ * This function gets the CRT Monitor Detection Threshold value.
+ *
+ * Input:
+ *      pRedValue   - Pointer to a variable to store the Red color threshold
+ *                    value.
+ *      pGreenValue - Pointer to a variable to store the Green color threshold
+ *                    value.
+ *      pBlueValue  - Pointer to a variable to store the Blue color threshold
+ *                    value. 
+ */
+void getCRTDetectThreshold(
+    unsigned char *pRedValue,
+    unsigned char *pGreenValue,
+    unsigned char *pBlueValue
+);
+
+/*
+ * This function detects if the CRT monitor is attached.
+ *
+ * Input:
+ *      redValue    - Threshold value to be detected on the red color.
+ *      greenValue  - Threshold value to be detected on the green color.
+ *      blueValue   - Threshold value to be detected on the blue color.
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long ddk750_detectCRTMonitor(
+    unsigned char redValue,
+    unsigned char greenValue,
+    unsigned char blueValue
+);
+
+/*
+ * This function checks whether the scaling is enabled.
+ *
+ * Input:
+ *      dispCtrl    - Display control to be checked.
+ *
+ * Output:
+ *      0   - Scaling is not enabled
+ *      1   - Scaling is enabled
+ */
+unsigned char isScalingEnabled(
+    disp_control_t dispCtrl
+);
+
+
+#endif /* _DISPLAY_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.c
new file mode 100644
index 000000000000..f4d6a9c19f70
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.c
@@ -0,0 +1,2238 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  edid.c --- SM750/SM718 DDK 
+*  This file contains functions to interpret the EDID structure.
+* 
+*******************************************************************/
+//#include <linux/math.h>
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_helper.h"
+#include "ddk750_hwi2c.h"
+#include "ddk750_swi2c.h"
+#include "ddk750_edid.h"
+
+#include "ddkdebug.h"
+#include <linux/string.h>
+
+/* Enable this one to print the VDIF timing when debug is enabled. */
+//#define ENABLE_DEBUG_PRINT_VDIF
+
+/****************************************************************
+ * Configuration setting
+ ****************************************************************/
+/* I2C Address of each Monitor. Currently, there is only one i2c bus and
+   both display devices will responds to 0xA0 address with analog CRT as the first priority
+   The second version of evaluation board will separate the i2c bus, so that each i2c bus
+   corresponds to one display devices.
+   The new monitor devices (at least the tested DVI monitor) also corresponds to 0xA2, 
+   which is temporarily used in this DDK. */
+#define EDID_DEVICE_I2C_ADDRESS             0xA0
+
+/* GPIO used for the I2C on the PANEL_PATH size  */
+#define EDID_PANEL_I2C_SCL                  DEFAULT_I2C_SCL
+#define EDID_PANEL_I2C_SDA                  DEFAULT_I2C_SDA
+
+/* GPIO used for the I2C on the CRT_PATH size.
+   These GPIO pins only available in the Evaluation Board version 2.2.
+   Need to find out which pins are used for the CRT_PATH i2c. */
+#define EDID_CRT_I2C_SCL                    17
+#define EDID_CRT_I2C_SDA                    18
+
+#define TOTAL_EDID_REGISTERS                128
+
+#define TOTAL_EDID_REGISTERS_128                128
+#define TOTAL_EDID_REGISTERS_256                256
+#define EDID_EXTEND_BLOCK         126
+
+
+typedef struct _est_timing_mode_t
+{
+    unsigned long x;        /* Mode Width */
+    unsigned long y;        /* Mode Height */
+    unsigned long hz;       /* Refresh Rate */
+    unsigned char source;   /* Source:  0 - VESA
+                                        1 - IBM
+                                        2 - Apple
+                             */
+}
+est_timing_mode_t;
+
+/* These values only applies to EDID Version 1 */
+static est_timing_mode_t establishTiming[3][8] =
+{
+    /* Established Timing 1 */
+    {   
+        { 800,  600, 60, 0},
+        { 800,  600, 56, 0},
+        { 640,  480, 75, 0},
+        { 640,  480, 72, 0},
+        { 640,  480, 67, 2},
+        { 640,  480, 60, 1},
+        { 720,  400, 88, 1},
+        { 720,  400, 70, 1},
+    },
+    {
+        {1280, 1024, 75, 0},
+        {1024,  768, 75, 0},
+        {1024,  768, 70, 0},
+        {1024,  768, 60, 0},
+        {1024,  768, 87, 1},
+        { 832,  624, 75, 0},
+        { 800,  600, 75, 0},
+        { 800,  600, 72, 0},
+    },
+    {
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {1152,  870, 75, 2},
+    }
+};
+
+static void printVdif(
+    vdif_t *pVDIF
+)
+{
+#ifdef DDKDEBUG
+
+#ifndef ENABLE_DEBUG_PRINT_VDIF
+    DDKDEBUGENABLE(0);
+#endif
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "pixelClock = %d\n", pVDIF->pixelClock));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "characterWidth = %d\n", pVDIF->characterWidth));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "scanType = %s\n", (pVDIF->scanType == VDIF_INTERLACED) ? "Interlaced" : "Progressive"));
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrequency = %d\n", pVDIF->horizontalFrequency));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalTotal = %d\n", pVDIF->horizontalTotal));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalActive = %d\n", pVDIF->horizontalActive));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankStart = %d\n", pVDIF->horizontalBlankStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankTime = %d\n", pVDIF->horizontalBlankTime));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncStart = %d\n", pVDIF->horizontalSyncStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalRightBorder = %d\n", pVDIF->horizontalRightBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrontPorch = %d\n", pVDIF->horizontalFrontPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncWidth = %d\n", pVDIF->horizontalSyncWidth));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBackPorch = %d\n", pVDIF->horizontalBackPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalLeftBorder = %d\n", pVDIF->horizontalLeftBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncPolarity = %s\n", 
+        (pVDIF->horizontalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive"));
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrequency = %d\n", pVDIF->verticalFrequency));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTotal = %d\n", pVDIF->verticalTotal));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalActive = %d\n", pVDIF->verticalActive));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankStart = %d\n", pVDIF->verticalBlankStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankTime = %d\n", pVDIF->verticalBlankTime));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncStart = %d\n", pVDIF->verticalSyncStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBottomBorder = %d\n", pVDIF->verticalBottomBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrontPorch = %d\n", pVDIF->verticalFrontPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncHeight = %d\n", pVDIF->verticalSyncHeight));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBackPorch = %d\n", pVDIF->verticalBackPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTopBorder = %d\n", pVDIF->verticalTopBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncPolarity = %s\n", 
+        (pVDIF->verticalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive"));
+
+#ifndef ENABLE_DEBUG_PRINT_VDIF
+    DDKDEBUGENABLE(1);
+#endif
+#endif
+}
+
+/*
+ *  edidGetVersion
+ *      This function gets the EDID version
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRevision   - Revision of the EDIE (if exist)
+ *
+ *  Output:
+ *      Revision number of the given EDID buffer.
+ */
+unsigned char edidGetVersion(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pRevision
+)
+{
+    unsigned char version;
+    
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Check the header */
+        if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) &&
+            (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) &&
+            (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00))
+        {
+            /* 
+             * EDID Structure Version 1.
+             */
+        
+            /* Read the version field from the buffer. It should be 1 */
+            version  = pEDIDBuffer[18];
+        
+            if (version == 1)
+            {
+                /* Copy the revision first */
+                if (pRevision != (unsigned char *)0)
+                    *pRevision = pEDIDBuffer[19];
+                    
+                return version;
+            }
+        }
+        else
+        {
+            /* 
+             * EDID Structure Version 2 
+             */
+             
+            /* Read the version and revision field from the buffer. */
+            version = pEDIDBuffer[0];
+        
+            if ((version >> 4) == 2)
+            {
+                /* Copy the revision */
+                if (pRevision != (unsigned char *)0)
+                    *pRevision = version & 0x0F;
+                
+                return (version >> 4);
+            }
+        }
+    }
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID Structure\n"));    
+    return 0;    
+}
+
+/*
+ *  edidGetProductInfo
+ *      This function gets the vendor and product information.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor [in]
+ *      pManufacturerName   - Pointer to a 3 byte length variable to store the manufacturer name [out]
+ *      pProductCode        - Pointer to a variable to store the product code [out]
+ *      pSerialNumber       - Pointer to a variable to store the serial number [out]
+ *      pWeekOfManufacture  - Pointer to a variable to store the week of manufacture [out]
+ *      pYearOfManufacture  - Pointer to a variable to store the year of manufacture 
+ *                            or model year (if WeekOfManufacture is 0xff) [out]
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetProductInfo(
+    unsigned char *pEDIDBuffer,
+    char *pManufacturerName,
+    unsigned short *pProductCode,
+    unsigned long *pSerialNumber,
+    unsigned char *pWeekOfManufacture,
+    unsigned short *pYearOfManufacture
+)
+{
+    unsigned char version, revision;
+    unsigned short manufactureID;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pManufacturerName != (char *)0)
+        {
+            /* Swap the byte */
+            manufactureID = (pEDIDStructure->manufacturerID >> 8) + (pEDIDStructure->manufacturerID << 8);
+            pManufacturerName[0] = ((manufactureID >> 10) & 0x001F) + 'A' - 1;
+            pManufacturerName[1] = ((manufactureID >> 5) & 0x001F) + 'A' - 1;
+            pManufacturerName[2] = (manufactureID & 0x001F) + 'A' - 1;
+            pManufacturerName[3] = '\0';
+        }
+        
+        if (pProductCode != (unsigned short *)0)
+            *pProductCode = pEDIDStructure->productCode;
+            
+        /* Only EDID structure version 1.1 and 1.2 supports this. EDID 1.3 uses
+           detail timing descriptor to store the serial number in ASCII. */
+        if (pSerialNumber != (unsigned long *)0)
+            *pSerialNumber = pEDIDStructure->serialNumber;
+        
+        /*
+         * Rev 1.3: - A value of 0 means that week of manufacture is not specified
+         *          - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture
+         *          - Any values greater than 54 is invalid.
+         *
+         * Rev 1.4: - A value of 0 means that week of manufacture is not specified
+         *          - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture
+         *          - A value of 0xFF means that Year of Manufacture contains the model year
+         *            instead of year of Manufacture.
+         *          - Other values means invalid
+         */
+        if (pWeekOfManufacture != (unsigned char *)0)
+            *pWeekOfManufacture = pEDIDStructure->weekOfManufacture;
+            
+        /* The value must be greater than 3 and less than or equal to the current
+           year minus 1990.
+           A value of 3 or less would indicated that the display was manufactured 
+           before the EDID standard was defined.
+           A value greater than (current year - 1990) would indicate that the display
+           has not yet been manufactured.
+         */
+        if (pYearOfManufacture != (unsigned short *)0)
+            *pYearOfManufacture = (unsigned short) pEDIDStructure->yearOfManufacture + 1990;
+        
+        return 0;
+    }
+
+    return (-1);
+}
+
+/*
+ *  edidCheckMonitorInputSignal
+ *      This function checks whether the monitor is expected analog/digital 
+ *      input signal.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Analog
+ *      1   - Digital
+ */
+unsigned char edidCheckMonitorInputSignal(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->videoInputDefinition.analogSignal.inputSignal;
+    
+    return 0;
+}
+
+/*
+ *  edidGetAnalogSignalInfo
+ *      This function gets the analog video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pRefWhiteAboveBlank     - Pointer to a variable to store the reference white above blank
+ *                                value. The value is in milliVolt.
+ *      pSyncLevelBelowBlank    - Pointer to a variable to store the Sync tip level below blank
+ *                                The value is also in milliVolt
+ *      pBlank2BlackSetup       - Pointer to a variable to store the Blank to black setup or
+ *                                pedestal per appropriate Signal Level Standard flag. 
+ *                                1 means that the display expect the setup.
+ *      pSeparateSyncSupport    - Pointer to a variable to store the flag to indicate that the
+ *                                monitor supports separate sync.
+ *      pCompositeSyncSupport   - Pointer to a variable to store a flag to indicate that the
+ *                                monitor supports composite sync.
+ *      pSyncOnGreenSupport     - Pointer to a variable to store a flag to indicate that
+ *                                the monitor supports sync on green video.
+ *      pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration
+ *                                of the VSync pulse is required when composite sync or
+ *                                sync-on-green video is used.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetAnalogSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRefWhiteAboveBlank,
+    unsigned short *pSyncLevelBelowBlank,
+    unsigned char *pBlank2BlackSetup,
+    unsigned char *pSeparateSyncSupport,
+    unsigned char *pCompositeSyncSupport,
+    unsigned char *pSyncOnGreenSupport,
+    unsigned char *pVSyncSerrationRequired
+)
+{
+    unsigned char version, revision;
+    unsigned short whiteReference, syncLevel;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Check if the input signal is analog */
+        if (pEDIDStructure->videoInputDefinition.analogSignal.inputSignal != 0)
+            return (-1);
+        
+        switch (pEDIDStructure->videoInputDefinition.analogSignal.signalLevelStd)
+        {
+            case 0:
+                whiteReference = 700;
+                syncLevel = 300;
+                break;
+            case 1:
+                whiteReference = 714;
+                syncLevel = 286;
+                break;
+            case 2:
+                whiteReference = 1000;
+                syncLevel = 400;
+                break;
+            case 3:
+                whiteReference = 700;
+                syncLevel = 0;
+                break;
+        }
+        
+        if (pRefWhiteAboveBlank != (unsigned short *)0)
+            *pRefWhiteAboveBlank = whiteReference; 
+        
+        if (pSyncLevelBelowBlank != (unsigned short *)0)
+            *pSyncLevelBelowBlank = syncLevel;
+        
+        if (pBlank2BlackSetup != (unsigned char *)0)
+            *pBlank2BlackSetup = (unsigned char)
+                                  pEDIDStructure->videoInputDefinition.analogSignal.blank2Black;
+        
+        if (pSeparateSyncSupport != (unsigned char *)0)
+            *pSeparateSyncSupport = (unsigned char)
+                                     pEDIDStructure->videoInputDefinition.analogSignal.separateSyncSupport;
+        
+        if (pCompositeSyncSupport != (unsigned char *)0)
+            *pCompositeSyncSupport = (unsigned char)
+                                      pEDIDStructure->videoInputDefinition.analogSignal.compositeSyncSupport;
+        
+        if (pSyncOnGreenSupport != (unsigned char *)0)
+            *pSyncOnGreenSupport = (unsigned char)
+                                    pEDIDStructure->videoInputDefinition.analogSignal.syncOnGreenSupport;
+        
+        if (pVSyncSerrationRequired != (unsigned char *)0)
+            *pVSyncSerrationRequired = (unsigned char)
+                                        pEDIDStructure->videoInputDefinition.analogSignal.vsyncSerration;
+                                        
+        return 0;
+    }
+    else
+    {
+        /* EDID Structure 2 */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetDigitalSignalInfo
+ *      This function gets the digital video input signal information.
+ *      Only applies to EDID 1.3 and above.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pDFP1xSupport   - Pointer to a variable to store the flag to indicate that
+ *                        the mointor interface is signal compatible with VESA
+ *                        DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color
+ *                        MSB aligned, DE active high
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDigitalSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDFP1xSupport
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision == 3))
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Check if the input signal is digital */
+        if (pEDIDStructure->videoInputDefinition.digitalSignal.inputSignal != 1)
+            return (-1);
+            
+        if (pDFP1xSupport != (unsigned char *)0)
+            *pDFP1xSupport = pEDIDStructure->videoInputDefinition.digitalSignal.dfp1Support;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetDisplaySize
+ *      This function gets the display sizes in cm.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMaxHorzImageSize   - Pointer to a variable to store the maximum horizontal 
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *      pMaxVertImageSize   - Pointer to a variable to store the maximum vertical
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDisplaySize(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMaxHorzImageSize,
+    unsigned char *pMaxVertImageSize
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pMaxHorzImageSize != (unsigned char *)0)
+            *pMaxHorzImageSize = pEDIDStructure->maxHorzImageSize;
+        
+        if (pMaxVertImageSize != (unsigned char *)0)
+            *pMaxVertImageSize = pEDIDStructure->maxVertImageSize;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+#if 0   /* Use the edidGetWhitePoint to get the Gamma */
+/*
+ *  edidGetGamma
+ *      This function gets the Display Transfer Characteristic (Gamma).
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Gamma value multiplied by 100. A value of 0xFFFF (-1) indicates that
+ *      the gamma value is not defined.
+ */
+unsigned short edidGetGamma(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned short)(((edid_version_1_t *)pEDIDBuffer)->displayTransferChar + 100);
+    
+    return (-1);
+}
+#endif
+
+/*
+ *  edidGetPowerManagementSupport
+ *      This function gets the monitor's power management support.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStandBy        - Pointer to a variable to store the flag to indicate that
+ *                        standby power mode is supported.
+ *      pSuspend        - Pointer to a variable to store the flag to indicate that
+ *                        suspend power mode is supported.
+ *      pLowPower       - Pointer to a variable to store the flag to indicate that
+ *                        the display consumes low power when it receives a timing
+ *                        signal that is outside its declared active operating range.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetPowerManagementSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStandBy,
+    unsigned char *pSuspend,
+    unsigned char *pLowPower
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pStandBy != (unsigned char *)0)
+            *pStandBy = (unsigned char) pEDIDStructure->featureSupport.standbySupport;
+            
+        if (pSuspend != (unsigned char *)0)
+            *pSuspend = (unsigned char) pEDIDStructure->featureSupport.suspendSupport;
+            
+        if (pLowPower != (unsigned char *)0)
+            *pLowPower = (unsigned char) pEDIDStructure->featureSupport.lowPowerSupport;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetDisplayType
+ *      This function gets the display type.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Monochrome / grayscale display
+ *      1   - RGB Color Display
+ *      2   - Non-RGB multicolor display, e.g. R/G/Y
+ *      3   - Undefined
+ */
+unsigned char edidGetDisplayType(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.displayType;
+    
+    return (3);
+}
+
+/*
+ *  edidChecksRGBUsage
+ *      This function checks if the display is using the sRGB standard default
+ *      color space as its primary color space. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Does not use sRGB as its primary color space
+ *      1   - Use sRGB as its primary color space
+ */
+unsigned char edidChecksRGBUsage(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.sRGBSupport;
+    
+    return (0);
+}
+
+/*
+ *  edidIsPreferredTimingAvailable
+ *      This function checks whether the preffered timing mode is available.
+ *      Use of preferred timing mode is required by EDID structure version 1
+ *      Revision 3 and higher. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Preferred Timing is not available
+ *      1   - Preferred Timing is available
+ */
+unsigned char edidIsPreferredTimingAvailable(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Get EDID Version and revision */
+        version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+        if (version == 1)
+            return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.preferredTiming;
+    }
+        
+    return (0);
+}
+
+/*
+ *  edidIsDefaultGTFSupported
+ *      This function checks whether the display supports timings based on the
+ *      GTF standard using default GTF parameter values. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Default GTF is not supported
+ *      1   - Default GTF is supported
+ */
+unsigned char edidIsDefaultGTFSupported(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.defaultGTFSupport;
+    
+    return (0);
+}
+
+/*
+ *  edidCalculateChromaticValue
+ *      This function calculates the chromatic value. 
+ *
+ *  Input:
+ *      colorBinaryValue    - Color Characteristic Binary Representation Value 
+ *                            to be computed
+ *
+ *  Output:
+ *      The chromatic value times a 1000.
+ */
+static unsigned short edidCalculateChromaticValue(
+    unsigned short colorBinaryValue
+)
+{
+    unsigned long index;
+    unsigned long result;
+    
+    result = 0;
+    for (index = 10; index > 0; index--)
+    {
+        /* Times 1000000 to make it accurate to the micro value. */
+        result += roundedDiv((colorBinaryValue & 0x0001) * 1000000, twoToPowerOfx(index));
+        colorBinaryValue >>= 1;
+    }
+    
+    /* Make it accurate to 1000 place */
+    return ((unsigned short)roundedDiv(result, 1000));
+}
+
+/*
+ *  edidGetColorCharacteristic
+ *      This function gets the chromaticity and white point values expressed as
+ *      an integer value which represents the actual value times 1000.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRedX   - Pointer to a variable to store the Red X values
+ *      pRedY   - Pointer to a variable to store the Red Y values
+ *      pGreenX - Pointer to a variable to store the Green X values
+ *      pGreenY - Pointer to a variable to store the Green Y values
+ *      pBlueX  - Pointer to a variable to store the Blue X values
+ *      pBlueY  - Pointer to a variable to store the Blue Y values
+ *
+ *  Note:
+ *      To get the White color characteristic, use the edidGetWhitePoint
+ */
+void edidGetColorCharacteristic(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRedX,
+    unsigned short *pRedY,
+    unsigned short *pGreenX,
+    unsigned short *pGreenY,
+    unsigned short *pBlueX,
+    unsigned short *pBlueY
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pRedX != (unsigned short *)0)
+        {
+            *pRedX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redX << 2) + 
+                                                  (unsigned short)pEDIDStructure->redGreenLowBits.redXLowBits);
+        }
+            
+        if (pRedY != (unsigned short *)0)
+        {
+            *pRedY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redY << 2) + 
+                                                  (unsigned short)pEDIDStructure->redGreenLowBits.redYLowBits);
+        }
+            
+        if (pGreenX != (unsigned short *)0)
+        {
+            *pGreenX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenX << 2) + 
+                                                    (unsigned short)pEDIDStructure->redGreenLowBits.greenXLowBits);
+        }
+            
+        if (pGreenY != (unsigned short *)0)
+        {
+            *pGreenY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenY << 2) + 
+                                                    (unsigned short)pEDIDStructure->redGreenLowBits.greenYLowBits);
+        }
+            
+        if (pBlueX != (unsigned short *)0)
+        {
+            *pBlueX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueX << 2) +
+                                                   (unsigned short)pEDIDStructure->blueWhiteLowBits.blueXLowBits);
+        }
+            
+        if (pBlueY != (unsigned short *)0)
+        {
+            *pBlueY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueY << 2) +
+                                                   (unsigned short)pEDIDStructure->blueWhiteLowBits.blueYLowBits);
+        }
+    }
+}
+
+/*
+ *  edidGetWhitePoint
+ *      This function gets the white point.
+ *      To get the default white point, set the index to 0. For multiple white point,
+ *      call this function multiple times to check if more than 1 white point is supported.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pWhitePointIndex    - Pointer to a variable that contains the white point index 
+ *                            to be retrieved.
+ *      pWhiteX             - Pointer to a variable to store the White X value
+ *      pWhiteY             - Pointer to a variable to store the White Y value
+ *      pWhiteGamma         - Pointer to a variable to store the White Gamma value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetWhitePoint(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pWhitePointIndex,
+    unsigned short *pWhiteX,
+    unsigned short *pWhiteY,
+    unsigned short *pWhiteGamma
+)
+{
+    unsigned char version, index, tableIndex;
+    
+    if (pWhitePointIndex == (unsigned char *)0)
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Get the index to a temporary variable and increment the index for the
+           next loop. */
+        index = *pWhitePointIndex;
+        (*pWhitePointIndex)++;
+        
+        if (index == 0)
+        {
+            if (pWhiteX != (unsigned short *)0)
+            {
+                *pWhiteX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteX << 2) +
+                                                        (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteXLowBits);
+            }
+            
+            if (pWhiteY != (unsigned short *)0)
+            {
+                *pWhiteY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteY << 2) +
+                                                        (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteYLowBits);
+            }
+            
+            if (pWhiteGamma != (unsigned short *)0)
+                *pWhiteGamma = pEDIDStructure->displayTransferChar + 100;
+                
+            return 0;
+        }
+        else
+        {
+            for (tableIndex = 0; tableIndex < 4; tableIndex++)
+            {
+                pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+                if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                    (pMonitorDescriptor->dataTypeTag == 0xFB) && 
+                    (pMonitorDescriptor->descriptor.colorPoint.white[index-1].whitePointIndex != 0))
+                {
+                    if (pWhiteX != (unsigned short *)0)
+                    {
+                        *pWhiteX = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteX << 2) +
+                                                                (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteXLowBits);
+                    }
+                    
+                    if (pWhiteY != (unsigned short *)0)
+                    {
+                        *pWhiteY = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteY << 2) +
+                                                                (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteYLowBits);
+                    }
+                    
+                    if (pWhiteGamma != (unsigned short *)0)
+                        *pWhiteGamma = pMonitorDescriptor->descriptor.colorPoint.white[index-1].gamma + 100;
+                    
+                    return 0;
+                }
+            }
+        }
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidCalculateChecksum
+ *      This function adds all one-byte value of the EDID buffer. 
+ *      The total should be equal to 0x00
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total of one-byte values. It should equal to 0x00. A value other than
+ *      0x00 indicates the EDID buffer is not valid.
+ */
+__attribute__((unused)) static unsigned char edidCalculateChecksum(
+    unsigned char *pEDIDBuffer)
+{
+    unsigned char version, revision, checksum;
+    unsigned short index;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    checksum = 0;
+    if (version == 1)
+    {
+        for (index = 0; index < 128; index++)
+            checksum += pEDIDBuffer[index];
+    }
+    
+    return checksum;
+}
+
+/*
+ *  edidGetExtension
+ *      This function gets the number of (optional) EDID extension blocks to follow
+ *      the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total number of EDID Extension to follow the given EDID buffer.
+ */
+unsigned char edidGetExtension(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+        return ((edid_version_1_t *)pEDIDBuffer)->extFlag;
+    
+    return 0;
+}
+
+#define EDID_TOTAL_RETRY_COUNTER            1
+
+#if 0
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidReadMonitorEx(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+)
+{
+    unsigned char value, retry, edidVersion, edidRevision;
+    unsigned char edidBuffer[256];
+    unsigned long offset;
+    
+    /* Initialize the i2c bus */
+    swI2CInit(sclGpio, sdaGpio);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+            
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++)
+            edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+            
+        /* Check if the EDID is valid. */
+        edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+        DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); 
+        if (edidVersion != 0)
+            break;
+    }
+    
+    /* 
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.  
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+    
+    /* Copy the data to the given buffer */
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        for (offset = 0; offset < bufferSize; offset++)
+            pEDIDBuffer[offset] = edidBuffer[offset];
+    }
+    
+#if 0 /*def DDKDEBUG*/
+    for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++)
+    {
+        if ((offset % 16) == 0)
+        {
+            if (offset != 0)
+                DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n"));
+            DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x:\t", offset));
+        }
+        DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x  ", pEDIDBuffer[offset]));
+    }
+    DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n"));
+#endif
+
+    return 0;
+}
+
+#else
+
+/*
+ *  ddk750_edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Fail
+ *      edidSize   - Success and return the edid's size
+ */
+long ddk750_edidReadMonitorEx(
+	disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+)
+{
+    unsigned char retry, edidVersion, edidRevision;
+    unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256];
+    unsigned long offset;
+    long edidSize = TOTAL_EDID_REGISTERS_128;
+
+    /* Initialize the i2c bus */
+    swI2CInit(sclGpio, sdaGpio);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+       // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+#ifndef  READ_EDID_CONTINUOUS
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++)
+            edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+#else
+        if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, TOTAL_EDID_REGISTERS_128, edidBuffer))
+            memset(edidBuffer, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */
+#endif
+
+         	if(edidBuffer[EDID_EXTEND_BLOCK])
+       	 	{
+#ifndef  READ_EDID_CONTINUOUS    
+            	for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++)
+                	edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+#else
+           	if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, TOTAL_EDID_REGISTERS_128, TOTAL_EDID_REGISTERS_128, edidBuffer + TOTAL_EDID_REGISTERS_128))
+                	memset(edidBuffer + TOTAL_EDID_REGISTERS_128, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */
+#endif
+        	edidSize = TOTAL_EDID_REGISTERS_256;
+         	}	
+
+        /* Check if the EDID is valid. */
+        edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); 
+        if (edidVersion != 0)
+            break;
+    }
+    
+    /* 
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return 0;
+    }
+
+    /* Copy the data to the given buffer */
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        for (offset = 0; offset < edidSize; offset++)
+            pEDIDBuffer[offset] = edidBuffer[offset];
+    }
+
+    return edidSize;
+}
+
+#endif
+
+long ddk750_edidReadMonitorEx_HW(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+)
+{
+    unsigned char value, retry, edidVersion, edidRevision;
+    unsigned char edidBuffer[256];
+    unsigned long offset;
+	long edidSize = 0;
+    
+    /* Initialize the i2c bus */
+    ddk750_hwI2CInit(1);
+
+#if 0
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+                
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++)
+            edidBuffer[offset] = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+            
+        /* Check if the EDID is valid. */
+        edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+        if (edidVersion != 0)
+            break;
+    }
+#else
+
+	for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+		edidSize = 0;
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++)
+        {
+            value = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+            if(0xFFFFFFFF == value)
+                break;
+            edidBuffer[offset] = (0xFF & value);
+        }
+        if(0xFFFFFFFF != value)
+        {
+          	edidSize = TOTAL_EDID_REGISTERS_128;
+            if(edidBuffer[EDID_EXTEND_BLOCK])
+            {
+                for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++)
+                {
+                    value = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+
+                    if(0xFFFFFFFF == value)
+                        break;
+                    edidBuffer[offset] = (0xFF & value);
+                }
+
+                if(0xFFFFFFFF != value)
+                	edidSize = TOTAL_EDID_REGISTERS_256;
+            }
+            if(0xFFFFFFFF != value)
+            {
+                /* Check if the EDID is valid. */
+                edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+           //     DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision));
+                if (edidVersion != 0)
+                    break;
+            }
+        }
+    }
+
+#endif
+    /* Finish using HW I2C, we can close the device. */
+    ddk750_hwI2CClose();
+
+    /* 
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.  
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+    
+    /* Copy the data to the given buffer */
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        for (offset = 0; offset < edidSize; offset++)
+            pEDIDBuffer[offset] = edidBuffer[offset];
+    }
+    
+#if 0 /*def DDKDEBUG*/
+    for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++)
+    {
+        if ((offset % 16) == 0)
+        {
+            if (offset != 0)
+                DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n"));
+            DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x:\t", offset));
+        }
+        DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x  ", pEDIDBuffer[offset]));
+    }
+    DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n"));
+#endif
+
+    return edidSize;
+}
+
+
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidReadMonitor(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+)
+{
+    return ddk750_edidReadMonitorEx(displayPath, pEDIDBuffer, bufferSize, edidExtNo, DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
+}
+
+#define HEADER_EDID_REGISTERS               8
+
+/*
+ *  edidGetHeader
+ *      This function gets the EDID Header
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0 get header success; -1 fail.
+ */
+unsigned char ddk750_edidGetHeader(
+    unsigned char *pEDIDBuffer
+)
+{
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Check the header */
+        if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) &&
+            (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) &&
+            (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00))
+        {
+            return 0;
+        }
+        else
+            return -1;
+    }
+
+   // DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID bufffer\n"));
+    return -1;
+}
+
+
+
+/*
+ *  edidHeaderReadMonitor
+ *      This function reads the EDID header from the attached monitor
+ *
+ *  Input:
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidHeaderReadMonitorEx(
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+)
+{
+    unsigned char retry;//value,
+    unsigned char edidBuffer[10];
+    
+
+    /* Initialize the i2c bus */
+    swI2CInit(sclGpio, sdaGpio);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+     //   DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+
+#ifndef READ_EDID_CONTINUOUS
+		  /* Read the EDID from the monitor. */
+		  for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++)
+			  edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+#else
+ 		  if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, HEADER_EDID_REGISTERS, edidBuffer))
+ 			  memset(edidBuffer, 0xFF, HEADER_EDID_REGISTERS); /* read error */
+#endif
+
+
+        /* Check if the EDID header is valid. */
+        if (!ddk750_edidGetHeader((unsigned char *)&edidBuffer))
+            break;
+    }
+
+    /*
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+
+    return 0;
+}
+
+long ddk750_edidHeaderReadMonitorExHwI2C(void)
+{
+    unsigned char retry;//value,
+    unsigned char edidBuffer[10];
+    unsigned long offset;
+
+    /* Initialize the i2c bus */
+    ddk750_hwI2CInit(1);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++)
+            edidBuffer[offset] = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+
+        /* Check if the EDID header is valid. */
+        if (!ddk750_edidGetHeader((unsigned char *)&edidBuffer))
+            break;
+    }
+
+	/* Finish using HW I2C, we can close the device. */
+    ddk750_hwI2CClose();
+
+    /*
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+
+    return 0;
+}
+
+
+
+
+/*
+ *  edidGetEstablishedTiming
+ *      This function gets the established timing list from the given EDID buffer,
+ *      table, and timing index.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor (In)
+ *      pEstTableIndex  - Pointer to the Established Timing Table index  (In/Out)
+ *      pIndex          - Pointer to the Establihsed Timing Index (In/Out)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *      pSource         - Pointer to a variable to store the standard timing source:
+ *                          0 - VESA
+ *                          1 - IBM
+ *                          2 - Apple
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetEstablishedTiming(
+    unsigned char *pEDIDBuffer,
+    /*unsigned char *pEstTableIndex,*/
+    unsigned char *pIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate,
+    unsigned char *pSource
+)
+{
+    unsigned char version, revision;
+    unsigned char tableIndex, index;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            /* Get index */
+            index = *pIndex;
+            
+            if (index > 16)
+                break;
+            
+            /* Search Established Table index 0 when the index is less than 8 */
+            tableIndex = index / 8;
+            
+            /* Exit the function when it has reached the last table. */
+            if (tableIndex > 2)
+                break;
+            
+            /* Increment the index value and update the index accordingly */
+            (*pIndex)++;
+            index %= 8;
+            
+            /* Check */
+            if ((pEDIDStructure->estTiming[tableIndex] & (1 << index)) != 0)
+            {
+                if (pWidth != (unsigned long *)0)
+                    *pWidth = establishTiming[tableIndex][index].x;
+        
+                if (pHeight != (unsigned long *)0)
+                    *pHeight = establishTiming[tableIndex][index].y;
+    
+                if (pRefreshRate != (unsigned long *)0)
+                    *pRefreshRate = establishTiming[tableIndex][index].hz;
+    
+                if (pSource != (unsigned char *)0)
+                    *pSource = establishTiming[tableIndex][index].source;
+                    
+                /* Return success */
+                return 0;
+            }
+        }
+    }
+    else
+    {
+        /* EDID Structure Version 2.0. */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidCalculateStdTiming
+ *      This function calculates the width, height, and vertical frequency values
+ *      from the given Standard Timing structure. This function only applies to
+ *      EDID structure version 1. It will give the wrong result when used with
+ *      EDID version 2.
+ *
+ *  Input:
+ *      pStdTiming      - Pointer to a standard timing structure that contains the
+ *                        standard timing value to be calculated (In)
+ *      edid1Revision   - Revision of the EDID 1 (In)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+static long edidCalculateStdTiming(
+    standard_timing_t *pStdTiming,
+    unsigned char edid1Revision,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+)
+{
+    unsigned long x, y;
+     
+    /* Calculate the standard timing into x and y mode dimension */
+    if (pStdTiming->horzActive != 0x01)
+    {
+        /* Calculate the X and Y */
+        x = (pStdTiming->horzActive + 31) * 8;
+        switch (pStdTiming->stdTimingInfo.aspectRatio)
+        {
+            case 0:
+                if (edid1Revision != 3)
+                    y = x;                  /* 1:1 aspect ratio (prior revision 1.3) */
+                else
+                    y = x * 10 / 16;        /* 16:10 aspect ratio (revision 1.3) */
+                break;
+            case 1:
+                y = x * 3 / 4;              /* 4:3 aspect ratio */
+                break;
+            case 2:
+                y = x * 4 / 5;              /* 5:4 aspect ratio */
+                break;
+            case 3:
+                y = x * 9 / 16;             /* 16:9 aspect ratio */
+                break;
+        }
+
+        if (pWidth != (unsigned long *)0)
+            *pWidth = x;
+
+        if (pHeight != (unsigned long *)0)
+            *pHeight = y;
+
+        if (pRefreshRate != (unsigned long *)0)
+            *pRefreshRate = pStdTiming->stdTimingInfo.refreshRate + 60;
+    
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetStandardTiming
+ *      This function gets the standard timing from the given EDID buffer and
+ *      calculates the width, height, and vertical frequency from that timing.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStdTimingIndex - Pointer to a standard timing index to be retrieved
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetStandardTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStdTimingIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+)
+{
+    unsigned char version, revision, timingIndex, tableIndex;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            /* There are only 8 standard timing entries */
+            if (*pStdTimingIndex > 7)
+                break;
+            
+            /* Get the table index first before incrementing the index. */
+            timingIndex = *pStdTimingIndex;
+            
+            /* Increment the standard timing index */
+            (*pStdTimingIndex)++;
+            
+            if (timingIndex < 8)
+            {
+                /*
+                 *  Search the first Standard Timing Identifier table
+                 */
+                 
+                /* Calculate the standard timing into x and y mode dimension */
+                if (edidCalculateStdTiming(&pEDIDStructure->stdTiming[timingIndex], 
+                                       revision, pWidth, pHeight, pRefreshRate) == 0)
+                {
+                    return 0;
+                }
+            }
+            else
+            {
+                /*
+                 *  Search Standard Timing Identifier Table in the detailed Timing block. 
+                 */
+                
+                /* 
+                 * Each Detailed Timing Identifier can contains 6 entries of Standard Timing
+                 * Identifier. Based on this value, we can get the Detailed Timing Table Index
+                 * that contains the requested standard timing.
+                 */
+                timingIndex = timingIndex - 8;
+                for (tableIndex = 0; tableIndex < 4; tableIndex++)
+                {
+                    /* Get detailed info */
+                    pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+                    if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                        (pMonitorDescriptor->dataTypeTag == 0xFA))
+                    {
+                        if (timingIndex >= 6)
+                        {
+                            timingIndex-=6;
+                            continue;
+                        }
+                        else
+                        {
+                            if (edidCalculateStdTiming(&pMonitorDescriptor->descriptor.stdTimingExt.stdTiming[timingIndex], 
+                                                   revision, pWidth, pHeight, pRefreshRate) == 0)
+                            {
+                                return 0;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        /* EDID Structure version 2 */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetDetailedTiming
+ *      This function gets the detailed timing from the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pDetailedTimingIndex    - Pointer to a detailed timing index to be retrieved
+ *      pModeParameter          - Pointer to a mode_parameter_t structure that will be
+ *                                filled with the detailed timing.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDetailedTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDetailedTimingIndex,
+    vdif_t *pVDIF
+)
+{
+    unsigned char version, revision, tableIndex;
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        detailed_timing_t *pDetailedTiming;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            if (*pDetailedTimingIndex > 3)
+                break;
+            
+            /* Get the Detail Timing entry index */
+            tableIndex = *pDetailedTimingIndex;
+            
+            /* Increment the index */
+            (*pDetailedTimingIndex)++;
+                
+            /* Get detailed info */
+            pDetailedTiming = &pEDIDStructure->miscInformation.detailTiming[tableIndex];
+            if ((pDetailedTiming->pixelClock != 0) && (pVDIF != (vdif_t *)0))
+            {
+                /* Translate the Detail timing to VDIF format. */
+                pVDIF->pixelClock = (unsigned long)pDetailedTiming->pixelClock * 10000;
+                pVDIF->characterWidth = 8;
+                pVDIF->scanType = (pDetailedTiming->flags.interlaced == 0) ? VDIF_NONINTERLACED : VDIF_INTERLACED;
+
+                pVDIF->horizontalActive = 
+                    ((unsigned long)pDetailedTiming->horzActiveBlanking.horzActiveMSB << 8) +
+                     (unsigned long)pDetailedTiming->horzActive;
+                pVDIF->horizontalBlankStart = pVDIF->horizontalActive;
+                pVDIF->horizontalBlankTime = 
+                    ((unsigned long)pDetailedTiming->horzActiveBlanking.horzBlankingMSB << 8) +
+                     (unsigned long)pDetailedTiming->horzBlanking;
+                pVDIF->horizontalTotal = pVDIF->horizontalActive + pVDIF->horizontalBlankTime;
+                pVDIF->horizontalFrontPorch = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncOffset << 8) + 
+                     (unsigned long)pDetailedTiming->horzSyncOffset;
+                pVDIF->horizontalSyncStart = pVDIF->horizontalBlankStart + pVDIF->horizontalFrontPorch;
+                pVDIF->horizontalSyncWidth = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncWidth << 8) +
+                     (unsigned long)pDetailedTiming->horzSyncPulseWidth;                     
+                pVDIF->horizontalBackPorch = 
+                    pVDIF->horizontalBlankTime - (pVDIF->horizontalFrontPorch + pVDIF->horizontalSyncWidth);
+                pVDIF->horizontalFrequency = roundedDiv(pVDIF->pixelClock, pVDIF->horizontalTotal);
+                pVDIF->horizontalLeftBorder = 0;
+                pVDIF->horizontalRightBorder = 0;
+        
+                pVDIF->verticalActive = 
+                    ((unsigned long)pDetailedTiming->vertActiveBlanking.vertActiveMSB << 8) +
+                     (unsigned long)pDetailedTiming->vertActive;
+                pVDIF->verticalBlankStart = pVDIF->verticalActive;
+                pVDIF->verticalBlankTime =
+                    ((unsigned long)pDetailedTiming->vertActiveBlanking.vertBlankingMSB << 8) +
+                     (unsigned long)pDetailedTiming->vertBlanking;
+                pVDIF->verticalTotal = pVDIF->verticalActive + pVDIF->verticalBlankTime;
+                pVDIF->verticalFrontPorch = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncOffset << 8) +
+                     (unsigned long)pDetailedTiming->verticalSyncInfo.syncOffset;
+                pVDIF->verticalSyncStart = pVDIF->verticalBlankStart + pVDIF->verticalFrontPorch;
+                pVDIF->verticalSyncHeight =
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncWidth  << 8) +
+                     (unsigned long)pDetailedTiming->verticalSyncInfo.syncWidth;
+                pVDIF->verticalBackPorch =
+                    pVDIF->verticalBlankTime - (pVDIF->verticalFrontPorch + pVDIF->verticalSyncHeight);
+                pVDIF->verticalFrequency =
+                    roundedDiv(pVDIF->pixelClock, (pVDIF->horizontalTotal * pVDIF->verticalTotal));
+                pVDIF->verticalTopBorder = 0;
+                pVDIF->verticalBottomBorder = 0;
+                
+                if (pDetailedTiming->flags.connectionType == 3)
+                {
+                    pVDIF->verticalSyncPolarity = 
+                        (pDetailedTiming->flags.vertSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE;
+                    pVDIF->horizontalSyncPolarity = 
+                        (pDetailedTiming->flags.horzSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE;
+                }
+                else
+                {
+                    pVDIF->verticalSyncPolarity = VDIF_SYNC_NEGATIVE;
+                    pVDIF->horizontalSyncPolarity = VDIF_SYNC_NEGATIVE;
+                }
+                
+                /* For debugging purpose. */
+                printVdif(pVDIF);
+                
+                return 0;
+            }
+        }
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidGetMonitorSerialNumber
+ *      This function gets the monitor serial number from the EDID structure.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the serial number 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the serial number.
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorSerialNumber(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorSerialNumber,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pMonitorSerialNumber == (char *)0) || (bufferSize == 0))
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFF))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.serialNo[charIndex] == 0x0A)
+                    {
+                        pMonitorSerialNumber[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pMonitorSerialNumber[charIndex] = pMonitorDescriptor->descriptor.serialNo[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Serial Number is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetDataString
+ *      This function gets the data string from the EDID 
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the data string 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the data string
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDataString(
+    unsigned char *pEDIDBuffer,
+    char *pDataString,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pDataString == (char *)0) || (bufferSize == 0))
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFE))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.dataString[charIndex] == 0x0A)
+                    {
+                        pDataString[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pDataString[charIndex] = pMonitorDescriptor->descriptor.dataString[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetMonitorRangeLimit
+ *      This function gets the monitor range limits from the EDID structure.
+ *      Only EDID version 1 revision 1 or above supports this feature.
+ *      This is a required field in EDID Version 1.3
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMinVerticalRate    - Pointer to a variable to store the Minimum Vertical Rate (Hz)
+ *      pMaxVerticalRate    - Pointer to a variable to store the Maximum Vertical Rate (Hz)
+ *      pMinHorzFreq        - Pointer to a variable to store the Minimum Horz. Freq (kHz)
+ *      pMaxHorzFreq        - Pointer to a variable to store the Maximum Horz. Freq (kHz)
+ *      pMaxPixelClock      - Pointer to a variable to store the Maximum Pixel Clock (Hz)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorRangeLimit(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMinVerticalRate,
+    unsigned char *pMaxVerticalRate,
+    unsigned char *pMinHorzFreq,
+    unsigned char *pMaxHorzFreq,
+    unsigned long *pMaxPixelClock
+)
+{
+    unsigned char version, revision, tableIndex;
+    
+    if (pEDIDBuffer == (unsigned char *)0)
+        return (-1);
+            
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFD) && (pMonitorDescriptor->flag3 == 0))
+            {
+                if (pMinVerticalRate != (unsigned char *)0)
+                    *pMinVerticalRate = pMonitorDescriptor->descriptor.monitorRange.minVertRate;
+
+                if (pMaxVerticalRate != (unsigned char *)0)
+                    *pMaxVerticalRate = pMonitorDescriptor->descriptor.monitorRange.maxVertRate;
+                    
+                if (pMinHorzFreq != (unsigned char *)0)
+                    *pMinHorzFreq = pMonitorDescriptor->descriptor.monitorRange.minHorzFrequency;
+                    
+                if (pMaxHorzFreq != (unsigned char *)0)
+                    *pMaxHorzFreq = pMonitorDescriptor->descriptor.monitorRange.maxHorzFrequency;
+                    
+                if (pMaxPixelClock != (unsigned long *)0)
+                    *pMaxPixelClock = (unsigned long) pMonitorDescriptor->descriptor.monitorRange.maxPixelClock * 10 * 1000000;
+                    
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetSecondaryTimingSupport
+ *      This function gets the secondary GTF timing support.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pStartFrequency         - Pointer to a variable to store the start frequency of 
+ *                                the secondary GTF
+ *      pOffset                 - Pointer to a variable to store the Offset (C) value of
+ *                                the secondary GTF
+ *      pGradient               - Pointer to a variable to store the Gradient (M) value of
+ *                                the secondary GTF
+ *      pScalingFactor          - Pointer to a variable to store the Scaling Factor (K)
+ *                                value of the secondary GTF
+ *      pScalingFactorWeight    - Pointer to a variable to store the Scaling Factore Weight (J)
+ *                                value of the secondary GTF
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetSecondaryTimingSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pStartFrequency,
+    unsigned char *pOffset,
+    unsigned short *pGradient,
+    unsigned char *pScalingFactor,
+    unsigned char *pScalingFactorWeight
+)
+{
+    unsigned char version, revision, tableIndex;
+            
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0) && (pEDIDBuffer != (unsigned char *)0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFD) && 
+                (pMonitorDescriptor->descriptor.monitorRange.secondaryTimingFlag == 0x02))
+            {
+                if (pStartFrequency != (unsigned short *)0)
+                    *pStartFrequency = (unsigned short)
+                        pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.startFrequency * 2 * 1000;
+
+                if (pOffset != (unsigned char *)0)
+                    *pOffset = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.cParam/2;
+                    
+                if (pGradient != (unsigned short *)0)
+                    *pGradient = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.mParam;
+                    
+                if (pScalingFactor != (unsigned char *)0)
+                    *pScalingFactor = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.kParam;
+                    
+                if (pScalingFactorWeight != (unsigned char *)0)
+                    *pScalingFactorWeight = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.jParam / 2;
+                    
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetMonitorName
+ *      This function gets the monitor name from the EDID structure.
+ *      This is a required field in EDID Version 1.3
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorName            - Pointer to a buffer to store the monitor name 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the monitor name
+ *                                The maximum size required is 13 bytes.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorName(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorName,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pMonitorName == (char *)0) || (bufferSize == 0))
+        return (-1);
+        
+    /* Get EDID Version and revision */
+    version = edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFC) && (pMonitorDescriptor->flag3 == 0))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.monitorName[charIndex] == 0x0A)
+                    {
+                        pMonitorName[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pMonitorName[charIndex] = pMonitorDescriptor->descriptor.monitorName[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetPreferredTiming
+ *      This function gets the preferred/native timing of the monitor
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWidth              - Pointer to an unsigned long buffer to store the width 
+ *                            of the preferred (native) timing.
+ *      pHeight             - Pointer to an unsigned long buffer to store the height
+ *                            of the preferred (native) timing.
+ *      pVerticalFrequency  - Pointer to an unsigned long buffer to store the refresh
+ *                            rate of the preferred (native) timing.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetPreferredTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pVerticalFrequency
+)
+{
+    unsigned char index = 0;
+    vdif_t vdifBuffer;
+
+/* Disable this checking since some old monitor does have the Detailed Timing although the preferred timing flag is 0. */
+#if 0
+    /* Check if preferred timing is available */
+    if (edidIsPreferredTimingAvailable(pEDIDBuffer) == 1)
+#endif
+    {
+        /* The preferred (native) timing is available, so get the timing. It is located
+           at the first index of detailed timing.
+         */
+        if (edidGetDetailedTiming(pEDIDBuffer, &index, &vdifBuffer) == 0)
+        {
+            if (pWidth != (unsigned long *)0)
+                *pWidth = vdifBuffer.horizontalActive;
+                
+            if (pHeight != (unsigned long *)0)
+                *pHeight = vdifBuffer.verticalActive;
+                
+            if (pVerticalFrequency != (unsigned long *)0)
+                *pVerticalFrequency = vdifBuffer.verticalFrequency;
+                
+            return 0;
+        }
+    }
+    
+    return (-1);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.h
new file mode 100644
index 000000000000..89bcaf2253c0
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_edid.h
@@ -0,0 +1,1028 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  edid.h --- SMI DDK 
+*  This file contains the EDID structure and function API to
+*  interpret the EDID
+* 
+*******************************************************************/
+#ifndef _EDID_H_
+#define _EDID_H_
+
+#include "ddk750_display.h"
+#include "vdif.h"
+
+/* Set the alignment to 1-bit aligned. Otherwise, it can't get the EDID correctly. */
+#pragma pack(1)
+
+#define READ_EDID_CONTINUOUS
+
+
+
+/* Standard Timing Structure */
+typedef struct _standard_timing_t
+{
+    unsigned char horzActive;       /* (Horizontal active pixels / 8 ) - 31 */
+    struct
+    {
+        unsigned char refreshRate:6;    /* Refresh Rate (Hz) - 60; Range 60 --> 123 */
+        unsigned char aspectRatio:2;    /* Aspect Ratio:
+                                            Bit 7   Bit 6   Operation
+                                              0       0        1:1      (prior Version 1.3)
+                                              0       0       16:10     (Version 1.3)
+                                              0       1        4:3
+                                              1       0        5:4
+                                              1       1       16:9
+                                         */
+    } stdTimingInfo;
+} standard_timing_t;
+
+/* Detailed Timing Description Structure */
+typedef struct _detailed_timing_t
+{
+    unsigned short pixelClock;
+    unsigned char horzActive;
+    unsigned char horzBlanking;
+    struct 
+    {
+        unsigned char horzBlankingMSB:4;
+        unsigned char horzActiveMSB:4;
+    } horzActiveBlanking;
+    unsigned char vertActive;
+    unsigned char vertBlanking;
+    struct 
+    {
+        unsigned char vertBlankingMSB:4;
+        unsigned char vertActiveMSB:4;
+    } vertActiveBlanking;
+    unsigned char horzSyncOffset;
+    unsigned char horzSyncPulseWidth;
+    struct
+    {
+        unsigned char syncWidth:4;
+        unsigned char syncOffset:4;
+    } verticalSyncInfo;
+    struct
+    {
+        unsigned char vertSyncWidth:2;
+        unsigned char vertSyncOffset:2;
+        unsigned char horzSyncWidth:2;
+        unsigned char horzSyncOffset:2;
+    } syncAuxInfo;
+    unsigned char horzImageSize;
+    unsigned char vertImageSize;
+    struct
+    {
+        unsigned char vertImageSizeMSB:4;
+        unsigned char horzImageSizeMSB:4;
+    } horzVertImageSize;
+    unsigned char horzBorder;
+    unsigned char vertBorder;
+    struct
+    {
+        unsigned char interleaved:1;
+        unsigned char horzSyncFlag:1;
+        unsigned char vertSyncFlag:1;
+        unsigned char connectionType:2;
+        unsigned char stereo:2;
+        unsigned char interlaced:1;
+    } flags;
+} detailed_timing_t;
+
+typedef struct _color_point_t
+{
+    unsigned char whitePointIndex;
+    struct
+    {
+        unsigned char whiteYLowBits:2;
+        unsigned char whiteXLowBits:2;
+        unsigned char reserved:4;
+    } whiteLowBits;
+    unsigned char whiteX;
+    unsigned char whiteY;
+    unsigned char gamma;
+} color_point_t;
+
+typedef struct _monitor_desc_t
+{
+    unsigned short flag1;               /* Flag = 0000h when block used as descriptor */
+    unsigned char flag2;                /* Flag = 00h when block used as descriptor */
+    unsigned char dataTypeTag;          /* Data type tag:
+                                                FFh: Monitor Serial Number - Stored as ASCII, 
+                                                     code page #437, <= 13bytes
+                                                FEh: ASCII String - Stored as ASCII, code 
+                                                     page #437, <= 13 bytes
+                                                FDh: Monitor range limits, binary coded
+                                                FCh: Monitor name, stored as ASCII, code page #437
+                                                FBh: Descriptor contains additional color point data
+                                                FAh: Descriptor contains additional Standard Timing
+                                                     Identifications
+                                                F9h-11h: Currently undefined
+                                                10h: Dummy descriptor, used to indicate 
+                                                     that the descriptor space is unused
+                                                0Fh-00h: Descriptor defined by manufacturer.
+                                         */
+    unsigned char flag3;                /* Flag = 00h when block used as descriptor */
+    union
+    {
+        unsigned char serialNo[13];
+        unsigned char dataString[13];
+        struct
+        {
+            unsigned char minVertRate;
+            unsigned char maxVertRate;
+            unsigned char minHorzFrequency;
+            unsigned char maxHorzFrequency;
+            unsigned char maxPixelClock;        /* Binary coded clock rate in MHz / 10 
+                                                   Max Pixel Clock those are not a multiple of 10MHz
+                                                   is rounded up to a multiple of 10MHz
+                                                 */
+            unsigned char secondaryTimingFlag;  /* 00h = No secondary timing formula supported
+                                                   (Support for default GTF indicated in feature byte)
+                                                   02h = Secondary GTF curve supported
+                                                   All other = Reserved for future timing formula
+                                                               definitions.
+                                                 */
+            union
+            {
+                unsigned char constantStr[7];
+                struct
+                {
+                    unsigned char reserved;
+                    unsigned char startFrequency;
+                    unsigned char cParam;
+                    unsigned short mParam;
+                    unsigned char kParam;
+                    unsigned char jParam;
+                } cmkjParam;
+            } secondaryTimingInfo;
+        } monitorRange;
+        
+        unsigned char monitorName[13];
+        struct
+        {
+            color_point_t white[2];
+            unsigned char reserved[3];          /* Set to (0Ah, 20h, 20h)*/
+        } colorPoint;
+        
+        struct
+        {
+            standard_timing_t stdTiming[6];
+            unsigned char reserved;             /* Set to 0Ah */
+        } stdTimingExt;
+        
+        unsigned char manufactureSpecifics[13];
+    } descriptor; 
+}
+monitor_desc_t;
+
+/* EDID Structuve Version 1. Within version 1 itself, there are 4 revisions mentioned
+   below: 
+    - EDID 1.0: The original 128-byte data format
+    - EDID 1.1: Added definitions for monitor descriptors as an alternate use of the space 
+                originally reserved for detailed timings, as well as definitions for 
+                previously unused fields.
+    - EDID 1.2: Added definitions to existing data fields.
+    - EDID 1.3: Added definitions for secondary GTF curve coefficients. This is the new
+                baseline for EDID data structures, which is recommended for all new monitor
+                designs.
+ */
+typedef struct _edid_version_1_t
+{
+    /* Header (8 bytes) */
+    unsigned char header[8];            /* Header */
+    
+    /* Vendor / Product ID (10 bytes) */
+    unsigned short manufacturerID;      /* Manufacture Identification */
+    unsigned short productCode;         /* Product code Identification */ 
+    unsigned long serialNumber;         /* Serial Number */
+    unsigned char weekOfManufacture;    /* Week of Manufacture */
+    unsigned char yearOfManufacture;    /* Year of Manufacture */
+    
+    /* EDID Structure version / revision (2 bytes) */
+    unsigned char version;              /* EDID Structure Version no. */
+    unsigned char revision;             /* Revision Version no. */
+    
+    /* Basic Display Parameters / Features (5 bytes) */
+    union
+    {
+        struct
+        {
+            unsigned char vsyncSerration:1;
+            unsigned char syncOnGreenSupport:1;
+            unsigned char compositeSyncSupport:1;
+            unsigned char separateSyncSupport:1;
+            unsigned char blank2Black:1;
+            unsigned char signalLevelStd:2;
+            unsigned char inputSignal:1;    /* Input Signal: Analog = 0, Digital = 1 */
+        } analogSignal;
+        struct
+        {
+            unsigned char dfp1Support:1;
+            unsigned char reserved:6;
+            unsigned char inputSignal:1;    /* Input Signal: Analog = 0, Digital = 1 */
+        } digitalSignal;
+    } videoInputDefinition;             /* Video Input Definition */
+
+    unsigned char maxHorzImageSize;     /* Maximum Horizontal Image Size */
+    unsigned char maxVertImageSize;     /* Maximum Vertical Image Size */
+    unsigned char displayTransferChar;  /* Display Transfer Characteristic (Gamma) */
+    struct
+    {
+        unsigned char defaultGTFSupport:1;  /* Support timings based on the GTF standard using
+                                               default GTF parameters 
+                                             */ 
+        unsigned char preferredTiming:1;    /* If set, the display's preferred timing mode is
+                                               indicated in the first detailed timing block.
+                                             */
+        unsigned char sRGBSupport:1;        /* If set, the display uses the sRGB standard
+                                               default color space as its primary color space
+                                             */
+        unsigned char displayType:2;        /* Display Type:
+                                                    00  - Monochrome / Grayscale display
+                                                    01  - RGB Color Display
+                                                    10  - Non-RGB multicolor display, e.g. R/G/Y
+                                                    11  - Undefined
+                                             */
+        unsigned char lowPowerSupport:1;    /* If set, the display consumes much less power when
+                                               it receives a timing signal outside its active
+                                               operating range. It will revert to normal if the
+                                               timing returns to the normal operating range.
+                                             */
+        unsigned char suspendSupport:1;     /* Support Suspend as defined in VESA DPMS spec. */
+        unsigned char standbySupport:1;     /* Support Standby as defined in VESA DPMS spec. */
+    } featureSupport;                   /* Feature Support */
+    
+    /* Color Characteristics (10 bytes) */
+    struct
+    {
+        unsigned char greenYLowBits:2;
+        unsigned char greenXLowBits:2;
+        unsigned char redYLowBits:2;
+        unsigned char redXLowBits:2;
+    } redGreenLowBits;                  /* Red/Green Low Bits */
+    struct
+    {
+        unsigned char whiteYLowBits:2;
+        unsigned char whiteXLowBits:2;
+        unsigned char blueYLowBits:2;
+        unsigned char blueXLowBits:2;
+    } blueWhiteLowBits;                 /* Blue/White Low Bits */
+    unsigned char redX;                 /* Red-x bits 9-2 */
+    unsigned char redY;                 /* Red-y bits 9-2 */
+    unsigned char greenX;               /* Green-x bits 9-2 */
+    unsigned char greenY;               /* Green-y bits 9-2 */
+    unsigned char blueX;                /* Blue-x bits 9-2 */
+    unsigned char blueY;                /* Blue-y bits 9-2 */
+    unsigned char whiteX;               /* White-x bits 9-2 */
+    unsigned char whiteY;               /* White-y bits 9-2 */
+    
+    /* Established Timings (3 bytes) */
+    unsigned char estTiming[3];         /* Established Timings */
+    
+    /* Standard Timing Identification (16 bytes) */
+    standard_timing_t stdTiming[8];     /* Standard Timings Identification */
+
+    /* Detailed Timing Descriptions (72 bytes) */
+    union
+    {
+        detailed_timing_t detailTiming[4];  /* Detailed Timing Descriptor */
+        monitor_desc_t monitorDesc[4];  /* Monitor descriptor */
+    } miscInformation;
+    
+    /* Extension Flag (1 byte) */
+    unsigned char extFlag;              /* Number of (optional) 1280byte EDID
+                                           extension blocks to follow. 
+                                         */
+                                         
+    /* Checksum (1 byte) */
+    unsigned char checksum;             /* The 1-byte sum of all 128 bytes in 
+                                           this EDID block shall equal zero. 
+                                         */
+}
+edid_version_1_t;
+
+#if 0   /* Temporary on hold. To be completed later. */
+
+/* EDID Version 2.0. Not widely used. Usually defined for displays that follow 
+   the original VESA Plug & Display (P&D) and Flat Panel Display Interface-2 (FPDI-2)
+   Standards
+ */
+typedef struct _edid_version_2_t
+{
+    /* 
+     * EDID Structure Version/Revision (1 byte) 
+     */
+    unsigned char version:4;
+    unsigned char revision:4;
+    
+    /* 
+     * Vendor / Product ID (7 bytes) 
+     */
+    unsigned short manufacturerID;              /* ID Manufacturer Name */
+    unsigned short productID;                   /* ID Product Code */
+    unsigned char manufactureWeek;              /* Week of Manufacture */
+    unsigned short manufactureYear;             /* Year of Manufacture */
+    
+    /* 
+     * Manufacturer/Product ID string (32 bytes) 
+     */
+    unsigned char productName;                  /* This string is compiresed of both manufacture name 
+                                                   and model name, which are separated using ASCII code 09h.
+                                                   If the entire string is <32 bytes, then it is terminated
+                                                   with ASCII code 0Ah and the field is padded with ASCII 
+                                                   code 20h 
+                                                 */
+                                             
+    /* 
+     * Serial number string (16 bytes) 
+     */
+    unsigned char serianNumber[16];             /* Serial number string. If <16 bytes then the string is
+                                                   terminated with ASCII code 0Ah and the field padded
+                                                   with ASCII code 20h
+                                                 */
+                                             
+    /* 
+     * Unused/Reserved (8 bytes) 
+     */
+    unsigned char reserved[8];
+    
+    /* 
+     * Display Interface Parameters (15 bytes) 
+     */
+    unsigned char secondaryPhysicalIF:4;        /* Look at defaultPhysicalIF description above. */
+    unsigned char defaultPhysicalIF:4;          /* Physical Connector Types. Consists of 2 fields. Bit 7-4
+                                                   indicates the connector for the default interface. If
+                                                   a secondary interface is available, its connector is
+                                                   indicated using bit 3-0. Both fields value description
+                                                   is listed below:
+                                                        0 = None (Not valid for default connector)
+                                                        1 = BNC
+                                                        2 = 15 pin VGA
+                                                        3 = 13w3
+                                                        4 = VESA EVC
+                                                        5 = VESA P&D-D
+                                                        6 = Micro-ribbon Connector (per the VESA P&D standard)
+                                                        7 = IEEE-1394 connector
+                                                        8 = VESA FPDI-2
+                                                        9-E = Reserved
+                                                        F = Non-standard connector
+                                                 */
+    unsigned char secondaryVideoIF:4;           /* Look at the defaultVideoIF description above. */
+    unsigned char defaultVideoIF:4;             /* Video Interface Types. Consists of 2 fields. Bit 7-4
+                                                   defines the default video interface. Bit 3-0 defines
+                                                   the secondary interface. Descriptions of the field is
+                                                   listed below:
+                                                        0 = None (Not valid for default interface)
+                                                        1 = Analog
+                                                        2 = Analog w/ sampled pixel clock
+                                                        3 = TMDS (Transition Minimized Differential Signaling)
+                                                        4 = IEEE-1394-1995
+                                                        5 = LVDS
+                                                        6 = Parallel
+                                                        7-F = Reserved
+                                                 */
+    unsigned char analogIFDataFormat[4];        /* Analog Interface Data Format */
+    unsigned char digitalIFDataFormat[4];       /* Digital Interface Data Format */
+    unsigned char secondaryColorEncodingIF:4;   /* Secondary Color Encoding Interface */
+    unsigned char defaultColorEncodingIF:4;     /* Color Encoding default Interface */
+    unsigned char primarySubChannel1:4;         /* Supported bit-depth of sub-channel 1 ("Green") 
+                                                   of the Primary interface. */
+    unsigned char primarySubChannel0:4;         /* Supported bit-depth of sub-channel 0 ("Red") 
+                                                   of the Primary interface. */
+    unsigned char primarySubChannel3:4;         /* Supported bit-depth of sub-channel 3 of the 
+                                                   Primary interface. */
+    unsigned char primarySubChannel2:4;         /* Supported bit-depth of sub-channel 2 ("Blue") 
+                                                   of the Primary interface. */
+    unsigned char secondarySubChannel1:4;       /* Supported bit-depth of sub-channel 1 ("Green") 
+                                                   of the Secondary interface. */
+    unsigned char secondarySubChannel0:4;       /* Supported bit-depth of sub-channel 0 ("Red") 
+                                                   of the Secondary interface. */
+    unsigned char secondarySubChannel3:4;       /* Supported bit-depth of sub-channel 3 of the 
+                                                   Secondary interface. */
+    unsigned char secondarySubChannel2:4;       /* Supported bit-depth of sub-channel 2 ("Blue") 
+                                                   of the Secondary interface. */
+                                                   
+    /* 
+     * Display Device Description (5 bytes) 
+     */
+    unsigned char displayType;                  /* Display technology type/subtype*/
+    unsigned char displayCharacteristic;        /* Major display characteristics. */
+    unsigned char featureSupport[3];            /* Feature Support */
+    
+    /* 
+     * Display Response Time (2 bytes) 
+     */
+    unsigned char riseTimeResponse:4;           /* Rise time response in seconds */
+    unsigned char riseTimeExponent:4;           /* Rise time exponent */
+    unsigned char fallTimeResponse:4;           /* Fall time response in seconds */
+    unsigned char fallTimeExponent:4;           /* Fall time exponent */
+    
+    /* 
+     * Color / Luminance Description (28 bytes) 
+     */
+    unsigned char whiteGamme;                   /* (Gamma x 100) - 100, [range 1.00 --> 3.55] */
+    unsigned char redGamma;                     /* Color 0 ("red") Gamma (optional). Set to ffh if unused. */
+    unsigned char greenGamma;                   /* Color 1 ("green") Gamma (optional). Set to ffh if unused. */
+    unsigned char blueGamma;                    /* Color 2 ("blue") Gamma (optional). Set to ffh if unused. */
+    unsigned short maxLuminance;                /* Maximum LUminance (white) in units of cd/m^2*10 */
+    unsigned char colorConfig;                  /* Standard RGB Model, adjustable Gamma and its offset */
+    unsigned char offsetValue;                  /* Color Offset value */
+    
+    /* Calorimetry and White Point(s) */
+    unsigned char redGreenLowBits;              /* Red / Green Low Bits */
+}
+edid_version_2_t;
+
+#endif
+
+/* Restore alignment */
+#pragma pack()
+
+/**************************************************************
+ *  Function Prototypes
+ **************************************************************/
+
+/*
+ *  edidGetVersion
+ *      This function gets the EDID version
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRevision   - Revision of the EDIE (if exist)
+ *
+ *  Output:
+ *      Revision number of the given EDID buffer.
+ */
+unsigned char edidGetVersion(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pRevision
+);
+
+/*
+ *  edidGetProductInfo
+ *      This function gets the vendor and product information.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor [in]
+ *      pManufacturerName   - Pointer to a 3 byte length variable to store the manufacturer name [out]
+ *      pProductCode        - Pointer to a variable to store the product code [out]
+ *      pSerialNumber       - Pointer to a variable to store the serial number [out]
+ *      pWeekOfManufacture  - Pointer to a variable to store the week of manufacture [out]
+ *      pYearOfManufacture  - Pointer to a variable to store the year of manufacture 
+ *                            or model year (if WeekOfManufacture is 0xff) [out]
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetProductInfo(
+    unsigned char *pEDIDBuffer,
+    char *pManufacturerName,
+    unsigned short *pProductCode,
+    unsigned long *pSerialNumber,
+    unsigned char *pWeekOfManufacture,
+    unsigned short *pYearOfManufacture
+);
+
+/*
+ *  edidCheckMonitorInputSignal
+ *      This function checks whether the monitor is expected analog/digital 
+ *      input signal.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Analog
+ *      1   - Digital
+ */
+unsigned char edidCheckMonitorInputSignal(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidGetAnalogSignalInfo
+ *      This function gets the analog video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pRefWhiteAboveBlank     - Pointer to a variable to store the reference white above blank
+ *                                value. The value is in milliVolt.
+ *      pSyncLevelBelowBlank    - Pointer to a variable to store the Sync tip level below blank
+ *                                The value is also in milliVolt
+ *      pBlank2BlackSetup       - Pointer to a variable to store the Blank to black setup or
+ *                                pedestal per appropriate Signal Level Standard flag. 
+ *                                1 means that the display expect the setup.
+ *      pSeparateSyncSupport    - Pointer to a variable to store the flag to indicate that the
+ *                                monitor supports separate sync.
+ *      pCompositeSyncSupport   - Pointer to a variable to store a flag to indicate that the
+ *                                monitor supports composite sync.
+ *      pSyncOnGreenSupport     - Pointer to a variable to store a flag to indicate that
+ *                                the monitor supports sync on green video.
+ *      pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration
+ *                                of the VSync pulse is required when composite sync or
+ *                                sync-on-green video is used.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetAnalogSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRefWhiteAboveBlank,
+    unsigned short *pSyncLevelBelowBlank,
+    unsigned char *pBlank2BlackSetup,
+    unsigned char *pSeparateSyncSupport,
+    unsigned char *pCompositeSyncSupport,
+    unsigned char *pSyncOnGreenSupport,
+    unsigned char *pVSyncSerrationRequired
+);
+
+/*
+ *  edidGetDigitalSignalInfo
+ *      This function gets the digital video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pDFP1xSupport   - Pointer to a variable to store the flag to indicate that
+ *                        the mointor interface is signal compatible with VESA
+ *                        DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color
+ *                        MSB aligned, DE active high
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDigitalSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDFP1xSupport
+);
+
+/*
+ *  edidGetDisplaySize
+ *      This function gets the display sizes in cm.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMaxHorzImageSize   - Pointer to a variable to store the maximum horizontal 
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *      pMaxVertImageSize   - Pointer to a variable to store the maximum vertical
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDisplaySize(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMaxHorzImageSize,
+    unsigned char *pMaxVertImageSize
+);
+
+/*
+ *  edidGetPowerManagementSupport
+ *      This function gets the monitor's power management support.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStandBy        - Pointer to a variable to store the flag to indicate that
+ *                        standby power mode is supported.
+ *      pSuspend        - Pointer to a variable to store the flag to indicate that
+ *                        suspend power mode is supported.
+ *      pLowPower       - Pointer to a variable to store the flag to indicate that
+ *                        the display consumes low power when it receives a timing
+ *                        signal that is outside its declared active operating range.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetPowerManagementSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStandBy,
+    unsigned char *pSuspend,
+    unsigned char *pLowPower
+);
+
+/*
+ *  edidGetDisplayType
+ *      This function gets the display type.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Monochrome / grayscale display
+ *      1   - RGB Color Display
+ *      2   - Non-RGB multicolor display, e.g. R/G/Y
+ *      3   - Undefined
+ */
+unsigned char edidGetDisplayType(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidChecksRGBUsage
+ *      This function checks if the display is using the sRGB standard default
+ *      color space as its primary color space. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Does not use sRGB as its primary color space
+ *      1   - Use sRGB as its primary color space
+ */
+unsigned char edidChecksRGBUsage(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidIsPreferredTimingAvailable
+ *      This function checks whether the preffered timing mode is available.
+ *      Use of preferred timing mode is required by EDID structure version 1
+ *      Revision 3 and higher. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Preferred Timing is not available
+ *      1   - Preferred Timing is available
+ */
+unsigned char edidIsPreferredTimingAvailable(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidIsDefaultGTFSupported
+ *      This function checks whether the display supports timings based on the
+ *      GTF standard using default GTF parameter values. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Default GTF is not supported
+ *      1   - Default GTF is supported
+ */
+unsigned char edidIsDefaultGTFSupported(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidGetColorCharacteristic
+ *      This function gets the chromaticity and white point values expressed as
+ *      an integer value which represents the actual value times 1000.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRedX   - Pointer to a variable to store the Red X values
+ *      pRedY   - Pointer to a variable to store the Red Y values
+ *      pGreenX - Pointer to a variable to store the Green X values
+ *      pGreenY - Pointer to a variable to store the Green Y values
+ *      pBlueX  - Pointer to a variable to store the Blue X values
+ *      pBlueY  - Pointer to a variable to store the Blue Y values
+ *
+ *  Note:
+ *      To get the White color characteristic, use the edidGetWhitePoint
+ */
+void edidGetColorCharacteristic(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRedX,
+    unsigned short *pRedY,
+    unsigned short *pGreenX,
+    unsigned short *pGreenY,
+    unsigned short *pBlueX,
+    unsigned short *pBlueY
+);
+
+/*
+ *  edidGetWhitePoint
+ *      This function gets the white point.
+ *      To get the default white point, set the index to 0. For multiple white point,
+ *      call this function multiple times to check if more than 1 white point is supported.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWhitePointIndex    - Pointer to a variable that contains the white point index 
+ *                            to be retrieved.
+ *      pWhiteX             - Pointer to a variable to store the White X value
+ *      pWhiteY             - Pointer to a variable to store the White Y value
+ *      pWhiteGamma         - Pointer to a variable to store the White Gamma value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetWhitePoint(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pWhitePointIndex,
+    unsigned short *pWhiteX,
+    unsigned short *pWhiteY,
+    unsigned short *pWhiteGamma
+);
+
+/*
+ *  edidGetExtension
+ *      This function gets the number of (optional) EDID extension blocks to follow
+ *      the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total number of EDID Extension to follow the given EDID buffer.
+ */
+unsigned char edidGetExtension(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidReadMonitor(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+);
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidReadMonitorEx(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);
+
+long ddk750_edidReadMonitorEx_HW(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+);
+
+
+/*
+ *  edidGetEstablishedTiming
+ *      This function gets the established timing list from the given EDID buffer,
+ *      table, and timing index.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor (In)
+ *      pEstTableIndex  - Pointer to the Established Timing Table index  (In/Out)
+ *      pIndex          - Pointer to the Establihsed Timing Index (In/Out)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *      pSource         - Pointer to a variable to store the standard timing source:
+ *                          0 - VESA
+ *                          1 - IBM
+ *                          2 - Apple
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetEstablishedTiming(
+    unsigned char *pEDIDBuffer,
+    /*unsigned char *pEstTableIndex,*/
+    unsigned char *pIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate,
+    unsigned char *pSource
+);
+
+/*
+ *  edidGetStandardTiming
+ *      This function gets the standard timing from the given EDID buffer and
+ *      calculates the width, height, and vertical frequency from that timing.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStdTimingIndex - Pointer to a standard timing index to be retrieved
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetStandardTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStdTimingIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+);
+
+/*
+ *  edidGetDetailedTiming
+ *      This function gets the detailed timing from the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pDetailedTimingIndex    - Pointer to a detailed timing index to be retrieved
+ *      pModeParameter          - Pointer to a mode_parameter_t structure that will be
+ *                                filled with the detailed timing.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDetailedTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDetailedTimingIndex,
+    vdif_t *pVDIF
+);
+
+/*
+ *  edidGetMonitorSerialNumber
+ *      This function gets the monitor serial number from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the serial number 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the serial number.
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorSerialNumber(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorSerialNumber,
+    unsigned char bufferSize
+);
+
+/*
+ *  edidGetDataString
+ *      This function gets the data string from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the data string 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the data string
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetDataString(
+    unsigned char *pEDIDBuffer,
+    char *pDataString,
+    unsigned char bufferSize
+);
+
+/*
+ *  edidGetMonitorRangeLimit
+ *      This function gets the monitor range limits from the EDID structure.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMinVerticalRate    - Pointer to a variable to store the Minimum Vertical Rate (Hz)
+ *      pMaxVerticalRate    - Pointer to a variable to store the Maximum Vertical Rate (Hz)
+ *      pMinHorzFreq        - Pointer to a variable to store the Minimum Horz. Freq (kHz)
+ *      pMaxHorzFreq        - Pointer to a variable to store the Maximum Horz. Freq (kHz)
+ *      pMaxPixelClock      - Pointer to a variable to store the Maximum Pixel Clock (Hz)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorRangeLimit(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMinVerticalRate,
+    unsigned char *pMaxVerticalRate,
+    unsigned char *pMinHorzFreq,
+    unsigned char *pMaxHorzFreq,
+    unsigned long *pMaxPixelClock
+);
+
+/*
+ *  edidGetSecondaryTimingSupport
+ *      This function gets the secondary GTF timing support.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pStartFrequency         - Pointer to a variable to store the start frequency of 
+ *                                the secondary GTF
+ *      pOffset                 - Pointer to a variable to store the Offset (C) value of
+ *                                the secondary GTF
+ *      pGradient               - Pointer to a variable to store the Gradient (M) value of
+ *                                the secondary GTF
+ *      pScalingFactor          - Pointer to a variable to store the Scaling Factor (K)
+ *                                value of the secondary GTF
+ *      pScalingFactorWeight    - Pointer to a variable to store the Scaling Factore Weight (J)
+ *                                value of the secondary GTF
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetSecondaryTimingSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pStartFrequency,
+    unsigned char *pOffset,
+    unsigned short *pGradient,
+    unsigned char *pScalingFactor,
+    unsigned char *pScalingFactorWeight
+);
+
+/*
+ *  edidGetMonitorName
+ *      This function gets the monitor name from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorName            - Pointer to a buffer to store the monitor name 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the monitor name
+ *                                The maximum size required is 13 bytes. 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetMonitorName(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorName,
+    unsigned char bufferSize
+);
+
+/*
+ *  edidGetPreferredTiming
+ *      This function gets the preferred/native timing of the monitor
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWidth              - Pointer to an unsigned long buffer to store the width 
+ *                            of the preferred (native) timing.
+ *      pHeight             - Pointer to an unsigned long buffer to store the height
+ *                            of the preferred (native) timing.
+ *      pVerticalFrequency  - Pointer to an unsigned long buffer to store the refresh
+ *                            rate of the preferred (native) timing.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetPreferredTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pVerticalFrequency
+);
+
+#endif  /* _EDID_H_ */
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_hardware.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_hardware.h
new file mode 100644
index 000000000000..86b84b4497d9
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_hardware.h
@@ -0,0 +1,191 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  HARDWARE.h --- Voyager GX SDK 
+*  This file contains the definitions for the physical hardware.
+* 
+*******************************************************************/
+#ifndef _HARDWARE_H_
+#define _HARDWARE_H_
+
+/* Use IO Port to access the MMIO 
+   NOTE:
+        The easiest way to run the application in MS-DOS when using the SM750 as 
+        secondary adapter is using the following steps:
+        1. Disable the VGA enable bit in the primary card's PCI to PCI bridge.
+           This bit is location at offset 0x3E bit 3. --> This can be implemented
+           in the application or run the PCI Tools to modify the PCI to PCI bridge manually.
+        2. Enable the VGA enable bit in the secondary (SM750) card's PCI to PCI bridge.
+           --> This can be implemented
+           in the application or run the PCI Tools to modify the PCI to PCI bridge manually.
+        3. Enable "USE_IO_PORT" definition and compile it. --> It will automatically 
+           enable the IO Port Access in the PCI Configuration Register offset 4, bit 1.
+        4. Configure the DOS system to use Serial port. Hints: Use "mode" command
+           and "ctty com1". It requires NULL model serial cable and another system to
+           operate the DOS from the other serial port. --> This step can be done in 
+           any sequence prior running the application. 
+        5. Run the application from the serial port.
+ */
+//#define USE_IO_PORT
+
+/* Use 0xA0000 as the frame buffer access. */
+//#define USE_A0000
+
+/* Silicon Motion PCI vendor ID */
+#define SMI_PCI_VENDOR_ID               0x126F
+#define HIS_PCI_VENDOR_ID               0x19E5
+
+/* Maximum number of devices with the same ID supported by this library. */
+#define MAX_SMI_DEVICE                  4
+
+/* List of Silicon Motion PCI Device ID that is supported by this library. */
+#define SMI_DEVICE_ID_SM750             0x0750
+#define SMI_DEVICE_ID_SM718             0x0718
+#define HIS_DEVICE_ID_SM750             0x1711
+
+/* Size of the SM750 MMIO and memory */
+#define SM750_PCI_ALLOC_MMIO_SIZE       (2*1024*1024)
+#define SM750_PCI_ALLOC_MEMORY_SIZE     (64*1024*1024)
+
+/* Register types */
+typedef enum _reg_type_t
+{
+    MISCELLANEOUS_REGISTER,
+    SEQUENCER_REGISTER,
+    CRT_REGISTER,
+    GRAPHICS_REGISTER,
+    OTHER_REGISTER
+}
+reg_type_t;
+
+#ifdef USE_A0000
+/*
+ * Set the bank size when using A0000h memory addressing .
+ */
+void setBankSize(
+    unsigned long bankSize
+);
+#endif
+
+/*
+ * Get the physical address of an offset location in frame buffer.
+ * In DOS, the physical and the logical address most likely are the same.
+ * Return: A valid address if success.
+ *         NULL address if fail.
+ */
+void *getPhysicalAddress(unsigned long offset /* Offset from base of physical frame buffer */);
+
+/*
+ * Get the logical address of an offset location in frame buffer.
+ * Return: A valid address if success.
+ *         NULL address if fail.
+ */
+void *getAddress(unsigned long offset /*Offset from base of frame buffer*/);
+
+/*
+ * Get the IRQ number of the current device.
+ */
+unsigned char getIRQ(void);
+
+/*
+ * This function detects what SMI chips is in the system.
+ *
+ * Return: A non-zero device ID if SMI chip is detected.
+ *         Zero means NO SMI chip is detected.
+ */
+unsigned short detectDevices(void);
+
+/*
+ *  Function to return vendor ID, chip ID and revision of the current chip, if any.
+ */
+unsigned short getVendorId(void);
+unsigned short getDeviceId(void);
+unsigned char  getDeviceRev(void);
+
+/*
+ * How many devices of the same ID are there.
+ */
+unsigned short getNumOfDevices(void);
+
+/*
+ * This function sets up the current accessible device, if more
+ * than one of the same ID exist in the system.
+ *
+ * Note:
+ * Single device application don't need to call this function.
+ * This function is to control multiple devices.
+ */
+long setCurrentDevice(unsigned short dev);
+//unsigned short getCurrentDevice(void);
+#define getCurrentDevice(...) SM750
+
+/* Video Memory read/write functions */
+unsigned char peekByte(unsigned long offset);
+unsigned short peekWord(unsigned long offset);
+unsigned long peekDWord(unsigned long offset);
+void poke_4_Byte(unsigned long offset, unsigned char *buf);
+void pokeByte(unsigned long offset, unsigned char value);
+void pokeWord(unsigned long offset, unsigned short value);
+void pokeDWord(unsigned long offset, unsigned long value);
+#if 0 //by ilena
+/* MMIO read/write functions */
+unsigned char peekRegisterByte(unsigned long offset);
+unsigned short peekRegisterWord(unsigned long offset);
+unsigned long peekRegisterDWord(unsigned long offset);
+void pokeRegisterByte(unsigned long offset, unsigned char value);
+void pokeRegisterWord(unsigned long offset, unsigned short value);
+void pokeRegisterDWord(unsigned long offset, unsigned long value);
+#endif
+
+#if 0   /* For Testing Purpose */
+/*
+ * Read SM718 PCI byte value 
+ */
+unsigned char readDevicePCIByte(
+    unsigned short offset
+);
+
+/*
+ * Read SM718 PCI word value 
+ */
+unsigned short readDevicePCIWord(
+    unsigned short offset
+);
+
+/*
+ * Read SM718 PCI dword value 
+ */
+unsigned long readDevicePCIDWord(
+    unsigned short offset
+);
+
+/*
+ * Write SM718 PCI byte value 
+ */
+long writeDevicePCIByte(
+    unsigned short offset,
+    unsigned char value
+);
+
+/*
+ * Write SM718 PCI word value 
+ */
+long writeDevicePCIWord(
+    unsigned short offset,
+    unsigned short value
+);
+
+/*
+ * Write SM718 PCI dword value 
+ */
+long writeDevicePCIDWord(
+    unsigned short offset,
+    unsigned long value
+);
+#endif
+
+#endif /* _HARDWARE_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_help.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_help.c
new file mode 100644
index 000000000000..5e36214b95e4
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_help.c
@@ -0,0 +1,18 @@
+#include "ddk750_help.h"
+
+volatile unsigned char __iomem * mmio750 = NULL;
+char revId750 = 0;
+unsigned short devId750 = 0;
+
+
+
+/* after driver mapped io registers, use this function first */
+void ddk750_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId)
+{
+	mmio750 = addr;
+	devId750 = devId;
+	revId750 = revId;
+	if(revId == 0xfe)
+		printk("found sm750le\n");
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_help.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_help.h
new file mode 100644
index 000000000000..4cf2b6e20d4e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_help.h
@@ -0,0 +1,33 @@
+#ifndef DDK750_HELP_H__
+#define DDK750_HELP_H__
+#include "ddk750_chip.h"
+#ifndef USE_INTERNAL_REGISTER_ACCESS
+
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include "ddk750_mode.h"
+
+
+#define PEEK32(addr) readl((addr)+mmio750)
+#define POKE32(addr,data) writel((data),(addr)+mmio750)
+#define peekRegisterDWord PEEK32
+#define pokeRegisterDWord POKE32
+
+
+#define peekRegisterByte(addr) readb((addr)+mmio750)
+#define pokeRegisterByte(addr,data) writeb((data),(addr)+mmio750)
+
+
+
+extern volatile unsigned  char __iomem * mmio750;
+extern char revId750;
+extern unsigned short devId750;
+void ddk750_set_mmio(volatile unsigned char *,unsigned short,char);
+
+#else
+/* implement if you want use it*/
+#endif
+
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.c
new file mode 100644
index 000000000000..41004100fa6c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.c
@@ -0,0 +1,47 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  helper.c --- SM750 DDK 
+*  This file contains helper functions those are used throughout
+*  the DDK library.
+* 
+*******************************************************************/
+#include "ddk750_helper.h"
+
+/* Perform a rounded division. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+unsigned long roundedDiv(unsigned long num, unsigned long denom)
+{
+    /* n / d + 1 / 2 = (2n + d) / 2d */
+    return (2 * num + denom) / (2 * denom);
+}
+
+
+/* Absolute differece between two numbers */
+unsigned long absDiff(unsigned long a, unsigned long b)
+{
+    if ( a >= b )
+        return(a - b);
+    else
+        return(b - a);
+}
+
+/* This function calculates 2 to the power of x 
+   Input is the power number.
+ */
+unsigned long twoToPowerOfx(unsigned long x)
+{
+    unsigned long i;
+    unsigned long result = 1;
+
+    for (i=1; i<=x; i++)
+        result *= 2;
+
+    return result;
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.h
new file mode 100644
index 000000000000..30b9fb8d1a10
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_helper.h
@@ -0,0 +1,30 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  helper.h --- SMI DDK 
+*  This file contains the helper functions those are used throughout
+*  the library
+* 
+*******************************************************************/
+#ifndef _HELPER_H_
+#define _HELPER_H_
+
+/* Perform a rounded division. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+unsigned long roundedDiv(unsigned long num, unsigned long denom);
+
+/* Absolute differece between two numbers */
+unsigned long absDiff(unsigned long a, unsigned long b);
+
+/* This function calculates 2 to the power of x 
+   Input is the power number.
+ */
+unsigned long twoToPowerOfx(unsigned long x);
+
+#endif  /* _HELPER_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.c
new file mode 100644
index 000000000000..c4c4a76c939c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.c
@@ -0,0 +1,488 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  hwi2c.c --- SMI DDK 
+*  This file contains the source code for hardware i2c.
+* 
+*******************************************************************/
+
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_power.h"
+#include "ddk750_help.h"
+#include "ddk750_hwi2c.h"
+
+
+#define MAX_HWI2C_FIFO                  16
+
+
+static unsigned long hwI2CWriteData(
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+);
+
+static unsigned long hwI2CReadData(
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+);
+
+static int ddk750_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+                           int num)
+{
+    unsigned long ret;
+    int i, count = 0;
+
+    for (i = 0; i < (num - 1); i++)
+        if (msgs[i].flags & I2C_M_RD)
+        {
+            pr_err("only one read message supported, has to be last\n");
+            return -EOPNOTSUPP;
+        }
+
+    while (msgs->len && (count < num))
+    {
+		msgs->addr = msgs->addr << 1;
+        if (!(msgs->flags & I2C_M_RD))
+        {
+            ret = hwI2CWriteData(
+                msgs->addr,
+                msgs->len,
+                msgs->buf);
+            if (ret < msgs->len)
+            {
+                pr_err("ddk50 i2c xfer tx failed %ld.\n", ret);
+                break;
+            }
+        }
+        else
+        {
+            ret = hwI2CReadData(
+                msgs->addr,
+                msgs->len,
+                msgs->buf);
+            if (ret < msgs->len)
+            {
+                pr_err("ddk750 i2c xfer rx failed %ld.\n", ret);
+                break;
+            }
+        }
+
+        msgs++;
+        count++;
+    }
+
+    if (count < num)
+    {
+        pr_err("ddk750 i2c xfer failed %d(%d).\n", count, num);
+        return -EIO;
+    }
+
+    return num;
+}
+
+static u32 ddk750_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+static const struct i2c_algorithm ddk750_i2c_algo = {
+	.master_xfer	= ddk750_i2c_xfer,
+	.functionality	= ddk750_i2c_func
+};
+
+
+/*
+ *  This function initializes the hardware i2c
+ *
+ *  Parameters:
+ *      busSpeedMode    - I2C Bus Speed Mode
+ *                          0 = Standard Mode (100kbps)
+ *                          1 = Fast Mode (400kbps)
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to initialize i2c
+ */
+long ddk750_hwI2CInit(
+    unsigned char busSpeedMode
+)
+{
+    unsigned long value;
+    
+    /* Enable GPIO 30 & 31 as IIC clock & data */
+	value = peekRegisterDWord(GPIO_MUX);
+    value = FIELD_SET(value, GPIO_MUX, 30, I2C) |
+			FIELD_SET(0, GPIO_MUX, 31, I2C);
+	pokeRegisterDWord(GPIO_MUX, value);
+              
+    /* Enable Hardware I2C power.
+       TODO: Check if we need to enable GPIO power?
+     */
+    enableI2C(1);
+    
+    /* Enable the I2C Controller and set the bus speed mode */
+    value = peekRegisterByte(I2C_CTRL);
+    if (busSpeedMode == 0)
+        value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD);
+    else
+        value = FIELD_SET(value, I2C_CTRL, MODE, FAST);        
+    value = FIELD_SET(value, I2C_CTRL, EN, ENABLE);
+    pokeRegisterByte(I2C_CTRL, value);
+    
+    return 0;
+}
+
+long ddk750_AdaptHWI2CInit(struct smi_connector *connector)
+{
+    int ret;
+
+    ddk750_hwI2CInit(1);
+
+    connector->adapter.owner = THIS_MODULE;
+    connector->adapter.class = I2C_CLASS_DDC;
+    snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI HW I2C Bus");
+    connector->adapter.dev.parent = connector->base.dev->dev;
+    i2c_set_adapdata(&connector->adapter, connector);
+	connector->adapter.algo = &ddk750_i2c_algo;
+    ret = i2c_add_adapter(&connector->adapter);
+	if (ret)
+    {
+        pr_err("HW i2c add adapter failed. %d\n", ret);
+		return -1;
+    }
+
+    return 0;
+}
+
+
+/*
+ *  This function closes the hardware i2c.
+ */
+void ddk750_hwI2CClose()
+{
+    unsigned long value;
+    
+    /* Disable I2C controller */
+    value = peekRegisterByte(I2C_CTRL);
+    value = FIELD_SET(value, I2C_CTRL, EN, DISABLE);
+    pokeRegisterByte(I2C_CTRL, value);
+
+    /* Disable I2C Power */
+    enableI2C(0);
+
+    /* Set GPIO 30 & 31 back as GPIO pins */
+    value = peekRegisterDWord(GPIO_MUX);
+    value = FIELD_SET(value, GPIO_MUX, 30, GPIO);
+    value = FIELD_SET(value, GPIO_MUX, 31, GPIO);
+    pokeRegisterDWord(GPIO_MUX, value);
+}
+
+long ddk750_AdaptHWI2CCleanBus(struct smi_connector *connector)
+{
+	ddk750_hwI2CClose();
+	return 0;
+}
+
+/*
+ *  This function waits until the transfer is completed within the timeout value.
+ *
+ *  Return Value:
+ *       0   - Transfer is completed
+ *      -1   - Tranfer is not successful (timeout)
+ */
+#define HWI2C_WAIT_TIMEOUT              0xF0000
+static long hwI2CWaitTXDone(void)
+{
+    unsigned long timeout;
+
+    /* Wait until the transfer is completed. */
+    timeout = HWI2C_WAIT_TIMEOUT;
+	while ((FIELD_GET(peekRegisterByte(I2C_STATUS), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) &&
+           (timeout != 0))
+		timeout--;
+    
+	if (timeout == 0)
+	    return (-1);
+
+    return 0;
+}
+
+/*
+ *  This function writes data to the i2c slave device registers.
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address
+ *      length          - Total number of bytes to be written to the device
+ *      pBuffer         - The buffer that contains the data to be written to the
+ *                     i2c device.   
+ *
+ *  Return Value:
+ *      Total number of bytes those are actually written.
+ */
+static unsigned long hwI2CWriteData(
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned char count, i;
+    unsigned long totalBytes = 0;
+    
+    /* Set the Device Address */
+    pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01);
+    
+    /* Write data.
+     * Note:
+     *      Only 16 byte can be accessed per i2c start instruction.
+     */
+    do
+    {
+        /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */
+        pokeRegisterByte(I2C_RESET, 0);
+        
+        /* Set the number of bytes to be written */
+        if (length < MAX_HWI2C_FIFO)
+            count = length - 1;
+        else
+            count = MAX_HWI2C_FIFO - 1;
+        pokeRegisterByte(I2C_BYTE_COUNT, count);
+        
+        /* Move the data to the I2C data register */
+	    for (i = 0; i <= count; i++)
+            pokeRegisterByte(I2C_DATA0 + i, *pBuffer++);
+
+        /* Start the I2C */
+        pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START));
+        
+        /* Wait until the transfer is completed. */
+        if (hwI2CWaitTXDone() != 0)
+            break;
+    
+        /* Substract length */
+        length -= (count + 1);
+        
+        /* Total byte written */
+        totalBytes += (count + 1);
+        
+    } while (length > 0);
+            
+    return totalBytes;
+}
+
+/*
+ *  This function reads data from the slave device and stores them
+ *  in the given buffer
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address
+ *      length          - Total number of bytes to be read
+ *      pBuffer         - Pointer to a buffer to be filled with the data read
+ *                     from the slave device. It has to be the same size as the
+ *                     length to make sure that it can keep all the data read.   
+ *
+ *  Return Value:
+ *      Total number of actual bytes read from the slave device
+ */
+static unsigned long hwI2CReadData(
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned char count, i;
+    unsigned long totalBytes = 0; 
+    
+    /* Set the Device Address */
+    pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress | 0x01);
+    
+    /* Read data and save them to the buffer.
+     * Note:
+     *      Only 16 byte can be accessed per i2c start instruction.
+     */
+    do
+    {
+        /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */
+        pokeRegisterByte(I2C_RESET, 0);
+        
+        /* Set the number of bytes to be read */
+        if (length <= MAX_HWI2C_FIFO)
+            count = length - 1;
+        else
+            count = MAX_HWI2C_FIFO - 1;
+        pokeRegisterByte(I2C_BYTE_COUNT, count);
+
+        /* Start the I2C */
+        pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START));
+        
+        /* Wait until transaction done. */
+        if (hwI2CWaitTXDone() != 0)
+            break;
+
+        /* Save the data to the given buffer */
+        for (i = 0; i <= count; i++) {
+		*pBuffer++ = peekRegisterByte(I2C_DATA0 + i);
+	}
+
+        /* Substract length by 16 */
+        length -= (count + 1);
+    
+        /* Number of bytes read. */
+        totalBytes += (count + 1); 
+        
+    } while (length > 0);
+    
+    return totalBytes;
+}
+
+/*
+ *  This function reads the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      registerIndex   - Slave device's register to be read
+ *
+ *  Return Value:
+ *      Register value
+ */
+unsigned char ddk750_hwI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+)
+{
+    unsigned char value = (0xFF);
+
+    if (hwI2CWriteData(deviceAddress, 1, &registerIndex) == 1)
+        hwI2CReadData(deviceAddress, 1, &value);
+
+    return value;
+}
+
+/*
+ *  This function writes a value to the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk750_hwI2CWriteReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+)
+{
+    unsigned char value[2];
+    
+    value[0] = registerIndex;
+    value[1] = data;
+    if (hwI2CWriteData(deviceAddress, 2, value) == 2)
+        return 0;
+
+    return (-1);
+}
+
+#if 0
+/* 
+ * This function read the i2c device register value
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be read
+ *
+ * Output:
+ *          The value of the register being read.
+ */
+unsigned long hwI2CReadRegMultiple(
+    unsigned char deviceAddress,
+    unsigned char registerIndex,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned long totalData = 0;
+
+    /* The length is limited to 256 since register index is limited to unsigned char. */
+    if ((registerIndex + length) > 256)
+        length = 256 - registerIndex;
+
+    /* Read from the slave device */
+    if (hwI2CWriteData(deviceAddress, 1, &registerIndex) == 1)
+        totalData = hwI2CReadData(deviceAddress, length, pBuffer);
+    
+    /* Return the total number of read data */
+    return totalData;
+}
+
+/* 
+ * This function writes a value to the i2c device register.
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be read
+ *
+ * Output:
+ *          The value of the register being read.
+ */
+long hwI2CWriteRegMultiple(
+    unsigned char deviceAddress,
+    unsigned char registerIndex,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned char value[MAX_HWI2C_FIFO], index, count, start = 1;
+    unsigned long totalData = 0;
+    
+    /* The length is limited to 256 since register index is limited to unsigned char. */
+    if ((registerIndex + length) > 256)
+        length = 256 - registerIndex;
+
+#if 1
+    /* Temporary use this one */
+    for (index = 0; index < (unsigned char)length; index++)
+    {
+        if (hwI2CWriteReg(deviceAddress, registerIndex + index, *pBuffer++) != 0)
+            return (-1); 
+    }
+#else
+    /* Does not work here. Need to find out how to write multiple data at once. */
+    while (length > 0)
+    {
+        if (length < MAX_HWI2C_FIFO)
+            count = length + 1;         /* Add one for the register Index. */
+        else
+            count = MAX_HWI2C_FIFO;
+        
+        /* Write the starting register index */
+        value[0] = registerIndex;
+        
+        /* Write the data */
+        for (index = 1; index < count; index++)
+            value[index] = *pBuffer++;
+    
+        if (hwI2CWriteData(deviceAddress, count, &value[0]) != count)
+            return (-1);
+            
+        /* Update the length */
+        length -= (count - 1);
+        
+        /* Update the registerIndex */
+        registerIndex += (count - 1);
+    }
+#endif
+    
+    return 0;
+}
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.h
new file mode 100644
index 000000000000..578e2169e58b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_hwi2c.h
@@ -0,0 +1,76 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  hwi2c.H --- SMI DDK 
+*  This file contains the definitions for Hardware I2C.
+* 
+*******************************************************************/
+#ifndef _HWI2C_H_
+#define _HWI2C_H_
+
+#include "../smi_drv.h"
+
+
+/*
+ *  This function initializes the hardware i2c
+ *
+ *  Parameters:
+ *      busSpeedMode    - I2C Bus Speed Mode
+ *                       0 = Standard Mode (100kbps)
+ *                       1 = Fast Mode (400kbps)
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to initialize i2c
+ */
+long ddk750_hwI2CInit(
+    unsigned char busSpeedMode
+);
+
+/* 
+ * This function close the hardware i2c 
+ */
+void ddk750_hwI2CClose(void);
+
+/* 
+ * This function read the i2c device register value
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be read
+ *
+ * Output:
+ *          The value of the register being read.
+ */
+unsigned char ddk750_hwI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+);
+
+/* 
+ * This function writes a value to the i2c device register.
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be written to
+ *          data            - Data to be written to
+ *
+ * Output:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk750_hwI2CWriteReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+);
+
+
+long ddk750_AdaptHWI2CInit(struct smi_connector *connector);
+long ddk750_AdaptHWI2CCleanBus(struct smi_connector *connector);
+
+
+
+#endif  /* _HWI2C_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.c
new file mode 100644
index 000000000000..8fb8d38db103
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.c
@@ -0,0 +1,1189 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  MODE.C --- SMI DDK 
+*  This file contains the source code for the mode table.
+* 
+*******************************************************************/
+//#include <string.h>
+#include "ddk750_defs.h"
+#include "ddk750_chip.h"
+#include "ddk750_clock.h"
+#include "ddk750_hardware.h"
+#include "ddk750_helper.h"
+#include "ddk750_power.h"
+#include "ddk750_mode.h"
+#include "ddk750_help.h"
+
+//#include "ddk750_os.h"
+
+//#include "ddkdebug.h"
+
+#define SCALE_CONSTANT                      (1 << 12)
+
+/* Maximum panel size scaling */
+#define MAX_PANEL_SIZE_WIDTH                1920
+#define MAX_PANEL_SIZE_HEIGHT               1440
+
+/* The valid signature of the user data pointer  for the setmode function. 
+   The following definition is ASCII representation of the word 'USER'
+ */
+#define MODE_USER_DATA_SIGNATURE            0x55534552
+
+/*
+ *  Default Timing parameter for some popular modes.
+ *  Note that the most timings in this table is made according to standard VESA 
+ *  parameters for the popular modes.
+ */
+static mode_parameter_t gDefaultModeParamTable[] =
+    {
+        /*800x480*/
+        //{0, 	800, 	0,	0,	NEG, 0, 480,  0,  0,   POS, 	0,		0,		0, NEG},
+        /* 320 x 240 [4:3] */
+        {352, 320, 335, 8, NEG, 265, 240, 254, 2, NEG, 5600000, 15909, 60, NEG},
+
+        /* 400 x 300 [4:3] -- Not a popular mode */
+        {528, 400, 420, 64, NEG, 314, 300, 301, 2, NEG, 9960000, 18864, 60, NEG},
+
+        /* 480 x 272 -- Not a popular mode --> only used for panel testing */
+        /* { 525, 480, 482, 41, NEG, 286, 272, 274, 10, NEG, 9009000, 17160, 60, NEG}, */
+
+        /* 640 x 480  [4:3] */
+        /* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+        /* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */
+        /* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */
+        {800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG},
+        {840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG},
+        {832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG},
+
+        /* 720 x 480  [3:2] */
+        {889, 720, 738, 108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG},
+
+        /* 720 x 540  [4:3] -- Not a popular mode */
+        {886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG},
+
+        /* 800 x 480  [5:3] -- Not a popular mode */
+        {973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG},
+
+        /* 800 x 600  [4:3] */
+        /* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+        /* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */
+        /* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */
+        {1056, 800, 840, 128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG},
+        {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG},
+        {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG},
+
+        /* 960 x 720  [4:3] -- Not a popular mode */
+        {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG},
+
+        /* 1024 x 600  [16:9] 1.7 */
+        {1313, 1024, 1064, 104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG},
+
+        /* 1024 x 768  [4:3] */
+        /* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+        /* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */
+        /* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */
+        {1344, 1024, 1048, 136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG},
+        {1312, 1024, 1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG},
+        {1376, 1024, 1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG},
+
+        /* 1152 x 864  [4:3] -- Widescreen eXtended Graphics Array */
+        /* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/
+        {1475, 1152, 1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG},
+        {1600, 1152, 1216, 128, POS, 900, 864, 865, 3, POS, 108000000, 67500, 75, NEG},
+
+        /* 1280 x 720  [16:9] -- HDTV (WXGA) */
+        {1664, 1280, 1336, 136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG},
+
+        /* 1280 x 768  [5:3] -- Not a popular mode */
+        {1678, 1280, 1350, 136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG},
+
+        /* 1280 x 800  [8:5] -- Not a popular mode */
+        {1650, 1280, 1344, 136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG},
+
+        /* 1280 x 960  [4:3] */
+        /* The first commented line below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+        /* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/
+        {1800, 1280, 1376, 112, POS, 1000, 960, 961, 3, POS, 108000000, 60000, 60, NEG},
+        {1728, 1280, 1344, 160, POS, 1011, 960, 961, 3, POS, 148500000, 85938, 85, NEG},
+
+/* 1280 x 1024 [5:4] */
+#if 1
+        /* GTF with C = 40, M = 600, J = 20, K = 128 */
+        {1712, 1280, 1360, 136, NEG, 1060, 1024, 1025, 3, POS, 108883200, 63600, 60, NEG},
+        {1728, 1280, 1368, 136, NEG, 1069, 1024, 1025, 3, POS, 138542400, 80175, 75, NEG},
+        {1744, 1280, 1376, 136, NEG, 1075, 1024, 1025, 3, POS, 159358000, 91375, 85, NEG},
+#else
+        /* VESA Standard */
+        {1688, 1280, 1328, 112, POS, 1066, 1024, 1025, 3, POS, 108000000, 63981, 60, NEG},
+        {1688, 1280, 1296, 144, POS, 1066, 1024, 1025, 3, POS, 135000000, 79976, 75, NEG},
+        {1728, 1280, 1344, 160, POS, 1072, 1024, 1025, 3, POS, 157500000, 91146, 85, NEG},
+#endif
+
+/* 1360 x 768 [16:9] */
+#if 1
+        /* GTF with C = 40, M = 600, J = 20, K = 128 */
+        //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG},
+
+        /* GTF with C = 30, M = 600, J = 20, K = 128 */
+        {1664, 1360, 1384, 128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG},
+#else
+        /* Previous Calculation */
+        {1776, 1360, 1424, 144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG},
+#endif
+
+        /* 1366 x 768  [16:9] */
+        /* Previous Calculation  */
+        {1722, 1366, 1424, 112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG},
+
+        /* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore
+   temporarily disabled. */
+        //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG},
+        //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG},
+
+        /* Taken from the www.tinyvga.com */
+        {1880, 1400, 1488, 152, NEG, 1087, 1050, 1051, 3, POS, 122610000, 65218, 60, NEG},
+
+        /* 1440 x 900  [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */
+        {1904, 1440, 1520, 152, NEG, 932, 900, 901, 3, POS, 106470000, 55919, 60, NEG},
+
+        /* 1440 x 960 [3:2] -- Not a popular mode */
+        {1920, 1440, 1528, 152, POS, 994, 960, 961, 3, POS, 114509000, 59640, 60, NEG},
+
+        /* 1600 x 900 */
+        {2128, 1600, 1664, 192, POS, 932, 900, 901, 3, POS, 119000000, 56000, 60, NEG},
+
+        /* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */
+        /* VESA */
+        {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 162000000, 75000, 60, NEG},
+        {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 202500000, 93750, 75, NEG},
+        {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 229500000, 106250, 85, NEG},
+
+        /* 
+ * The timing below is taken from the www.tinyvga.com/vga-timing.
+ * With the exception of 1920x1080.
+ */
+
+        /* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */
+        /* The first commented timing might be used for DVI LCD Monitor timing. */
+        /* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */
+        /* GTF with C = 30, M = 600, J = 20, K = 128 */
+        {2256, 1680, 1784, 184, NEG, 1087, 1050, 1051, 3, POS, 147140000, 65222, 60, NEG},
+        /*
+ {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG},
+ {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG},
+*/
+
+        /* 1792 x 1344 [4:3]. -- Not a popular mode */
+        {2448, 1792, 1920, 200, NEG, 1394, 1344, 1345, 3, POS, 204800000, 83660, 60, NEG},
+        {2456, 1792, 1888, 216, NEG, 1417, 1344, 1345, 3, POS, 261000000, 106270, 75, NEG},
+
+        /* 1856 x 1392 [4:3]. -- Not a popular mode 
+   The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency
+   where not all monitor can support it (including the developer monitor)
+ */
+        {2528, 1856, 1952, 224, NEG, 1439, 1392, 1393, 3, POS, 218300000, 86353, 60, NEG},
+        /* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/
+
+        /* 1920 x 1080 [16:9]. This is a make-up value, need to be proven. 
+   The Pixel clock is calculated based on the maximum resolution of
+   "Single Link" DVI, which support a maximum 165MHz pixel clock.
+   The second values are taken from:
+   http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf
+ */
+        /* {2560,1920,2048,208, NEG,1125,1080,1081, 3, POS,172800000, 67500, 60, NEG}, */
+        {2200, 1920, 2008, 44, NEG, 1125, 1080, 1081, 3, POS, 148500000, 67500, 60, NEG},
+
+        /* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */
+        {2592, 1920, 2048, 208, NEG, 1242, 1200, 1201, 3, POS, 193160000, 74522, 60, NEG},
+
+        /* 1920 x 1440 [4:3]. */
+        /* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. 
+   The timing for 75 Hz is provided here if necessary to do testing. - Some underflow
+   has been noticed. */
+        {2600, 1920, 2048, 208, NEG, 1500, 1440, 1441, 3, POS, 234000000, 90000, 60, NEG},
+        /* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */
+
+        /* End of table. */
+        {0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+#if 0
+static mode_parameter_t gPrimaryModeParamTable[MAX_SMI_DEVICE][MAX_MODE_TABLE_ENTRIES] =
+{
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    }
+};
+
+static mode_parameter_t gSecondaryModeParamTable[MAX_SMI_DEVICE][MAX_MODE_TABLE_ENTRIES] =
+{
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    },
+    {
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+    }
+};
+#endif
+
+/* Static variable to store the mode information. */
+static mode_parameter_t gPrimaryCurrentModeParam[MAX_SMI_DEVICE];
+static mode_parameter_t gSecondaryCurrentModeParam[MAX_SMI_DEVICE];
+
+/*
+ *  getUserDataSignature
+ *      This function gets the user data mode signature
+ *
+ *  Output:
+ *      The signature to be filled in the user_data_mode_t structure to be considered
+ *      a valid structure.
+ */
+unsigned long getUserDataSignature(void)
+{
+    return MODE_USER_DATA_SIGNATURE;
+}
+
+/*
+ *  findModeParamFromTable
+ *      This function locates the requested mode in the given parameter table
+ *
+ *  Input:
+ *      width           - Mode width
+ *      height          - Mode height
+ *      refresh_rate    - Mode refresh rate
+ *      index           - Index that is used for multiple search of the same mode 
+ *                        that have the same width, height, and refresh rate, 
+ *                        but have different timing parameters.
+ *
+ *  Output:
+ *      Success: return a pointer to the mode_parameter_t entry.
+ *      Fail: a NULL pointer.
+ */
+mode_parameter_t *findModeParamFromTable(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index,
+    mode_parameter_t *pModeTable
+)
+{
+    unsigned short modeIndex = 0;
+#if 0
+    unsigned short tempIndex = 0;
+#endif
+    /* Walk the entire mode table. */    
+    while (pModeTable[modeIndex].pixel_clock != 0)
+    {
+        if (((width == (unsigned long)(-1)) || (pModeTable[modeIndex].horizontal_display_end == width)) &&
+            ((height == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_display_end == height)) &&
+            ((refresh_rate == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_frequency == refresh_rate)))
+        {
+#if 0
+            if (tempIndex < index)
+                tempIndex++;
+            else
+#endif
+            {
+                return (&pModeTable[modeIndex]);
+            }
+        }
+        
+        /* Next entry */
+        modeIndex++;
+    }
+
+    /* No match, return NULL pointer */
+    return((mode_parameter_t *)0);
+}
+
+/*
+ *  Locate in-stock parameter table for the requested mode.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *findModeParam(
+    disp_control_t dispCtrl,
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index
+)
+{
+    return findModeParamFromTable(width, height, refresh_rate, index, getStockModeParamTableEx(dispCtrl));
+}
+
+/*
+ *  Use the
+ *  Locate timing parameter for the requested mode from the default mode table.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *findVesaModeParam(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate
+)
+{
+	switch(ddk750_getChipType())
+	{
+		default: /* Normal SM750/SM718 */
+    		return findModeParamFromTable(width, height, refresh_rate, 0, gDefaultModeParamTable);
+	}
+}
+
+/*
+ * (Obsolete) 
+ * Return a point to the gDefaultModeParamTable.
+ * Function in other files used this to get the mode table pointer.
+ */
+mode_parameter_t *getStockModeParamTable(void)
+{
+	switch(ddk750_getChipType())
+	{
+		default:
+    		return (gDefaultModeParamTable);
+	}	
+}
+
+/*
+ * (Obsolete)
+ * Return the size of the Stock Mode Param Table
+ */
+unsigned long getStockModeParamTableSize(void)
+{
+
+    return (sizeof(gDefaultModeParamTable) / sizeof(mode_parameter_t) - 1);
+
+}
+
+/* 
+ *  getStockModeParamTableEx
+ *      This function gets the mode parameters table associated to the
+ *      display control (PRIMARY_CTRL or SECONDAR_CTRL).
+ *
+ *  Input:
+ *      dispCtrl    - Display Control of the mode table that is associated to.
+ *
+ *  Output:
+ *      Pointer to the mode table
+ */
+mode_parameter_t *getStockModeParamTableEx(
+    disp_control_t dispCtrl
+)
+{
+    mode_parameter_t *pModeTable;
+    pModeTable = getStockModeParamTable();
+#if 0 
+    if (dispCtrl == PRIMARY_CTRL)
+        pModeTable = (mode_parameter_t *)&gPrimaryModeParamTable[getCurrentDevice()];
+    else
+        pModeTable = (mode_parameter_t *)&gSecondaryModeParamTable[getCurrentDevice()];
+        
+    /* Check if the table exist by checking the first entry. 
+       If it doesn't, then use the default mode table. */
+    if (pModeTable->pixel_clock == 0)
+	{
+#if 1 /* Cheok_2013_0118 */
+		pModeTable = getStockModeParamTable();
+#else
+		if (ddk750_getChipType() == SM750LE)
+        	pModeTable = (mode_parameter_t *)&gSM750LEModeParamTable;
+		else
+        	pModeTable = (mode_parameter_t *)&gDefaultModeParamTable;
+#endif
+	}
+#endif   
+    return (pModeTable);
+}
+
+/*
+ *  getStockModeParamTableSizeEx
+ *      This function gets the size of the mode parameter table associated with
+ *      specific display control
+ *
+ *  Input:
+ *      dispCtrl    - Display control of the mode param table that is associated to.
+ *
+ *  Output:
+ *      Size of the requeted mode param table.
+ */
+unsigned long getStockModeParamTableSizeEx(
+    disp_control_t dispCtrl
+)
+{
+    unsigned long tableSize;
+    mode_parameter_t *pModeTable;
+    
+    /* Get the mode table */
+    pModeTable = getStockModeParamTableEx(dispCtrl);
+    
+    /* Calculate the table size by finding the end of table entry indicated by all zeroes. */    
+    tableSize = 0;
+    while (pModeTable[tableSize].pixel_clock != 0)
+        tableSize++;
+        
+    return tableSize;
+}
+
+
+/* 
+ * This function returns the current mode.
+ */
+mode_parameter_t getCurrentModeParam(
+    disp_control_t dispCtrl
+)
+{
+    if (dispCtrl == PRIMARY_CTRL)
+        return gPrimaryCurrentModeParam[getCurrentDevice()];
+    else
+        return gSecondaryCurrentModeParam[getCurrentDevice()];
+}
+
+/*
+ *  Convert the timing into possible SM750 timing.
+ *  If actual pixel clock is not equal to timing pixel clock.
+ *  other parameter like horizontal total and sync have to be changed.
+ *
+ *  Input: Pointer to a mode parameters.
+ *         Pointer to a an empty mode parameter structure to be filled.
+ *         Actual pixel clock generated by SMI hardware.
+ *
+ *  Output:
+ *      1) Fill up input structure mode_parameter_t with possible timing for SM750.
+ */
+long adjustModeParam(
+mode_parameter_t *pModeParam,/* Pointer to mode parameter */
+mode_parameter_t *pMode,     /* Pointer to mode parameter to be updated here */
+unsigned long ulPClk         /* real pixel clock feasible by SM750 */
+)
+{
+    unsigned long blank_width, sync_start, sync_width;
+
+    /* Sanity check */
+    if ( pModeParam == (mode_parameter_t *)0 ||
+         pMode      == (mode_parameter_t *)0 ||
+         ulPClk     == 0)
+    {
+        return -1;
+    }
+
+    /* Copy VESA mode into SM750 mode. */
+    *pMode = *pModeParam;
+
+    /* If it can generate the vesa required pixel clock, and there are a minimum of
+       24 pixel difference between the horizontal sync start and the horizontal display
+       end, then there is nothing to change */
+    if ((ulPClk == pModeParam->pixel_clock) && 
+        ((pModeParam->horizontal_sync_start - pModeParam->horizontal_display_end) > 24))
+        return 0;
+
+    pMode->pixel_clock = ulPClk; /* Update actual pixel clock into mode */
+
+    /* Calculate the sync percentages of the VESA mode. */
+    blank_width = pModeParam->horizontal_total - pModeParam->horizontal_display_end;
+    sync_start = roundedDiv((pModeParam->horizontal_sync_start -
+                       pModeParam->horizontal_display_end) * 100, blank_width);
+    sync_width = roundedDiv(pModeParam->horizontal_sync_width * 100, blank_width);
+
+     /* Calculate the horizontal total based on the actual pixel clock and VESA line frequency. */
+    pMode->horizontal_total = roundedDiv(pMode->pixel_clock,
+                                    pModeParam->horizontal_frequency);
+
+    /* Calculate the sync start and width based on the VESA percentages. */
+    blank_width = pMode->horizontal_total - pMode->horizontal_display_end;
+
+    if (ddk750_getChipType() == SM750)
+    {
+        unsigned long sync_adjustment;
+            
+        /* There is minimum delay of 22 pixels between the horizontal display end 
+           to the horizontal sync start. Therefore, the horizontal sync start value
+           needs to be adjusted if the value falls below 22 pixels.
+           The 22 pixels comes from the propagating delay from the CRT display to
+           all the 11 display pipes inside SM750. The factor of 2 is caused by the
+           double pixel support in SM750. The value used here is 24 to align to 
+           8 bit character width.
+         */
+        sync_adjustment = roundedDiv(blank_width * sync_start, 100);
+        if (sync_adjustment < 24)
+            sync_adjustment = 24;
+        pMode->horizontal_sync_start = pMode->horizontal_display_end + sync_adjustment;
+    
+        /* Check if the adjustment of the sync start will cause the sync width to go
+           over the horizontal total. If it is, then reduce the width instead of
+           changing the horizontal total.
+         */
+        /* Maximum value for sync width and back porch. */
+        sync_adjustment = blank_width - sync_adjustment;
+        pMode->horizontal_sync_width = roundedDiv(blank_width * sync_width, 100);
+        if (sync_adjustment <= pMode->horizontal_sync_width)
+            pMode->horizontal_sync_width = sync_adjustment/2;
+    }
+    else
+    {
+        /* SM718 does not have the above restriction. */
+        pMode->horizontal_sync_start = pMode->horizontal_display_end + roundedDiv(blank_width * sync_start, 100);
+        pMode->horizontal_sync_width = roundedDiv(blank_width * sync_width, 100);
+    }
+    
+    /* Calculate the line and screen frequencies. */
+    pMode->horizontal_frequency = roundedDiv(pMode->pixel_clock,
+                                        pMode->horizontal_total);
+    pMode->vertical_frequency = roundedDiv(pMode->horizontal_frequency,
+                                      pMode->vertical_total);
+    return 0;
+}
+
+
+/*
+ *	This function gets the display status
+ *
+ *	Input:
+ *		dispControl		- display control of which display status to be retrieved.
+ *
+ *  Output:
+ *      0   - Display is pending
+ *     -1   - Display is not pending
+ */
+long isCurrentDisplayPending(
+    disp_control_t dispControl
+)
+{
+    /* Get the display status */
+    if (dispControl == PRIMARY_CTRL)
+    {
+        if (FIELD_GET(peekRegisterDWord(PRIMARY_FB_ADDRESS), PRIMARY_FB_ADDRESS, STATUS) == PRIMARY_FB_ADDRESS_STATUS_PENDING)
+            return 0;
+    }
+	else if (dispControl == SECONDARY_CTRL)
+    {
+        if (FIELD_GET(peekRegisterDWord(SECONDARY_FB_ADDRESS), SECONDARY_FB_ADDRESS, STATUS) == SECONDARY_FB_ADDRESS_STATUS_PENDING)
+            return 0;
+    }
+
+    return (-1);
+}
+
+/*
+ *	This function sets the display base address
+ *
+ *	Input:
+ *		dispControl		- display control of which base address to be set.
+ *		ulBaseAddress	- Base Address value to be set.
+ */
+void setDisplayBaseAddress(
+	disp_control_t dispControl,
+	unsigned long ulBaseAddress
+)
+{
+	if (dispControl == PRIMARY_CTRL)
+	{
+		/* Frame buffer base for this mode */
+	    pokeRegisterDWord(PRIMARY_FB_ADDRESS,
+              FIELD_SET(0, PRIMARY_FB_ADDRESS, STATUS, PENDING)
+            | FIELD_SET(0, PRIMARY_FB_ADDRESS, EXT, LOCAL)
+            | FIELD_VALUE(0, PRIMARY_FB_ADDRESS, ADDRESS, ulBaseAddress));
+	}
+	else if (dispControl == SECONDARY_CTRL)
+	{
+        /* Frame buffer base for this mode */
+        pokeRegisterDWord(SECONDARY_FB_ADDRESS,
+              FIELD_SET(0, SECONDARY_FB_ADDRESS, STATUS, PENDING)
+            | FIELD_SET(0, SECONDARY_FB_ADDRESS, EXT, LOCAL)
+            | FIELD_VALUE(0, SECONDARY_FB_ADDRESS, ADDRESS, ulBaseAddress));
+	}
+}
+
+
+/* 
+ * Program the hardware for a specific video mode
+ */
+void programModeRegisters(
+mode_parameter_t *pModeParam,   /* mode information about pixel clock, horizontal total, etc. */
+unsigned long ulBpp,            /* Color depth for this mode */
+unsigned long ulBaseAddress,    /* Offset in frame buffer */
+unsigned long ulPitch,          /* Mode pitch value in byte: no of bytes between two lines. */
+pll_value_t *pPLL               /* Pre-calculated values for the PLL */
+)
+{
+    unsigned long ulTmpValue, ulReg, ulReservedBits;
+    unsigned long palette_ram;
+    unsigned long offset;
+	logical_chip_type_t chipType;
+
+    /* Enable display power gate */
+    ulTmpValue = peekRegisterDWord(CURRENT_GATE);
+    ulTmpValue = FIELD_SET(ulTmpValue, CURRENT_GATE, DISPLAY, ON);
+    setCurrentGate(ulTmpValue);
+
+    if (pPLL->clockType == SECONDARY_PLL)
+    {
+   // printk("func[%s], secondary reg, ulPitch=[%d]\n", __func__, ulPitch);
+        /* Secondary Display Control: SECONDARY_PLL */
+        pokeRegisterDWord(SECONDARY_PLL_CTRL, formatPllReg(pPLL)); 
+
+        /* Frame buffer base for this mode */
+        //setDisplayBaseAddress(SECONDARY_CTRL, ulBaseAddress);//move by ilena
+
+        /* Pitch value (Sometime, hardware people calls it Offset) */
+       // pokeRegisterDWord(SECONDARY_FB_WIDTH,
+         //     FIELD_VALUE(0, SECONDARY_FB_WIDTH, WIDTH, ulPitch)
+           // | FIELD_VALUE(0, SECONDARY_FB_WIDTH, OFFSET, ulPitch));
+
+        pokeRegisterDWord(SECONDARY_HORIZONTAL_TOTAL,
+              FIELD_VALUE(0, SECONDARY_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
+            | FIELD_VALUE(0, SECONDARY_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
+
+        pokeRegisterDWord(SECONDARY_HORIZONTAL_SYNC,
+              FIELD_VALUE(0, SECONDARY_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
+            | FIELD_VALUE(0, SECONDARY_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
+
+        pokeRegisterDWord(SECONDARY_VERTICAL_TOTAL,
+              FIELD_VALUE(0, SECONDARY_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
+            | FIELD_VALUE(0, SECONDARY_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
+
+        pokeRegisterDWord(SECONDARY_VERTICAL_SYNC,
+              FIELD_VALUE(0, SECONDARY_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
+            | FIELD_VALUE(0, SECONDARY_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
+
+        /* Set control register value */
+        ulTmpValue =        
+            (pModeParam->vertical_sync_polarity == POS
+            ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
+            : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
+          | (pModeParam->horizontal_sync_polarity == POS
+            ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
+            : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
+          | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, SELECT, SECONDARY)
+          | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, TIMING, ENABLE)
+          | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, PLANE, ENABLE) 
+          | (ulBpp == 8
+            ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 8)
+            : (ulBpp == 16
+            ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 16)
+            : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 32)));
+
+		chipType = ddk750_getChipType();
+
+		if (chipType == SM750 || chipType == SM718)
+        {
+            /* TODO: Check if the auto expansion bit can be cleared here */
+            ulReg = peekRegisterDWord(SECONDARY_DISPLAY_CTRL)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, VSYNC_PHASE)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, HSYNC_PHASE)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, SELECT)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, TIMING)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, PLANE)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, FORMAT)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, LOCK_TIMING)
+              & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, EXPANSION);
+
+            pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulTmpValue | ulReg);
+        }
+		
+
+        /* Palette RAM. */
+        palette_ram = SECONDARY_PALETTE_RAM;
+        
+        /* Save the current mode param */
+        gSecondaryCurrentModeParam[getCurrentDevice()] = *pModeParam;
+    }
+    else 
+    {
+        /* Primary display control clock: PRIMARY_PLL */
+        pokeRegisterDWord(PRIMARY_PLL_CTRL, formatPllReg(pPLL));
+
+        /* Program primary PLL, if applicable */
+        if (pPLL->clockType == PRIMARY_PLL)
+        {
+            pokeRegisterDWord(PRIMARY_PLL_CTRL, formatPllReg(pPLL));
+
+            /* Program to Non-VGA mode when using primary PLL */
+            pokeRegisterDWord(VGA_CONFIGURATION, 
+                FIELD_SET(peekRegisterDWord(VGA_CONFIGURATION), VGA_CONFIGURATION, PLL, PRIMARY));
+        }
+        
+        /* Frame buffer base for this mode */
+		//setDisplayBaseAddress(PRIMARY_CTRL, ulBaseAddress);// move by iena
+		//printk("func[%s], primary reg, ulPitch=[%d]\n", __func__, ulPitch);
+        /* Pitch value (Sometime, hardware people calls it Offset) */
+        //pokeRegisterDWord(PRIMARY_FB_WIDTH,
+          //    FIELD_VALUE(0, PRIMARY_FB_WIDTH, WIDTH, ulPitch)
+            //| FIELD_VALUE(0, PRIMARY_FB_WIDTH, OFFSET, ulPitch));
+
+        pokeRegisterDWord(PRIMARY_WINDOW_WIDTH,
+              FIELD_VALUE(0, PRIMARY_WINDOW_WIDTH, WIDTH, pModeParam->horizontal_display_end - 1)
+            | FIELD_VALUE(0, PRIMARY_WINDOW_WIDTH, X, 0));
+
+        pokeRegisterDWord(PRIMARY_WINDOW_HEIGHT,
+              FIELD_VALUE(0, PRIMARY_WINDOW_HEIGHT, HEIGHT, pModeParam->vertical_display_end - 1)
+            | FIELD_VALUE(0, PRIMARY_WINDOW_HEIGHT, Y, 0));
+
+        pokeRegisterDWord(PRIMARY_PLANE_TL,
+              FIELD_VALUE(0, PRIMARY_PLANE_TL, TOP, 0)
+            | FIELD_VALUE(0, PRIMARY_PLANE_TL, LEFT, 0));
+
+        pokeRegisterDWord(PRIMARY_PLANE_BR, 
+              FIELD_VALUE(0, PRIMARY_PLANE_BR, BOTTOM, pModeParam->vertical_display_end - 1)
+            | FIELD_VALUE(0, PRIMARY_PLANE_BR, RIGHT, pModeParam->horizontal_display_end - 1));
+
+        pokeRegisterDWord(PRIMARY_HORIZONTAL_TOTAL,
+              FIELD_VALUE(0, PRIMARY_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
+            | FIELD_VALUE(0, PRIMARY_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
+
+        pokeRegisterDWord(PRIMARY_HORIZONTAL_SYNC,
+              FIELD_VALUE(0, PRIMARY_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
+            | FIELD_VALUE(0, PRIMARY_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
+
+        pokeRegisterDWord(PRIMARY_VERTICAL_TOTAL,
+              FIELD_VALUE(0, PRIMARY_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
+            | FIELD_VALUE(0, PRIMARY_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
+
+        pokeRegisterDWord(PRIMARY_VERTICAL_SYNC,
+              FIELD_VALUE(0, PRIMARY_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
+            | FIELD_VALUE(0, PRIMARY_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
+
+        /* Set control register value */
+        ulTmpValue =
+            (pModeParam->clock_phase_polarity == POS
+            ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH)
+            : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW))
+          | (pModeParam->vertical_sync_polarity == POS
+            ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
+            : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
+          | (pModeParam->horizontal_sync_polarity == POS
+            ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
+            : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
+          | FIELD_SET(0, PRIMARY_DISPLAY_CTRL, TIMING, ENABLE)
+          | FIELD_SET(0, PRIMARY_DISPLAY_CTRL, PLANE, ENABLE)
+          | (ulBpp == 8
+            ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 8)
+            : (ulBpp == 16
+            ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 16)
+            : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 32)));
+
+        /* Added some masks to mask out the reserved bits. 
+         * Sometimes, the reserved bits are set/reset randomly when 
+         * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
+         * reserved bits are needed to be masked out.
+         */
+        ulReservedBits = FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
+                         FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
+                         FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE);
+
+        ulReg = (peekRegisterDWord(PRIMARY_DISPLAY_CTRL) & ~ulReservedBits)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, CLOCK_PHASE)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, VSYNC_PHASE)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, HSYNC_PHASE)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, TIMING)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, VERTICAL_PAN)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, HORIZONTAL_PAN)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, PLANE)
+              & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, FORMAT);
+
+        pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulTmpValue | ulReg);
+
+        /* 
+         * PRIMARY_DISPLAY_CTRL register seems requiring few writes
+         * before a value can be succesfully written in.
+         * Added some masks to mask out the reserved bits.
+         * Note: This problem happens by design. The hardware will wait for the
+         *       next vertical sync to turn on/off the plane.
+         */
+        while((peekRegisterDWord(PRIMARY_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg))
+        {
+            pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulTmpValue | ulReg);
+        }
+
+        /* Palette RAM */
+        palette_ram = PRIMARY_PALETTE_RAM;
+        
+        /* Save the current mode param */
+        gPrimaryCurrentModeParam[getCurrentDevice()] = *pModeParam;
+    }
+
+    /* In case of 8-bpp, fill palette */
+    if (ulBpp==8)
+    {
+        /* Start with RGB = 0,0,0. */
+        unsigned char red = 0, green = 0, blue = 0;
+        unsigned long gray = 0;
+        for (offset = 0; offset < 256 * 4; offset += 4)
+        {
+            /* Store current RGB value. */
+            pokeRegisterDWord(palette_ram + offset, gray
+                                ? RGB((gray + 50) / 100,
+                                      (gray + 50) / 100,
+                                      (gray + 50) / 100)
+                                : RGB(red, green, blue));
+
+            if (gray)
+            {
+                /* Walk through grays (40 in total). */
+                gray += 654;
+            }
+
+            else
+            {
+                /* Walk through colors (6 per base color). */
+                if (blue != 255)
+                {
+                    blue += 51;
+                }
+                else if (green != 255)
+                {
+                    blue = 0;
+                    green += 51;
+                }
+                else if (red != 255)
+                {
+                    green = blue = 0;
+                    red += 51;
+                }
+                else
+                {
+                    gray = 1;
+                }
+            }
+        }
+    }
+
+    /* For 16- and 32-bpp,  fill palette with gamma values. */
+    else
+    {
+        /* Start with RGB = 0,0,0. */
+        ulTmpValue = 0x000000;
+        for (offset = 0; offset < 256 * 4; offset += 4)
+        {
+            pokeRegisterDWord(palette_ram + offset, ulTmpValue);
+
+            /* Advance RGB by 1,1,1. */
+            ulTmpValue += 0x010101;
+        }
+    }
+}
+
+/* 
+ * This function gets the available clock type
+ *
+ */
+clock_type_t getClockType(disp_control_t dispCtrl)
+{
+    clock_type_t clockType;
+
+    switch (dispCtrl)
+    {
+        case PRIMARY_CTRL:
+            clockType = PRIMARY_PLL;
+            break;
+        default:
+        case SECONDARY_CTRL:
+            clockType = SECONDARY_PLL;
+            break;
+    }
+    return clockType;
+}
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution and bpp.
+ *     2) A user defined parameter table for the mode.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined Vesa parameter table (gDefaultModeParamTable) does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setCustomMode(
+	logicalMode_t *pLogicalMode, 
+	mode_parameter_t *pUserModeParam
+)
+{
+    mode_parameter_t pModeParam; /* physical parameters for the mode */
+    pll_value_t pll;
+    unsigned long ulActualPixelClk, ulTemp;
+
+    /*
+     * Minimum check on mode base address.
+     * At least it shouldn't be bigger than the size of frame buffer.
+     */
+    if (ddk750_getFrameBufSize() <= pLogicalMode->baseAddress)
+    	{printk("in func [%s], line[%d], return error\n", __func__, __LINE__);
+        return -1;
+    	}
+
+    /*
+     * Set up PLL, a structure to hold the value to be set in clocks.
+     */
+    pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */
+
+    /* Get the Clock Type */
+    pll.clockType = getClockType(pLogicalMode->dispCtrl);
+
+    /* 
+     * Call calcPllValue() to fill up the other fields for PLL structure.
+     * Sometime, the chip cannot set up the exact clock required by User.
+     * Return value from calcPllValue() gives the actual possible pixel clock.
+     */
+    ulActualPixelClk = calcPllValue(pUserModeParam->pixel_clock, &pll);
+    //DDKDEBUGPRINT((DISPLAY_LEVEL, "Actual Pixel Clock: %d\n", ulActualPixelClk));
+
+    /* 
+     * Adjust Vesa mode parameter to feasible mode parameter for SMI hardware.
+     */
+    if (adjustModeParam(pUserModeParam, &pModeParam, ulActualPixelClk) != 0 )
+    {
+    //printk("in func [%s], line[%d], return error\n", __func__, __LINE__);
+        return -1;
+    }
+
+    /* If calling function don't have a preferred pitch value, 
+       work out a 16 byte aligned pitch value.
+    */	
+    //printk("func[%s], ulPitch=[%d]\n", __func__, pLogicalMode->pitch);
+    if (pLogicalMode->pitch <= 0)
+    {
+        /* 
+         * Pitch value calculation in Bytes.
+         * Usually, it is (screen width) * (byte per pixel).
+         * However, there are cases that screen width is not 16 pixel aligned, which is
+         * a requirement for some OS and the hardware itself.
+         * For standard 4:3 resolutions: 320, 640, 800, 1024 and 1280, they are all
+         * 16 pixel aligned and pitch is simply (screen width) * (byte per pixel).
+         *   
+         * However, 1366 resolution, for example, has to be adjusted for 16 pixel aligned.
+         */
+
+        ulTemp = (pLogicalMode->x + 15) & ~15; /* This calculation has no effect on 640, 800, 1024 and 1280. */
+        pLogicalMode->pitch = ulTemp * (pLogicalMode->bpp / 8);
+    }
+	//printk("func[%s], ulPitch=[%d]\n", __func__, pLogicalMode->pitch);
+
+    /* Program the hardware to set up the mode. */
+    programModeRegisters( 
+        &pModeParam,
+        pLogicalMode->bpp, 
+        pLogicalMode->baseAddress, 
+        pLogicalMode->pitch, 
+        &pll);
+        
+    return (0);
+}
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution, bpp, xLCD, and yLCD.
+ *     2) A user defined parameter table for the mode.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode and scale the mode if necessary.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined parameter table does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setCustomModeEx(
+	logicalMode_t *pLogicalMode, 
+	mode_parameter_t *pUserModeParam
+)
+{
+    long returnValue = 0;
+
+#if 0   /* userData field is used on DDK version 1.1 and above. Thereofre, this checking is
+           not needed anymore. */
+    /* For the current DDK version, the userData needs to be set to 0. If not, then return error. */
+    if (pLogicalMode->userData != (void *)0)
+        return (-1);
+#endif
+
+    /* Return error when the mode is bigger than the panel size. Might be temporary solution
+       depending whether we will support panning or not. */
+    if (((pLogicalMode->xLCD != 0) && 
+         (pLogicalMode->yLCD != 0)) &&
+        ((pLogicalMode->xLCD < pLogicalMode->x) ||
+         (pLogicalMode->yLCD < pLogicalMode->y)))
+    	{
+    	//printk("in func [%s], line[%d], return error\n", __func__, __LINE__);
+        return (-1);
+    	}
+    
+    /* Return error when the panel size exceed the maximum mode that we can support. */
+    if ((pLogicalMode->xLCD > MAX_PANEL_SIZE_WIDTH) ||
+        (pLogicalMode->yLCD > MAX_PANEL_SIZE_HEIGHT))
+    	{
+    	//printk("in func [%s], line[%d], return error\n", __func__, __LINE__);
+        return (-1);    /* Unsupported panel size. */
+    	}
+    
+    /* Set the mode first */
+    returnValue = setCustomMode(pLogicalMode, pUserModeParam);
+
+    
+    return (returnValue);
+}
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution, bpp, 
+ * xLCD and yLCD. The main difference between setMode and setModeEx are
+ * these two parameters (xLCD and yLCD). Use this setModeEx API to set
+ * expansion while setMode API for regular setmode without any expansion.
+ * Refer to MODE.h for the details.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setModeEx(
+	logicalMode_t *pLogicalMode
+)
+{
+    mode_parameter_t *pModeParam;       /* physical parameters for the mode */
+    unsigned short index = 0;
+    unsigned long modeWidth, modeHeight;
+    userData_t *pUserData;
+    
+    /* Conditions to set the mode when scaling is needed (xLCD and yLCD is not zeroes)
+     *      1. PRIMARY_CTRL
+     *          a. Set the primary display control timing to the actual display mode.
+     *          b. Set the secondary display control timing to the mode that equals to
+     *             the panel size.
+     *      2. SECONDARY_CTRL
+     *          a. Set the secondary display control timing to the mode that equals to
+     *             the panel size.
+     */
+    if ((pLogicalMode->dispCtrl == SECONDARY_CTRL) &&
+        (pLogicalMode->xLCD != 0) && (pLogicalMode->yLCD != 0))
+    {
+        modeWidth = pLogicalMode->xLCD;
+        modeHeight = pLogicalMode->yLCD;
+    }
+    else
+    {
+        modeWidth = pLogicalMode->x;
+        modeHeight = pLogicalMode->y;
+    }
+    
+    /*
+     * Check the validity of the userData pointer and translate the information as necessary
+     */
+    pUserData = (userData_t *)pLogicalMode->userData;
+    if ((pUserData != (userData_t *)0) &&
+        (pUserData->signature == getUserDataSignature()) &&
+        (pUserData->size == sizeof(userData_t)))
+    {
+        /* Interpret the userData information */
+        if (pUserData->paramList.size == sizeof(userDataParam_t))
+        {
+            if (pUserData->paramList.modeInfoID == MODE_INFO_INDEX)
+                index = pUserData->paramList.paramInfo.index;
+        }
+    }
+    
+    /* 
+     * Check if we already have physical timing parameter for this mode.
+     */
+  //   printk("fine ctrl=[%d], width[%d](x=[%d]), height[%d], hz[%d], index[%d], disp=[%d]\n", pLogicalMode->dispCtrl, modeWidth,pLogicalMode->x,modeHeight, pLogicalMode->hz, index,pLogicalMode->dispCtrl);
+    pModeParam = findModeParam(pLogicalMode->dispCtrl, modeWidth, modeHeight, pLogicalMode->hz, index);
+    if (pModeParam == (mode_parameter_t *)0)
+    	{
+    	//printk("in func [%s], line[%d], return error\n", __func__, __LINE__);
+        return -1;
+    	}
+
+    return(setCustomModeEx(pLogicalMode, pModeParam));
+}
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp.
+ * Refer to MODE.h for the details.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setMode(
+	logicalMode_t *pLogicalMode
+)
+{
+    /* Initialize the panel size to 0 */
+    pLogicalMode->xLCD = 0;
+    pLogicalMode->yLCD = 0;
+    pLogicalMode->userData = (void *)0;
+
+    /* Call the setModeEx to set the mode. */
+    return setModeEx(pLogicalMode);
+}
+
+/*
+ *  setInterpolation
+ *      This function enables/disables the horizontal and vertical interpolation
+ *      for the secondary display control. Primary display control does not have
+ *      this capability.
+ *
+ *  Input:
+ *      enableHorzInterpolation - Flag to enable/disable Horizontal interpolation
+ *      enableVertInterpolation - Flag to enable/disable Vertical interpolation
+ */
+void setInterpolation(
+    unsigned long enableHorzInterpolation,
+    unsigned long enableVertInterpolation
+)
+{
+    unsigned long value;
+
+    value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL);
+    
+    if (enableHorzInterpolation)
+        value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, HORIZONTAL_MODE, INTERPOLATE);
+    else
+        value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, HORIZONTAL_MODE, REPLICATE);
+        
+    if (enableVertInterpolation)
+        value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, VERTICAL_MODE, INTERPOLATE);
+    else
+        value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, VERTICAL_MODE, REPLICATE);
+        
+    pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, value);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.h
new file mode 100644
index 000000000000..0430a6b0ca74
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_mode.h
@@ -0,0 +1,565 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  MODE.H --- SMI DDK 
+*  This file contains the definitions for the mode tables.
+* 
+*******************************************************************/
+#ifndef _MODE_H_
+#define _MODE_H_
+
+/* Maximum parameters those can be saved in the mode table. */
+#define MAX_MODE_TABLE_ENTRIES              60
+
+/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the
+   modeext to compare timing will not work. */
+#pragma pack(1)
+
+typedef enum _spolarity_t
+{
+    POS, /* positive */
+    NEG, /* negative */
+}
+spolarity_t;
+
+typedef struct _mode_parameter_t
+{
+    /* Horizontal timing. */
+    unsigned long horizontal_total;
+    unsigned long horizontal_display_end;
+    unsigned long horizontal_sync_start;
+    unsigned long horizontal_sync_width;
+    spolarity_t horizontal_sync_polarity;
+
+    /* Vertical timing. */
+    unsigned long vertical_total;
+    unsigned long vertical_display_end;
+    unsigned long vertical_sync_start;
+    unsigned long vertical_sync_height;
+    spolarity_t vertical_sync_polarity;
+
+    /* Refresh timing. */
+    unsigned long pixel_clock;
+    unsigned long horizontal_frequency;
+    unsigned long vertical_frequency;
+    
+    /* Clock Phase. This clock phase only applies to Panel. */
+    spolarity_t clock_phase_polarity;
+}
+mode_parameter_t;
+
+typedef enum _disp_control_t
+{
+    PRIMARY_CTRL = 0,
+    SECONDARY_CTRL   = 1,
+#if 0    
+    VGA_CTRL   = 2
+#endif
+}
+disp_control_t;
+
+typedef struct _logicalMode_t
+{
+    unsigned long x;            /* X resolution */
+    unsigned long y;            /* Y resolution */
+    unsigned long bpp;          /* Bits per pixel */
+    unsigned long hz;           /* Refresh rate */
+
+    unsigned long baseAddress;  /* Offset from beginning of frame buffer.
+                                   It is used to control the starting location of a mode.
+                                   Calling function must initialize this field.
+                                 */
+
+    unsigned long pitch;        /* Mode pitch in byte.
+                                   If initialized to 0, setMode function will set
+                                   up this field.
+                                   If not zero, setMode function will use this value.
+                                 */
+	unsigned long  valid_edid;
+    disp_control_t dispCtrl;    /* SECONDARY or PRIMARY display control channel */
+    
+    /* These two parameters are used in the setModeEx. */
+    unsigned long xLCD;         /* Panel width */
+    unsigned long yLCD;         /* Panel height */
+    
+    void *userData;             /* Not used now, set it to 0 (for future used only) */
+}
+logicalMode_t;
+
+/*
+ * ID of the modeInfoID used in the userDataParam_t
+ */
+#define MODE_INFO_INDEX         0x01
+
+typedef struct _userDataParam_t
+{
+    unsigned long size;         /* Size of this parameter */
+    unsigned char modeInfoID;   /* Mode information ID */
+    
+    /* As the modeInfoID might be expanded in the future to support more stuffs as necessary, 
+       the following parameter list might be expanded in the future. */
+    union
+    {
+        unsigned char index;    /* The index of the mode timing of the given resolution:
+                                        0   - The first mode timing found in the table
+                                        1   - The second mode timing found in the table
+                                        etc...
+                                 */
+        /* Add more user data information parameters here as necessary. */
+    } paramInfo;
+} userDataParam_t;
+
+/* 
+ * Structure that is used as userData pointer in the logicalMode_t 
+ */
+typedef struct _userData_t
+{
+    unsigned long signature;    /* Signature of the userData pointer. 
+                                   It has to be filled with user data Signature to be a valid
+                                   structure pointer. The signature can be obtained by
+                                   calling getUserDataSignature function.
+                                 */
+    unsigned long size;         /* Size of this data structure. */
+    userDataParam_t paramList;  /* List of parameters those are associated with this userData 
+                                   Currently, only one modeInfoID is supported. Later on, when
+                                   the ID is expanded, then the paramList might be expanded
+                                   as an array. */
+} 
+userData_t;
+
+/* Restore alignment */
+#pragma pack()
+
+/*
+ *  getUserDataSignature
+ *      This function gets the user data mode signature
+ *
+ *  Output:
+ *      The signature to be filled in the user_data_mode_t structure to be considered
+ *      a valid structure.
+ */
+unsigned long getUserDataSignature(void);
+
+/*
+ *  compareModeParam
+ *      This function compares two mode parameters
+ *
+ *  Input:
+ *      pModeParam1 - Pointer to the first mode parameter to be compared
+ *      pModeParam2 - Pointer to the second mode parameter to be compared
+ *
+ *  Output:
+ *      0   - Identical mode
+ *     -1   - Mode is not identical
+ */
+long compareModeParam(
+    mode_parameter_t *pModeParam1,
+    mode_parameter_t *pModeParam2
+);
+
+/*
+ *  getDuplicateModeIndex
+ *      This function retrieves the index of dupicate modes, but having different timing.
+ *
+ *  Input:
+ *      dispCtrl    - Display Control where the mode table belongs to.
+ *      pModeParam  - The mode parameters which index to be checked.
+ *
+ *  Output:
+ *      0xFFFF  - The mode parameter can not be found in the current mode table
+ *      Other   - The index of the given parameters among the duplicate modes.
+ *                0 means that the mode param is the first mode encountered in the table
+ *                1 means that the mode param is the second mode encountered in the table
+ *                etc...
+ */
+unsigned short getDuplicateModeIndex(
+    disp_control_t dispCtrl,
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *  findModeParamFromTable
+ *      This function locates the requested mode in the given parameter table
+ *
+ *  Input:
+ *      width           - Mode width
+ *      height          - Mode height
+ *      refresh_rate    - Mode refresh rate
+ *      index           - Index that is used for multiple search of the same mode 
+ *                        that have the same width, height, and refresh rate, 
+ *                        but have different timing parameters.
+ *
+ *  Output:
+ *      Success: return a pointer to the mode_parameter_t entry.
+ *      Fail: a NULL pointer.
+ */
+mode_parameter_t *findModeParamFromTable(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index,
+    mode_parameter_t *pModeTable
+);
+
+/*
+ *  Locate in-stock parameter table for the requested mode.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *findModeParam(
+    disp_control_t dispCtrl,
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index
+);
+
+/*
+ *  (Obsolete) --> replace by findModeParam
+ *  Locate in-stock parameter table for the requested mode.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *findVesaModeParam(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate
+);
+
+/* 
+ * Return a point to the gModeParamTable.
+ * Function in other files used this to get the mode table pointer.
+ */
+mode_parameter_t *getStockModeParamTable(void);
+
+/*
+ * Return the size of the Stock Mode Param Table
+ */
+unsigned long getStockModeParamTableSize(void);
+
+/* 
+ *  getStockModeParamTableEx
+ *      This function gets the mode parameters table associated to the
+ *      display control (PRIMARY_CTRL or SECONDAR_CTRL).
+ *
+ *  Input:
+ *      dispCtrl    - Display Control of the mode table that is associated to.
+ *
+ *  Output:
+ *      Pointer to the mode table
+ */
+mode_parameter_t *getStockModeParamTableEx(
+    disp_control_t dispCtrl
+);
+
+/*
+ *  getStockModeParamTableSizeEx
+ *      This function gets the size of the mode parameter table associated with
+ *      specific display control
+ *
+ *  Input:
+ *      dispCtrl    - Display control of the mode param table that is associated to.
+ *
+ *  Output:
+ *      Size of the requeted mode param table.
+ */
+unsigned long getStockModeParamTableSizeEx(
+    disp_control_t dispCtrl
+);
+
+/* 
+ * This function returns the current mode.
+ */
+mode_parameter_t getCurrentModeParam(
+    disp_control_t dispCtrl
+);
+
+/*
+ *  getMaximumModeEntries
+ *      This function gets the maximum entries that can be stored in the mode table.
+ *
+ *  Output:
+ *      Total number of maximum entries
+ */
+unsigned long getMaximumModeEntries(void);
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution and bpp.
+ *     2) A user defined parameter table for the mode.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined Vesa parameter table (gModeParamTable) does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setCustomMode(
+    logicalMode_t *pLogicalMode, 
+    mode_parameter_t *pUserModeParam
+);
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution, bpp, xLCD, and yLCD.
+ *     2) A user defined parameter table for the mode.
+ *
+ * Similar like setCustomMode, this function calculate and programs the hardware 
+ * to set up the requested mode and also scale the mode if necessary.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined Vesa parameter table (gModeParamTable) does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setCustomModeEx(
+    logicalMode_t *pLogicalMode, 
+    mode_parameter_t *pUserModeParam
+);
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp.
+ * Refer to MODE.h for the details.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setMode(
+    logicalMode_t *pLogicalMode
+);
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution, bpp, 
+ * xLCD and yLCD. The main difference between setMode and setModeEx are
+ * the xLCD and yLCD parameters. Use this setModeEx API to set the mode
+ * and enable expansion. setMode API does not support expansion.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long setModeEx(
+    logicalMode_t *pLogicalMode
+);
+
+
+/*
+ *  setInterpolation
+ *      This function enables/disables the horizontal and vertical interpolation
+ *      for the secondary display control. Primary display control does not have
+ *      this capability.
+ *
+ *  Input:
+ *      enableHorzInterpolation - Flag to enable/disable Horizontal interpolation
+ *      enableVertInterpolation - Flag to enable/disable Vertical interpolation
+ */
+void setInterpolation(
+    unsigned long enableHorzInterpolation,
+    unsigned long enableVertInterpolation
+);
+
+/***********************************************************************************
+ *
+ *  The following function prototypes are the extension of mode.c where it involves
+ *  EDID, GTF, and others calculation. Please include modeext.c to use these
+ *  functions.
+ *
+ ***********************************************************************************/
+
+/*
+ *  registerEdidTiming
+ *      This function registers timing from EDID, LCD Monitor Timing Extension,
+ *      Standard Timing Extension, etc...
+ *
+ *  Input:
+ *      dispCtrl            - Display control where the mode will be associated to
+ *      pEDIDBuffer         - Pointer to the display device's EDID Buffer
+ *      pLCDTimingExt       - Pointer to LCD Monitor Timing Extension (currently is not supported)
+ *      pStdTimingExt       - Pointer to Standard Timing extension (currently is not supported)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long registerEdidTiming(
+    disp_control_t dispCtrl,
+    unsigned char *pEDIDBuffer,
+    unsigned char *pLCDTimingExt,
+    unsigned char *pStdTimingExt
+);
+
+/*
+ *  calculateGtfTiming
+ *      This function calculate the GTF Timing and produce the SM750 mode parameter
+ *      format
+ *
+ *  Input:
+ *      width               - Mode Width
+ *      height              - Mode Height
+ *      refreshRate         - Mode Refresh Rate
+ *      pModeParam          - Pointer to SM750 mode parameter format variable to store
+ *                            the calculated value of the GTF
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long calculateDefaultGtfTiming(
+    unsigned long width,
+    unsigned long height,
+    unsigned long refreshRate,
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *  calculateGtfTiming
+ *      This function calculate the GTF Timing and produce the SM750 mode parameter
+ *      format
+ *
+ *  Input:
+ *      width               - Mode Width
+ *      height              - Mode Height
+ *      refreshRate         - Mode Refresh Rate
+ *      pModeParam          - Pointer to SM750 mode parameter format variable to store
+ *                            the calculated value of the GTF
+ *      offset              - The value of GTF Offset parameter
+ *      gradient            - The value of GTF Gradient parameter
+ *      scalingFactor       - The value of the GTF scaling factor parameter
+ *      scalingFactorWeight - The value of the GTF scaling Factor Weight parameter
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long calculateGtfTiming(
+    unsigned long width,
+    unsigned long height,
+    unsigned long refreshRate,
+    mode_parameter_t *pModeParam,
+    unsigned char offset,
+    unsigned short gradient,
+    unsigned char scalingFactor,
+    unsigned char scalingFactorWeight
+    
+);
+
+/*
+ *  isDefaultGtfTiming
+ *      Check if the given timing is default GTF timing. 
+ *      Default here means it uses the following configuration to calculate the timing:
+ *          Offset (C) = 40%
+ *          Gradient (M) = 600%/kHz
+ *          Scaling Factor (K) = 128
+ *          Weighted Scaling Factor (J) = 20%
+ *
+ *  Input:
+ *      pModeParam  - Mode Parameter that will be checked whether is default GTF or not
+ *
+ *  Output:
+ *      0       - Indicates that the given mode parameter is a NOT a default GTF Timing
+ *      Other   - Indicates that the given mode parameter is a default GTF Timing
+ */
+long isDefaultGtfTiming(
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *  isSecondaryGtfTiming
+ *      Check if the given timing is the secondary GTF timing calculated based on the
+ *      given offset (C), gradient (M), scaling factor (K), and weighted scaling factor (J). 
+ *
+ *  Input:
+ *      pModeParam          - Mode Parameter that will be checked whether is secondary GTF or not
+ *      offset              - Blanking formula offset used to calculate the secondary GTF mode param.
+ *      gradient            - Blanking formula gradient used to calculate the secondary GTF 
+ *                            mode param.
+ *      scalingFactor       - Blanking formula scaling factor used to calculate the secondary 
+ *                            GTF mode param
+ *      scalingFactorWeight - Blanking formula scaling factor weighting used to calculate the
+ *                            secondary GTF mode param
+ *
+ *  Output:
+ *      0       - Indicates that the given mode parameter is NOT a default GTF Timing
+ *      Other   - Indicates that the given mode parameter is a default GTF Timing
+ */
+long isSecondaryGtfTiming(
+    mode_parameter_t *pModeParam,
+    unsigned char offset,
+    unsigned short gradient,
+    unsigned char scalingFactor,
+    unsigned char scalingFactorWeight
+);
+
+/*
+ *  isVesaTiming
+ *      Check if the given timing is the VESA Discrete Monitor Timing Standard. 
+ *
+ *  Input:
+ *      pModeParam  - Mode Parameter that will be checked whether is VESA Timing or not
+ *
+ *  Output:
+ *      0       - Indicates that the given mode parameter is NOT a VESA DMT Timing
+ *      Other   - Indicates that the given mode parameter is a VESA DMT Timing
+ */
+long isVesaTiming(
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *  isEdidPreferredTiming
+ *      Check if the given timing is the EDID preferred timing. 
+ *
+ *  Input:
+ *      pEDIDBuffer - Pointer to an EDID Buffer. 
+ *      pModeParam  - Mode Parameter that will be checked whether is EDID
+ *                    preferred timing or not.
+ *
+ *  Output:
+ *     >0   - Indicates that the given mode parameter is a default GTF Timing
+ *      0   - Indicates that the given mode parameter is NOT a default GTF Timing
+ */
+long isEdidPreferredTiming(
+    unsigned char *pEDIDBuffer,
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *	This function sets the display base address
+ *
+ *	Input:
+ *		dispControl		- display control of which base address to be set.
+ *		ulBaseAddress	- Base Address value to be set.
+ */
+void setDisplayBaseAddress(
+	disp_control_t dispControl,
+	unsigned long ulBaseAddress
+);
+
+/*
+ *	This function gets the display status
+ *
+ *	Input:
+ *		dispControl		- display control of which display status to be retrieved.
+ *
+ *  Output:
+ *      0   - Display is pending
+ *     -1   - Display is not pending
+ */
+long isCurrentDisplayPending(
+    disp_control_t dispControl
+);
+
+#endif /* _MODE_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_power.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_power.c
new file mode 100644
index 000000000000..5f3317b216d7
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_power.c
@@ -0,0 +1,495 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  power.c --- Voyager GX SDK 
+*  This file contains the source code for the power functions.
+* 
+*******************************************************************/
+#include "ddk750_defs.h"
+#include "ddk750_chip.h"
+#include "ddk750_clock.h"
+#include "ddk750_hardware.h"
+#include "ddk750_power.h"
+#include "ddk750_help.h"
+
+//#include "ddkdebug.h"
+
+/* Semaphore Counter for Bus Master Enable Bit */
+unsigned long g_ulBusMasterSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0};
+unsigned long g_ulPCISlaveBurstWriteSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0};
+unsigned long g_ulPCISlaveBurstReadSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0};
+
+/* Set DPMS state */
+void setDPMS(DPMS_t state)
+{
+    unsigned long value;
+
+    //if(ddk750_getChipType() == SM750LE)
+    if(ddk750_getChipType() >= SM750LE)
+    {
+        value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL);
+        switch (state)
+        {
+        case DPMS_ON:
+            value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 0);
+            break;
+
+        case DPMS_STANDBY:
+            value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 1);
+            break;
+
+        case DPMS_SUSPEND:
+            value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 2);
+            break;
+
+        case DPMS_OFF:
+            value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 3);
+            break;
+        }
+
+        pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, value);
+        return;
+    }
+
+    value = peekRegisterDWord(SYSTEM_CTRL);
+    switch (state)
+    {
+       case DPMS_ON:
+        value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHP);
+        break;
+
+       case DPMS_STANDBY:
+        value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHN);
+        break;
+
+       case DPMS_SUSPEND:
+        value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHP);
+        break;
+
+       case DPMS_OFF:
+        value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHN);
+        break;
+    }
+
+    pokeRegisterDWord(SYSTEM_CTRL, value);
+}
+
+/*
+ * This function gets the power mode, one of three modes: 0, 1 or Sleep.
+ * On hardware reset, power mode 0 is default.
+ */
+unsigned long getPowerMode()
+{
+
+    return (FIELD_GET(peekRegisterDWord(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE));
+}
+
+/*
+ * SM750/SM718 can operate in one of three modes: 0, 1 or Sleep.
+ * On hardware reset, power mode 0 is default.
+ */
+void setPowerMode(unsigned long powerMode)
+{
+    unsigned long control_value = 0, previousPowerState;
+
+    /* Get the current power mode ctrl register value and save it 
+       before switching the power mode. */
+    control_value = peekRegisterDWord(POWER_MODE_CTRL);
+    previousPowerState = FIELD_GET(control_value, POWER_MODE_CTRL, MODE);
+
+    /* Set the power mode to the requested power mode. */
+    switch (powerMode)
+    {
+        case 0:
+            control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0);
+            break;
+
+        case 1:
+            control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1);
+            break;
+
+        case 2:
+            control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP);
+            break;
+
+        default:
+            break;
+    }
+
+#if 0   /* These routines are removed since turning off the oscillator during sleep
+           will require the software to reset the frame buffer memory. 
+         */
+    /* Set up other fields in Power Control Register */
+    if (powerMode == POWER_MODE_CTRL_MODE_SLEEP)
+        control_value = FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, OFF);
+    else
+        control_value = FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, ON);
+#endif
+
+    /* Program new power mode. */
+    pokeRegisterDWord(POWER_MODE_CTRL, control_value);
+    
+    /* In SM718, the chip needs to wait until wake up from the sleep mode and wait for
+       a few milliseconds before reseting the memory and resume the normal operation. */
+    if ((powerMode != 2) && (previousPowerState != FIELD_GET(control_value, POWER_MODE_CTRL, MODE)))
+    {
+        /* Switching power mode between power mode 0 and 1 */
+        
+        /* Need a minimum of 16ms between power mode switching */
+        waitMasterClock(16);
+        
+        /* Reset Memory. */
+        ddk750_resetFrameBufferMemory();
+    }
+}
+
+void setCurrentGate(unsigned long gate)
+{
+    unsigned long gate_reg;
+    unsigned long mode;
+
+    /* Get current power mode. */
+    mode = getPowerMode();
+
+    switch (mode)
+    {
+        case POWER_MODE_CTRL_MODE_MODE0:
+            gate_reg = MODE0_GATE;
+            break;
+
+        case POWER_MODE_CTRL_MODE_MODE1:
+            gate_reg = MODE1_GATE;
+            break;
+
+        default:
+            gate_reg = MODE0_GATE;
+            break;
+    }
+    pokeRegisterDWord(gate_reg, gate);
+}
+
+/*
+ * This function enable/disable Bus Master
+ */
+void enableBusMaster(unsigned long enable)
+{
+    unsigned long busMasterCounter, value;
+
+    /* Enable Bus Master as necessary.*/
+	busMasterCounter = g_ulBusMasterSemaphoreCounter[getCurrentDevice()];
+	value = peekRegisterDWord(SYSTEM_CTRL);
+
+    /* Currently, only SM718 needs to enable the Bus Master enable bit. 
+       The Bus Master in SM750 is enabled by default, without programming any bits. */
+    if (enable)
+    {
+        if ((ddk750_getChipType() == SM718) && (busMasterCounter == 0))        
+            pokeRegisterDWord(SYSTEM_CTRL, FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_MASTER, ON));
+        
+        busMasterCounter++;
+    }
+    else
+    {
+        if (busMasterCounter > 0)
+            busMasterCounter--;
+        
+        if ((ddk750_getChipType() == SM718) && (busMasterCounter == 0))
+            pokeRegisterDWord(SYSTEM_CTRL, FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_MASTER, OFF));
+    }
+
+    g_ulBusMasterSemaphoreCounter[getCurrentDevice()] = busMasterCounter;
+}
+
+/* 
+ *	setPCIMasterBaseAddress
+ *		This function set the PCI Master Base Address (used by bus master or DMA).
+ *
+ *	Input:	
+ *		physicalSystemMemAddress	- System physical memory address which PCI
+ *									  Master Base Address to be set to.
+ *
+ *	Output:
+ *		The memory address to be set in the register.  
+ */
+unsigned long setPCIMasterBaseAddress(
+	unsigned long physicalSystemMemAddress
+)
+{
+	unsigned long pciMasterBaseAddress, remainingAddress;
+
+    /* Set PCI Master Base Address */
+    if (ddk750_getChipType() == SM750)
+    {
+#ifdef SM750_AA
+        pciMasterBaseAddress = ((physicalSystemMemAddress & 0xFFF00000) >> 23) << 3;
+        pokeRegisterDWord(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+        
+        /* This errata only applies to System Memory. For local to local, no correction is
+           needed. */
+        remainingAddress = ((physicalSystemMemAddress & 0x00700000) << 3) + (physicalSystemMemAddress & 0x000FFFFF);
+#else
+        pciMasterBaseAddress = physicalSystemMemAddress >> 23;
+        pciMasterBaseAddress = (pciMasterBaseAddress > 0xFF) ? 0xFF : pciMasterBaseAddress;
+        pokeRegisterDWord(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+        remainingAddress = physicalSystemMemAddress - (pciMasterBaseAddress << 23);
+#endif
+    }
+    else
+    {
+        pciMasterBaseAddress = physicalSystemMemAddress & 0xFFF00000;
+        pokeRegisterDWord(SM718_PCI_MASTER_BASE, FIELD_VALUE(0, SM718_PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+        remainingAddress = physicalSystemMemAddress - pciMasterBaseAddress;
+    }
+
+    //DDKDEBUGPRINT((DMA_LEVEL, "pciMasterBaseAddress: %x\n", pciMasterBaseAddress));
+
+	/* Send back the remaining address */
+    return remainingAddress;
+}
+
+/*
+ * 	This function enable/disable PCI Slave Burst Write provided the CPU supports Write Combine.
+ *
+ *	Input:
+ *			enable		- Enable/Disable the PCI Slave Burst Write (0 = disable, 1 = enable)
+ */
+void enablePCISlaveBurstWrite(
+	unsigned long enable
+)
+{
+	unsigned long pciSlaveBurstWriteCounter, value;
+
+    /* Enable PCI Slave Burst Write */
+	pciSlaveBurstWriteCounter = g_ulPCISlaveBurstWriteSemaphoreCounter[getCurrentDevice()];
+	value = peekRegisterDWord(SYSTEM_CTRL);
+
+    if (enable != 0)
+    {
+        if ((ddk750_getChipType() == SM718) && (pciSlaveBurstWriteCounter == 0))
+		{
+			/* Enable PCI Slave Burst Write. */
+			value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON); 
+			pokeRegisterDWord(SYSTEM_CTRL, value);
+        }
+
+        pciSlaveBurstWriteCounter++;
+    }
+    else
+    {
+        if (pciSlaveBurstWriteCounter > 0)
+            pciSlaveBurstWriteCounter--;
+        
+        if ((ddk750_getChipType() == SM718) && (pciSlaveBurstWriteCounter == 0))
+		{
+			/* Disable PCI Slave Burst Write */
+			value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, OFF); 
+			pokeRegisterDWord(SYSTEM_CTRL, value);
+		}
+    }
+
+	g_ulPCISlaveBurstWriteSemaphoreCounter[getCurrentDevice()] = pciSlaveBurstWriteCounter;
+}
+
+/*
+ * 	This function enable/disable PCI Slave Burst Read provided the CPU supports it.
+ *
+ *	Input:
+ *			enable			- Enable/Disable the PCI Slave Burst Read (0 = disable, 1 = enable)
+ *			burstReadSize	- Burst Read Size in 32-words (valid values are 1, 2, 4, and 8)
+ */
+void enablePCISlaveBurstRead(
+	unsigned long enable,
+	unsigned long burstReadSize
+)
+{
+	unsigned long pciSlaveBurstReadCounter, value;
+
+    /* Currently, only SM718 needs to enable the Bus Master enable bit. 
+       The Bus Master in SM750 is enabled by default, without programming any bits. */
+	pciSlaveBurstReadCounter = g_ulPCISlaveBurstReadSemaphoreCounter[getCurrentDevice()];
+	value = peekRegisterDWord(SYSTEM_CTRL);
+
+    if (enable != 0)
+    {
+        if ((ddk750_getChipType() == SM718) && (pciSlaveBurstReadCounter == 0))
+		{
+			value = peekRegisterDWord(SYSTEM_CTRL);
+
+			/* Enable PCI Slave Burst Read. */
+			value = FIELD_SET(value, SYSTEM_CTRL, PCI_BURST_READ, ON); 
+
+			/* Set the Read Size */
+			switch(burstReadSize)
+			{
+				case 1:
+					value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 1);
+					break;
+				case 2:
+					value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 2);
+					break;
+				case 4:
+					value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 4);
+					break;
+				default:
+				case 8:
+					value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 8);
+					break;
+			}
+			pokeRegisterDWord(SYSTEM_CTRL, value);
+        }
+
+        pciSlaveBurstReadCounter++;
+    }
+    else
+    {
+        if (pciSlaveBurstReadCounter > 0)
+            pciSlaveBurstReadCounter--;
+        
+        if ((ddk750_getChipType() == SM718) && (pciSlaveBurstReadCounter == 0))
+		{
+			/* Disable PCI Slave Burst */
+			value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST_READ, OFF); 
+			pokeRegisterDWord(SYSTEM_CTRL, value);
+		}
+    }
+
+	g_ulPCISlaveBurstReadSemaphoreCounter[getCurrentDevice()] = pciSlaveBurstReadCounter;
+}
+
+/* 
+ * This function enable/disable the 2D engine.
+ */
+void enable2DEngine(unsigned long enable)
+{
+    unsigned long gate;
+
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+    {
+        gate = FIELD_SET(gate, CURRENT_GATE, DE,  ON);
+        gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON);
+    }
+    else
+    {
+        gate = FIELD_SET(gate, CURRENT_GATE, DE,  OFF);
+        gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF);
+    }
+
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the ZV Port.
+ */
+void enableZVPort(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable ZV Port Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+    {
+        gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON);
+#if 1
+        /* Using Software I2C */
+        gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON);
+#endif
+    }
+    else
+    {
+        /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used
+           or not. Therefore, do not disable the GPIO gate. */
+        gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF);
+    }
+    
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the SSP.
+ */
+void enableSSP(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable SSP Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+        gate = FIELD_SET(gate, CURRENT_GATE, SSP, ON);        
+    else
+        gate = FIELD_SET(gate, CURRENT_GATE, SSP, OFF);
+    
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the DMA Engine
+ */
+void enableDMA(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable DMA Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+        gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON);
+    else
+        gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF);
+
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the GPIO Engine
+ */
+void enableGPIO(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable GPIO Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+        gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON);        
+    else
+        gate = FIELD_SET(gate, CURRENT_GATE, GPIO, OFF);
+    
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the PWM Engine
+ */
+void enablePWM(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable PWM Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+        gate = FIELD_SET(gate, CURRENT_GATE, PWM, ON);        
+    else
+        gate = FIELD_SET(gate, CURRENT_GATE, PWM, OFF);
+    
+    setCurrentGate(gate);
+}
+
+/* 
+ * This function enable/disable the I2C Engine
+ */
+void enableI2C(unsigned long enable)
+{
+    unsigned long gate;
+    
+    /* Enable I2C Gate */
+    gate = peekRegisterDWord(CURRENT_GATE);
+    if (enable)
+        gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON);        
+    else
+        gate = FIELD_SET(gate, CURRENT_GATE, I2C, OFF);
+    
+    setCurrentGate(gate);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_power.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_power.h
new file mode 100644
index 000000000000..4fc93b0e05dc
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_power.h
@@ -0,0 +1,121 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  power.h --- Voyager GX SDK 
+*  This file contains the definitions for the power functions.
+* 
+*******************************************************************/
+#ifndef _POWER_H_
+#define _POWER_H_
+
+typedef enum _DPMS_t
+{
+    DPMS_ON,
+    DPMS_STANDBY,
+    DPMS_SUSPEND,
+    DPMS_OFF
+}
+DPMS_t;
+
+/*
+ * This function sets the DPMS state 
+ */
+void setDPMS(DPMS_t state);
+
+/* 
+ * This function gets the current power mode 
+ */
+unsigned long getPowerMode(void);
+
+/* 
+ * This function sets the current power mode
+ */
+void setPowerMode(unsigned long powerMode);
+
+/* 
+ * This function sets current gate 
+ */
+void setCurrentGate(unsigned long gate);
+
+/*
+ * This function enable/disable Bus Master
+ */
+void enableBusMaster(unsigned long enable);
+
+/* 
+ *	setPCIMasterBaseAddress
+ *		This function set the PCI Master Base Address (used by bus master or DMA).
+ *
+ *	Input:	
+ *		physicalSystemMemAddress	- System physical memory address which PCI
+ *									  Master Base Address to be set to.
+ *
+ *	Output:
+ *		The memory address to be set in the register.  
+ */
+unsigned long setPCIMasterBaseAddress(
+	unsigned long physicalSystemMemAddress
+);
+
+/*
+ * 	This function enable/disable PCI Slave Burst Write provided the CPU supports Write Combine.
+ *
+ *	Input:
+ *			enable		- Enable/Disable the PCI Slave Burst Write (0 = disable, 1 = enable)
+ */
+void enablePCISlaveBurstWrite(
+	unsigned long enable
+);
+
+/*
+ * 	This function enable/disable PCI Slave Burst Read provided the CPU supports it.
+ *
+ *	Input:
+ *			enable			- Enable/Disable the PCI Slave Burst Read (0 = disable, 1 = enable)
+ *			burstReadSize	- Burst Read Size in 32-words (valid values are 1, 2, 4, and 8)
+ */
+void enablePCISlaveBurstRead(
+	unsigned long enable,
+	unsigned long burstReadSize
+);
+
+/* 
+ * This function enable/disable the 2D engine.
+ */
+void enable2DEngine(unsigned long enable);
+
+/* 
+ * This function enable/disable the ZV Port 
+ */
+void enableZVPort(unsigned long enable);
+
+/* 
+ * This function enable/disable the DMA Engine
+ */
+void enableDMA(unsigned long enable);
+
+/* 
+ * This function enable/disable the GPIO Engine
+ */
+void enableGPIO(unsigned long enable);
+
+/* 
+ * This function enable/disable the PWM Engine
+ */
+void enablePWM(unsigned long enable);
+
+/* 
+ * This function enable/disable the I2C Engine
+ */
+void enableI2C(unsigned long enable);
+
+/* 
+ * This function enable/disable the SSP.
+ */
+void enableSSP(unsigned long enable);
+
+#endif /* _POWER_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_regdc.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_regdc.h
new file mode 100644
index 000000000000..07cc3e01a316
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_regdc.h
@@ -0,0 +1,960 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  RegDC.h --- SMI DDK 
+*  This file contains the definitions for the Display Controller registers.
+* 
+*******************************************************************/
+
+/* Primary Graphics Control */
+
+#define PRIMARY_DISPLAY_CTRL                            0x080000
+#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK            31:30
+#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE    0
+#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE     3
+#define PRIMARY_DISPLAY_CTRL_SELECT                     29:28
+#define PRIMARY_DISPLAY_CTRL_SELECT_PRIMARY             0
+#define PRIMARY_DISPLAY_CTRL_SELECT_VGA                 1
+#define PRIMARY_DISPLAY_CTRL_SELECT_SECONDARY           2
+#define PRIMARY_DISPLAY_CTRL_FPEN                       27:27
+#define PRIMARY_DISPLAY_CTRL_FPEN_LOW                   0
+#define PRIMARY_DISPLAY_CTRL_FPEN_HIGH                  1
+#define PRIMARY_DISPLAY_CTRL_VBIASEN                    26:26
+#define PRIMARY_DISPLAY_CTRL_VBIASEN_LOW                0
+#define PRIMARY_DISPLAY_CTRL_VBIASEN_HIGH               1
+#define PRIMARY_DISPLAY_CTRL_DATA                       25:25
+#define PRIMARY_DISPLAY_CTRL_DATA_DISABLE               0
+#define PRIMARY_DISPLAY_CTRL_DATA_ENABLE                1
+#define PRIMARY_DISPLAY_CTRL_FPVDDEN                    24:24
+#define PRIMARY_DISPLAY_CTRL_FPVDDEN_LOW                0
+#define PRIMARY_DISPLAY_CTRL_FPVDDEN_HIGH               1
+#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK            23:20
+#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE    0
+#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE     15
+#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY               19:19
+#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_DISABLE       0
+#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_ENABLE        1
+#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL               18:18
+#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_DISABLE       0
+#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_ENABLE        1
+#define PRIMARY_DISPLAY_CTRL_FIFO                       17:16
+#define PRIMARY_DISPLAY_CTRL_FIFO_1                     0
+#define PRIMARY_DISPLAY_CTRL_FIFO_3                     1
+#define PRIMARY_DISPLAY_CTRL_FIFO_7                     2
+#define PRIMARY_DISPLAY_CTRL_FIFO_11                    3
+#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK            15:15
+#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK_DISABLE    0
+#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK_ENABLE     1
+#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE                14:14
+#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH    0
+#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW     1
+#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE                13:13
+#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH    0
+#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW     1
+#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE                12:12
+#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH    0
+#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW     1
+#define PRIMARY_DISPLAY_CTRL_VSYNC                      11:11
+#define PRIMARY_DISPLAY_CTRL_VSYNC_ACTIVE_HIGH          0
+#define PRIMARY_DISPLAY_CTRL_VSYNC_ACTIVE_LOW           1
+#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING             10:10
+#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING_DISABLE     0
+#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING_ENABLE      1
+#define PRIMARY_DISPLAY_CTRL_COLOR_KEY                  9:9
+#define PRIMARY_DISPLAY_CTRL_COLOR_KEY_DISABLE          0
+#define PRIMARY_DISPLAY_CTRL_COLOR_KEY_ENABLE           1
+#define PRIMARY_DISPLAY_CTRL_TIMING                     8:8
+#define PRIMARY_DISPLAY_CTRL_TIMING_DISABLE             0
+#define PRIMARY_DISPLAY_CTRL_TIMING_ENABLE              1
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR           7:7
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR_DOWN      0
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR_UP        1
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN               6:6
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DISABLE       0
+#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_ENABLE        1
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR         5:5
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR_RIGHT   0
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR_LEFT    1
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN             4:4
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DISABLE     0
+#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_ENABLE      1
+#define PRIMARY_DISPLAY_CTRL_GAMMA                      3:3
+#define PRIMARY_DISPLAY_CTRL_GAMMA_DISABLE              0
+#define PRIMARY_DISPLAY_CTRL_GAMMA_ENABLE               1
+#define PRIMARY_DISPLAY_CTRL_PLANE                      2:2
+#define PRIMARY_DISPLAY_CTRL_PLANE_DISABLE              0
+#define PRIMARY_DISPLAY_CTRL_PLANE_ENABLE               1
+#define PRIMARY_DISPLAY_CTRL_FORMAT                     1:0
+#define PRIMARY_DISPLAY_CTRL_FORMAT_8                   0
+#define PRIMARY_DISPLAY_CTRL_FORMAT_16                  1
+#define PRIMARY_DISPLAY_CTRL_FORMAT_32                  2
+
+#define PRIMARY_PAN_CTRL                                0x080004
+#define PRIMARY_PAN_CTRL_VERTICAL_PAN                   31:24
+#define PRIMARY_PAN_CTRL_VERTICAL_VSYNC                 21:16
+#define PRIMARY_PAN_CTRL_HORIZONTAL_PAN                 15:8
+#define PRIMARY_PAN_CTRL_HORIZONTAL_VSYNC               5:0
+
+#define PRIMARY_COLOR_KEY                               0x080008
+#define PRIMARY_COLOR_KEY_MASK                          31:16
+#define PRIMARY_COLOR_KEY_VALUE                         15:0
+
+#define PRIMARY_FB_ADDRESS                              0x08000C
+#define PRIMARY_FB_ADDRESS_STATUS                       31:31
+#define PRIMARY_FB_ADDRESS_STATUS_CURRENT               0
+#define PRIMARY_FB_ADDRESS_STATUS_PENDING               1
+#define PRIMARY_FB_ADDRESS_EXT                          27:27
+#define PRIMARY_FB_ADDRESS_EXT_LOCAL                    0
+#define PRIMARY_FB_ADDRESS_EXT_EXTERNAL                 1
+#define PRIMARY_FB_ADDRESS_ADDRESS                      25:0
+
+#define PRIMARY_FB_WIDTH                                0x080010
+#define PRIMARY_FB_WIDTH_WIDTH                          29:16
+#define PRIMARY_FB_WIDTH_OFFSET                         13:0
+
+#define PRIMARY_WINDOW_WIDTH                            0x080014
+#define PRIMARY_WINDOW_WIDTH_WIDTH                      27:16
+#define PRIMARY_WINDOW_WIDTH_X                          11:0
+
+#define PRIMARY_WINDOW_HEIGHT                           0x080018
+#define PRIMARY_WINDOW_HEIGHT_HEIGHT                    27:16
+#define PRIMARY_WINDOW_HEIGHT_Y                         11:0
+
+#define PRIMARY_PLANE_TL                                0x08001C
+#define PRIMARY_PLANE_TL_TOP                            26:16
+#define PRIMARY_PLANE_TL_LEFT                           10:0
+
+#define PRIMARY_PLANE_BR                                0x080020
+#define PRIMARY_PLANE_BR_BOTTOM                         26:16
+#define PRIMARY_PLANE_BR_RIGHT                          10:0
+
+#define PRIMARY_HORIZONTAL_TOTAL                        0x080024
+#define PRIMARY_HORIZONTAL_TOTAL_TOTAL                  27:16
+#define PRIMARY_HORIZONTAL_TOTAL_DISPLAY_END            11:0
+
+#define PRIMARY_HORIZONTAL_SYNC                         0x080028
+#define PRIMARY_HORIZONTAL_SYNC_WIDTH                   23:16
+#define PRIMARY_HORIZONTAL_SYNC_START                   11:0
+
+#define PRIMARY_VERTICAL_TOTAL                          0x08002C
+#define PRIMARY_VERTICAL_TOTAL_TOTAL                    26:16
+#define PRIMARY_VERTICAL_TOTAL_DISPLAY_END              10:0
+
+#define PRIMARY_VERTICAL_SYNC                           0x080030
+#define PRIMARY_VERTICAL_SYNC_HEIGHT                    21:16
+#define PRIMARY_VERTICAL_SYNC_START                     10:0
+
+#define PRIMARY_CURRENT_LINE                            0x080034
+#define PRIMARY_CURRENT_LINE_LINE                       10:0
+
+/* Video Control */
+
+#define VIDEO_DISPLAY_CTRL                              0x080040
+#define VIDEO_DISPLAY_CTRL_LINE_BUFFER                  18:18
+#define VIDEO_DISPLAY_CTRL_LINE_BUFFER_DISABLE          0
+#define VIDEO_DISPLAY_CTRL_LINE_BUFFER_ENABLE           1
+#define VIDEO_DISPLAY_CTRL_FIFO                         17:16
+#define VIDEO_DISPLAY_CTRL_FIFO_1                       0
+#define VIDEO_DISPLAY_CTRL_FIFO_3                       1
+#define VIDEO_DISPLAY_CTRL_FIFO_7                       2
+#define VIDEO_DISPLAY_CTRL_FIFO_11                      3
+#define VIDEO_DISPLAY_CTRL_BUFFER                       15:15
+#define VIDEO_DISPLAY_CTRL_BUFFER_0                     0
+#define VIDEO_DISPLAY_CTRL_BUFFER_1                     1
+#define VIDEO_DISPLAY_CTRL_CAPTURE                      14:14
+#define VIDEO_DISPLAY_CTRL_CAPTURE_DISABLE              0
+#define VIDEO_DISPLAY_CTRL_CAPTURE_ENABLE               1
+#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER                13:13
+#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER_DISABLE        0
+#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER_ENABLE         1
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP                    12:12
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_DISABLE            0
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_ENABLE             1
+#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE               11:11
+#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE_NORMAL        0
+#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE_HALF          1
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE             10:10
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE_NORMAL      0
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE_HALF        1
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE                9:9
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE      0
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE    1
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE              8:8
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE    0
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE  1
+#define VIDEO_DISPLAY_CTRL_PIXEL                        7:4
+#define VIDEO_DISPLAY_CTRL_GAMMA                        3:3
+#define VIDEO_DISPLAY_CTRL_GAMMA_DISABLE                0
+#define VIDEO_DISPLAY_CTRL_GAMMA_ENABLE                 1
+#define VIDEO_DISPLAY_CTRL_PLANE                        2:2
+#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE                0
+#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE                 1
+#define VIDEO_DISPLAY_CTRL_FORMAT                       1:0
+#define VIDEO_DISPLAY_CTRL_FORMAT_8                     0
+#define VIDEO_DISPLAY_CTRL_FORMAT_16                    1
+#define VIDEO_DISPLAY_CTRL_FORMAT_32                    2
+#define VIDEO_DISPLAY_CTRL_FORMAT_YUV                   3
+
+#define VIDEO_FB_0_ADDRESS                              0x080044
+#define VIDEO_FB_0_ADDRESS_STATUS                       31:31
+#define VIDEO_FB_0_ADDRESS_STATUS_CURRENT               0
+#define VIDEO_FB_0_ADDRESS_STATUS_PENDING               1
+#define VIDEO_FB_0_ADDRESS_EXT                          27:27
+#define VIDEO_FB_0_ADDRESS_EXT_LOCAL                    0
+#define VIDEO_FB_0_ADDRESS_EXT_EXTERNAL                 1
+#define VIDEO_FB_0_ADDRESS_ADDRESS                      25:0
+
+#define VIDEO_FB_WIDTH                                  0x080048
+#define VIDEO_FB_WIDTH_WIDTH                            29:16
+#define VIDEO_FB_WIDTH_OFFSET                           13:0
+
+#define VIDEO_FB_0_LAST_ADDRESS                         0x08004C
+#define VIDEO_FB_0_LAST_ADDRESS_EXT                     27:27
+#define VIDEO_FB_0_LAST_ADDRESS_EXT_LOCAL               0
+#define VIDEO_FB_0_LAST_ADDRESS_EXT_EXTERNAL            1
+#define VIDEO_FB_0_LAST_ADDRESS_ADDRESS                 25:0
+
+#define VIDEO_PLANE_TL                                  0x080050
+#define VIDEO_PLANE_TL_TOP                              26:16
+#define VIDEO_PLANE_TL_LEFT                             10:0
+
+#define VIDEO_PLANE_BR                                  0x080054
+#define VIDEO_PLANE_BR_BOTTOM                           26:16
+#define VIDEO_PLANE_BR_RIGHT                            10:0
+
+#define VIDEO_SCALE                                     0x080058
+#define VIDEO_SCALE_VERTICAL_MODE                       31:31
+#define VIDEO_SCALE_VERTICAL_MODE_EXPAND                0
+#define VIDEO_SCALE_VERTICAL_MODE_SHRINK                1
+#define VIDEO_SCALE_VERTICAL_SCALE                      27:16
+#define VIDEO_SCALE_HORIZONTAL_MODE                     15:15
+#define VIDEO_SCALE_HORIZONTAL_MODE_EXPAND              0
+#define VIDEO_SCALE_HORIZONTAL_MODE_SHRINK              1
+#define VIDEO_SCALE_HORIZONTAL_SCALE                    11:0
+
+#define VIDEO_INITIAL_SCALE                             0x08005C
+#define VIDEO_INITIAL_SCALE_FB_1                        27:16
+#define VIDEO_INITIAL_SCALE_FB_0                        11:0
+
+#define VIDEO_YUV_CONSTANTS                             0x080060
+#define VIDEO_YUV_CONSTANTS_Y                           31:24
+#define VIDEO_YUV_CONSTANTS_R                           23:16
+#define VIDEO_YUV_CONSTANTS_G                           15:8
+#define VIDEO_YUV_CONSTANTS_B                           7:0
+
+#define VIDEO_FB_1_ADDRESS                              0x080064
+#define VIDEO_FB_1_ADDRESS_STATUS                       31:31
+#define VIDEO_FB_1_ADDRESS_STATUS_CURRENT               0
+#define VIDEO_FB_1_ADDRESS_STATUS_PENDING               1
+#define VIDEO_FB_1_ADDRESS_EXT                          27:27
+#define VIDEO_FB_1_ADDRESS_EXT_LOCAL                    0
+#define VIDEO_FB_1_ADDRESS_EXT_EXTERNAL                 1
+#define VIDEO_FB_1_ADDRESS_ADDRESS                      25:0
+
+#define VIDEO_FB_1_LAST_ADDRESS                         0x080068
+#define VIDEO_FB_1_LAST_ADDRESS_EXT                     27:27
+#define VIDEO_FB_1_LAST_ADDRESS_EXT_LOCAL               0
+#define VIDEO_FB_1_LAST_ADDRESS_EXT_EXTERNAL            1
+#define VIDEO_FB_1_LAST_ADDRESS_ADDRESS                 25:0
+
+#define VIDEO_EDGE_DETECTION                            0x080074
+#define VIDEO_EDGE_DETECTION_DETECT                     24:24
+#define VIDEO_EDGE_DETECTION_DETECT_DISABLE             0
+#define VIDEO_EDGE_DETECTION_DETECT_ENABLE              1
+#define VIDEO_EDGE_DETECTION_VALUE                      9:0
+
+/* Video Alpha Control */
+
+#define VIDEO_ALPHA_DISPLAY_CTRL                        0x080080
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT                 28:28
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL       0
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_ALPHA           1
+#define VIDEO_ALPHA_DISPLAY_CTRL_ALPHA                  27:24
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO                   17:16
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_1                 0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_3                 1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_7                 2
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_11                3
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE             11:11
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE_NORMAL      0
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE_HALF        1
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE             10:10
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE_NORMAL      0
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE_HALF        1
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE              9:9
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE_REPLICATE    0
+#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE_INTERPOLATE  1
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE              8:8
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE_REPLICATE    0
+#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE_INTERPOLATE  1
+#define VIDEO_ALPHA_DISPLAY_CTRL_PIXEL                  7:4
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY             3:3
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE     0
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE      1
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE                  2:2
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_DISABLE          0
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_ENABLE           1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT                 1:0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_8               0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_16              1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4       2
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4   3
+
+#define VIDEO_ALPHA_FB_ADDRESS                          0x080084
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS                   31:31
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS_CURRENT           0
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS_PENDING           1
+#define VIDEO_ALPHA_FB_ADDRESS_EXT                      27:27
+#define VIDEO_ALPHA_FB_ADDRESS_EXT_LOCAL                0
+#define VIDEO_ALPHA_FB_ADDRESS_EXT_EXTERNAL             1
+#define VIDEO_ALPHA_FB_ADDRESS_ADDRESS                  25:0
+
+#define VIDEO_ALPHA_FB_WIDTH                            0x080088
+#define VIDEO_ALPHA_FB_WIDTH_WIDTH                      29:16
+#define VIDEO_ALPHA_FB_WIDTH_OFFSET                     13:0
+
+#define VIDEO_ALPHA_FB_LAST_ADDRESS                     0x08008C
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT                 27:27
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT_LOCAL           0
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT_EXTERNAL        1
+#define VIDEO_ALPHA_FB_LAST_ADDRESS_ADDRESS             25:0
+
+#define VIDEO_ALPHA_PLANE_TL                            0x080090
+#define VIDEO_ALPHA_PLANE_TL_TOP                        26:16
+#define VIDEO_ALPHA_PLANE_TL_LEFT                       10:0
+
+#define VIDEO_ALPHA_PLANE_BR                            0x080094
+#define VIDEO_ALPHA_PLANE_BR_BOTTOM                     26:16
+#define VIDEO_ALPHA_PLANE_BR_RIGHT                      10:0
+
+#define VIDEO_ALPHA_SCALE                               0x080098
+#define VIDEO_ALPHA_SCALE_VERTICAL_MODE                 31:31
+#define VIDEO_ALPHA_SCALE_VERTICAL_MODE_EXPAND          0
+#define VIDEO_ALPHA_SCALE_VERTICAL_MODE_SHRINK          1
+#define VIDEO_ALPHA_SCALE_VERTICAL_SCALE                27:16
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE               15:15
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE_EXPAND        0
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE_SHRINK        1
+#define VIDEO_ALPHA_SCALE_HORIZONTAL_SCALE              11:0
+
+#define VIDEO_ALPHA_INITIAL_SCALE                       0x08009C
+#define VIDEO_ALPHA_INITIAL_SCALE_VERTICAL              27:16
+#define VIDEO_ALPHA_INITIAL_SCALE_HORIZONTAL            11:0
+
+#define VIDEO_ALPHA_CHROMA_KEY                          0x0800A0
+#define VIDEO_ALPHA_CHROMA_KEY_MASK                     31:16
+#define VIDEO_ALPHA_CHROMA_KEY_VALUE                    15:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_01                     0x0800A4
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_23                     0x0800A8
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_45                     0x0800AC
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_67                     0x0800B0
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_89                     0x0800B4
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB                     0x0800B8
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD                     0x0800BC
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF                     0x0800C0
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_BLUE              4:0
+
+/* Primary Cursor Control */
+
+#define PRIMARY_HWC_ADDRESS                             0x0800F0
+#define PRIMARY_HWC_ADDRESS_ENABLE                      31:31
+#define PRIMARY_HWC_ADDRESS_ENABLE_DISABLE              0
+#define PRIMARY_HWC_ADDRESS_ENABLE_ENABLE               1
+#define PRIMARY_HWC_ADDRESS_MODE                        30:30
+#define PRIMARY_HWC_ADDRESS_MODE_MONO                   0
+#define PRIMARY_HWC_ADDRESS_MODE_COLOR                  1
+#define PRIMARY_HWC_ADDRESS_EXT                         27:27
+#define PRIMARY_HWC_ADDRESS_EXT_LOCAL                   0
+#define PRIMARY_HWC_ADDRESS_EXT_EXTERNAL                1
+#define PRIMARY_HWC_ADDRESS_ADDRESS                     25:0
+
+#define PRIMARY_HWC_LOCATION                            0x0800F4
+#define PRIMARY_HWC_LOCATION_TOP                        27:27
+#define PRIMARY_HWC_LOCATION_TOP_INSIDE                 0
+#define PRIMARY_HWC_LOCATION_TOP_OUTSIDE                1
+#define PRIMARY_HWC_LOCATION_Y                          26:16
+#define PRIMARY_HWC_LOCATION_LEFT                       11:11
+#define PRIMARY_HWC_LOCATION_LEFT_INSIDE                0
+#define PRIMARY_HWC_LOCATION_LEFT_OUTSIDE               1
+#define PRIMARY_HWC_LOCATION_X                          10:0
+
+#define PRIMARY_HWC_COLOR_12                            0x0800F8
+#define PRIMARY_HWC_COLOR_12_2_RGB565                   31:16
+#define PRIMARY_HWC_COLOR_12_1_RGB565                   15:0
+
+#define PRIMARY_HWC_COLOR_3                             0x0800FC
+#define PRIMARY_HWC_COLOR_3_RGB565                      15:0
+
+/* Alpha Control */
+
+#define ALPHA_DISPLAY_CTRL                              0x080100
+#define ALPHA_DISPLAY_CTRL_SELECT                       28:28
+#define ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL             0
+#define ALPHA_DISPLAY_CTRL_SELECT_ALPHA                 1
+#define ALPHA_DISPLAY_CTRL_ALPHA                        27:24
+#define ALPHA_DISPLAY_CTRL_FIFO                         17:16
+#define ALPHA_DISPLAY_CTRL_FIFO_1                       0
+#define ALPHA_DISPLAY_CTRL_FIFO_3                       1
+#define ALPHA_DISPLAY_CTRL_FIFO_7                       2
+#define ALPHA_DISPLAY_CTRL_FIFO_11                      3
+#define ALPHA_DISPLAY_CTRL_PIXEL                        7:4
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY                   3:3
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE           0
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE            1
+#define ALPHA_DISPLAY_CTRL_PLANE                        2:2
+#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE                0
+#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE                 1
+#define ALPHA_DISPLAY_CTRL_FORMAT                       1:0
+#define ALPHA_DISPLAY_CTRL_FORMAT_16                    1
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4             2
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4         3
+
+#define ALPHA_FB_ADDRESS                                0x080104
+#define ALPHA_FB_ADDRESS_STATUS                         31:31
+#define ALPHA_FB_ADDRESS_STATUS_CURRENT                 0
+#define ALPHA_FB_ADDRESS_STATUS_PENDING                 1
+#define ALPHA_FB_ADDRESS_EXT                            27:27
+#define ALPHA_FB_ADDRESS_EXT_LOCAL                      0
+#define ALPHA_FB_ADDRESS_EXT_EXTERNAL                   1
+#define ALPHA_FB_ADDRESS_ADDRESS                        25:0
+
+#define ALPHA_FB_WIDTH                                  0x080108
+#define ALPHA_FB_WIDTH_WIDTH                            29:16
+#define ALPHA_FB_WIDTH_OFFSET                           13:0
+
+#define ALPHA_PLANE_TL                                  0x08010C
+#define ALPHA_PLANE_TL_TOP                              26:16
+#define ALPHA_PLANE_TL_LEFT                             10:0
+
+#define ALPHA_PLANE_BR                                  0x080110
+#define ALPHA_PLANE_BR_BOTTOM                           26:16
+#define ALPHA_PLANE_BR_RIGHT                            10:0
+
+#define ALPHA_CHROMA_KEY                                0x080114
+#define ALPHA_CHROMA_KEY_MASK                           31:16
+#define ALPHA_CHROMA_KEY_VALUE                          15:0
+
+#define ALPHA_COLOR_LOOKUP_01                           0x080118
+#define ALPHA_COLOR_LOOKUP_01_1                         31:16
+#define ALPHA_COLOR_LOOKUP_01_1_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_01_1_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_01_1_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_01_0                         15:0
+#define ALPHA_COLOR_LOOKUP_01_0_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_01_0_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_01_0_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_23                           0x08011C
+#define ALPHA_COLOR_LOOKUP_23_3                         31:16
+#define ALPHA_COLOR_LOOKUP_23_3_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_23_3_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_23_3_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_23_2                         15:0
+#define ALPHA_COLOR_LOOKUP_23_2_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_23_2_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_23_2_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_45                           0x080120
+#define ALPHA_COLOR_LOOKUP_45_5                         31:16
+#define ALPHA_COLOR_LOOKUP_45_5_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_45_5_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_45_5_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_45_4                         15:0
+#define ALPHA_COLOR_LOOKUP_45_4_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_45_4_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_45_4_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_67                           0x080124
+#define ALPHA_COLOR_LOOKUP_67_7                         31:16
+#define ALPHA_COLOR_LOOKUP_67_7_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_67_7_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_67_7_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_67_6                         15:0
+#define ALPHA_COLOR_LOOKUP_67_6_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_67_6_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_67_6_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_89                           0x080128
+#define ALPHA_COLOR_LOOKUP_89_9                         31:16
+#define ALPHA_COLOR_LOOKUP_89_9_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_89_9_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_89_9_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_89_8                         15:0
+#define ALPHA_COLOR_LOOKUP_89_8_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_89_8_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_89_8_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_AB                           0x08012C
+#define ALPHA_COLOR_LOOKUP_AB_B                         31:16
+#define ALPHA_COLOR_LOOKUP_AB_B_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_AB_B_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_AB_B_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_AB_A                         15:0
+#define ALPHA_COLOR_LOOKUP_AB_A_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_AB_A_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_AB_A_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_CD                           0x080130
+#define ALPHA_COLOR_LOOKUP_CD_D                         31:16
+#define ALPHA_COLOR_LOOKUP_CD_D_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_CD_D_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_CD_D_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_CD_C                         15:0
+#define ALPHA_COLOR_LOOKUP_CD_C_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_CD_C_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_CD_C_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_EF                           0x080134
+#define ALPHA_COLOR_LOOKUP_EF_F                         31:16
+#define ALPHA_COLOR_LOOKUP_EF_F_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_EF_F_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_EF_F_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_EF_E                         15:0
+#define ALPHA_COLOR_LOOKUP_EF_E_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_EF_E_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_EF_E_BLUE                    4:0
+
+/* Secondary Graphics Control */
+
+#define SECONDARY_DISPLAY_CTRL                              0x080200
+
+/* SM750 and SM718 definition */
+#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK              31:27
+#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE      0
+#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE       0x1F
+/* SM750LE definition */
+#define SECONDARY_DISPLAY_CTRL_DPMS                         31:30
+#define SECONDARY_DISPLAY_CTRL_DPMS_0                       0
+#define SECONDARY_DISPLAY_CTRL_DPMS_1                       1
+#define SECONDARY_DISPLAY_CTRL_DPMS_2                       2
+#define SECONDARY_DISPLAY_CTRL_DPMS_3                       3
+#define SECONDARY_DISPLAY_CTRL_CLK                          29:27
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL25                    0
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL41                    1
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL62                    2
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL65                    3
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL74                    4
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL80                    5
+#define SECONDARY_DISPLAY_CTRL_CLK_PLL108                   6
+#define SECONDARY_DISPLAY_CTRL_CLK_RESERVED                 7
+#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC                26:26
+#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC_DISABLE        1
+#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC_ENABLE         0
+
+/* SM750 and SM718 definition */
+#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK              25:24
+#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE      0
+#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE       3
+
+/* SM750LE definition */
+#define SECONDARY_DISPLAY_CTRL_CRTSELECT                    25:25
+#define SECONDARY_DISPLAY_CTRL_CRTSELECT_VGA                0
+#define SECONDARY_DISPLAY_CTRL_CRTSELECT_CRT                1
+#define SECONDARY_DISPLAY_CTRL_RGBBIT                       24:24
+#define SECONDARY_DISPLAY_CTRL_RGBBIT_24BIT                 0
+#define SECONDARY_DISPLAY_CTRL_RGBBIT_12BIT                 1
+
+#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING                  23:23
+#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING_DISABLE          0
+#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING_ENABLE           1
+#define SECONDARY_DISPLAY_CTRL_EXPANSION                    22:22
+#define SECONDARY_DISPLAY_CTRL_EXPANSION_DISABLE            0
+#define SECONDARY_DISPLAY_CTRL_EXPANSION_ENABLE             1
+#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE                21:21
+#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE      0
+#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE    1
+#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE              20:20
+#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE    0
+#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE  1
+#define SECONDARY_DISPLAY_CTRL_SELECT                       19:18
+#define SECONDARY_DISPLAY_CTRL_SELECT_PRIMARY               0
+#define SECONDARY_DISPLAY_CTRL_SELECT_VGA                   1
+#define SECONDARY_DISPLAY_CTRL_SELECT_SECONDARY             2
+#define SECONDARY_DISPLAY_CTRL_FIFO                         17:16
+#define SECONDARY_DISPLAY_CTRL_FIFO_1                       0
+#define SECONDARY_DISPLAY_CTRL_FIFO_3                       1
+#define SECONDARY_DISPLAY_CTRL_FIFO_7                       2
+#define SECONDARY_DISPLAY_CTRL_FIFO_11                      3
+#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK              15:15
+#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK_DISABLE      0
+#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK_ENABLE       1
+#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE                  14:14
+#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH      0
+#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW       1
+#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE                  13:13
+#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH      0
+#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW       1
+#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE                  12:12
+#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH      0
+#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW       1
+#define SECONDARY_DISPLAY_CTRL_BLANK                        10:10
+#define SECONDARY_DISPLAY_CTRL_BLANK_OFF                    0
+#define SECONDARY_DISPLAY_CTRL_BLANK_ON                     1
+#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK              9:9
+#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK_DISABLE      0
+#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK_ENABLE       1
+#define SECONDARY_DISPLAY_CTRL_TIMING                       8:8
+#define SECONDARY_DISPLAY_CTRL_TIMING_DISABLE               0
+#define SECONDARY_DISPLAY_CTRL_TIMING_ENABLE                1
+#define SECONDARY_DISPLAY_CTRL_PIXEL                        7:4
+#define SECONDARY_DISPLAY_CTRL_GAMMA                        3:3
+#define SECONDARY_DISPLAY_CTRL_GAMMA_DISABLE                0
+#define SECONDARY_DISPLAY_CTRL_GAMMA_ENABLE                 1
+#define SECONDARY_DISPLAY_CTRL_PLANE                        2:2
+#define SECONDARY_DISPLAY_CTRL_PLANE_DISABLE                0
+#define SECONDARY_DISPLAY_CTRL_PLANE_ENABLE                 1
+#define SECONDARY_DISPLAY_CTRL_FORMAT                       1:0
+#define SECONDARY_DISPLAY_CTRL_FORMAT_8                     0
+#define SECONDARY_DISPLAY_CTRL_FORMAT_16                    1
+#define SECONDARY_DISPLAY_CTRL_FORMAT_32                    2
+#define SECONDARY_DISPLAY_CTRL_RESERVED_BITS_MASK           0xFF000200
+
+#define SECONDARY_FB_ADDRESS                            0x080204
+#define SECONDARY_FB_ADDRESS_STATUS                     31:31
+#define SECONDARY_FB_ADDRESS_STATUS_CURRENT             0
+#define SECONDARY_FB_ADDRESS_STATUS_PENDING             1
+#define SECONDARY_FB_ADDRESS_EXT                        27:27
+#define SECONDARY_FB_ADDRESS_EXT_LOCAL                  0
+#define SECONDARY_FB_ADDRESS_EXT_EXTERNAL               1
+#define SECONDARY_FB_ADDRESS_ADDRESS                    25:0
+
+#define SECONDARY_FB_WIDTH                              0x080208
+#define SECONDARY_FB_WIDTH_WIDTH                        29:16
+#define SECONDARY_FB_WIDTH_OFFSET                       13:0
+
+#define SECONDARY_HORIZONTAL_TOTAL                      0x08020C
+#define SECONDARY_HORIZONTAL_TOTAL_TOTAL                27:16
+#define SECONDARY_HORIZONTAL_TOTAL_DISPLAY_END          11:0
+
+#define SECONDARY_HORIZONTAL_SYNC                       0x080210
+#define SECONDARY_HORIZONTAL_SYNC_WIDTH                 23:16
+#define SECONDARY_HORIZONTAL_SYNC_START                 11:0
+
+#define SECONDARY_VERTICAL_TOTAL                        0x080214
+#define SECONDARY_VERTICAL_TOTAL_TOTAL                  26:16
+#define SECONDARY_VERTICAL_TOTAL_DISPLAY_END            10:0
+
+#define SECONDARY_VERTICAL_SYNC                         0x080218
+#define SECONDARY_VERTICAL_SYNC_HEIGHT                  21:16
+#define SECONDARY_VERTICAL_SYNC_START                   10:0
+
+#define SECONDARY_SIGNATURE_ANALYZER                    0x08021C
+#define SECONDARY_SIGNATURE_ANALYZER_STATUS             31:16
+#define SECONDARY_SIGNATURE_ANALYZER_ENABLE             3:3
+#define SECONDARY_SIGNATURE_ANALYZER_ENABLE_DISABLE     0
+#define SECONDARY_SIGNATURE_ANALYZER_ENABLE_ENABLE      1
+#define SECONDARY_SIGNATURE_ANALYZER_RESET              2:2
+#define SECONDARY_SIGNATURE_ANALYZER_RESET_NORMAL       0
+#define SECONDARY_SIGNATURE_ANALYZER_RESET_RESET        1
+#define SECONDARY_SIGNATURE_ANALYZER_SOURCE             1:0
+#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_RED         0
+#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_GREEN       1
+#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_BLUE        2
+
+#define SECONDARY_CURRENT_LINE                          0x080220
+#define SECONDARY_CURRENT_LINE_LINE                     10:0
+
+#define SECONDARY_MONITOR_DETECT                        0x080224
+#define SECONDARY_MONITOR_DETECT_VALUE                  25:25
+#define SECONDARY_MONITOR_DETECT_VALUE_DISABLE          0
+#define SECONDARY_MONITOR_DETECT_VALUE_ENABLE           1
+#define SECONDARY_MONITOR_DETECT_ENABLE                 24:24
+#define SECONDARY_MONITOR_DETECT_ENABLE_DISABLE         0
+#define SECONDARY_MONITOR_DETECT_ENABLE_ENABLE          1
+#define SECONDARY_MONITOR_DETECT_RED                    23:16
+#define SECONDARY_MONITOR_DETECT_GREEN                  15:8
+#define SECONDARY_MONITOR_DETECT_BLUE                   7:0
+
+#define SECONDARY_SCALE                                 0x080228
+#define SECONDARY_SCALE_VERTICAL_MODE                   31:31
+#define SECONDARY_SCALE_VERTICAL_MODE_EXPAND            0
+#define SECONDARY_SCALE_VERTICAL_MODE_SHRINK            1
+#define SECONDARY_SCALE_VERTICAL_SCALE                  27:16
+#define SECONDARY_SCALE_HORIZONTAL_MODE                 15:15
+#define SECONDARY_SCALE_HORIZONTAL_MODE_EXPAND          0
+#define SECONDARY_SCALE_HORIZONTAL_MODE_SHRINK          1
+#define SECONDARY_SCALE_HORIZONTAL_SCALE                11:0
+
+/* Secondary Cursor Control */
+
+#define SECONDARY_HWC_ADDRESS                           0x080230
+#define SECONDARY_HWC_ADDRESS_ENABLE                    31:31
+#define SECONDARY_HWC_ADDRESS_ENABLE_DISABLE            0
+#define SECONDARY_HWC_ADDRESS_ENABLE_ENABLE             1
+#define SECONDARY_HWC_ADDRESS_MODE                      30:30
+#define SECONDARY_HWC_ADDRESS_MODE_MONO                 0
+#define SECONDARY_HWC_ADDRESS_MODE_COLOR                1
+#define SECONDARY_HWC_ADDRESS_EXT                       27:27
+#define SECONDARY_HWC_ADDRESS_EXT_LOCAL                 0
+#define SECONDARY_HWC_ADDRESS_EXT_EXTERNAL              1
+#define SECONDARY_HWC_ADDRESS_ADDRESS                   25:0
+
+#define SECONDARY_HWC_LOCATION                          0x080234
+#define SECONDARY_HWC_LOCATION_TOP                      27:27
+#define SECONDARY_HWC_LOCATION_TOP_INSIDE               0
+#define SECONDARY_HWC_LOCATION_TOP_OUTSIDE              1
+#define SECONDARY_HWC_LOCATION_Y                        26:16
+#define SECONDARY_HWC_LOCATION_LEFT                     11:11
+#define SECONDARY_HWC_LOCATION_LEFT_INSIDE              0
+#define SECONDARY_HWC_LOCATION_LEFT_OUTSIDE             1
+#define SECONDARY_HWC_LOCATION_X                        10:0
+
+#define SECONDARY_HWC_COLOR_12                          0x080238
+#define SECONDARY_HWC_COLOR_12_2_RGB565                 31:16
+#define SECONDARY_HWC_COLOR_12_1_RGB565                 15:0
+
+#define SECONDARY_HWC_COLOR_3                           0x08023C
+#define SECONDARY_HWC_COLOR_3_RGB565                    15:0
+
+/* This vertical expansion below start at 0x080240 ~ 0x080264 */
+#define SECONDARY_VERTICAL_EXPANSION                    0x080240
+#define SECONDARY_VERTICAL_EXPANSION_CENTERING_VALUE    31:24 
+#define SECONDARY_VERTICAL_EXPANSION_COMPARE_VALUE      23:16
+#define SECONDARY_VERTICAL_EXPANSION_LINE_BUFFER        15:12
+#define SECONDARY_VERTICAL_EXPANSION_SCALE_FACTOR       11:0
+
+/* This horizontal expansion below start at 0x080268 ~ 0x08027C */
+#define SECONDARY_HORIZONTAL_EXPANSION                  0x080268
+#define SECONDARY_HORIZONTAL_EXPANSION_CENTERING_VALUE  31:24 
+#define SECONDARY_HORIZONTAL_EXPANSION_COMPARE_VALUE    23:16
+#define SECONDARY_HORIZONTAL_EXPANSION_SCALE_FACTOR     11:0
+
+/* Auto Centering */
+#define SECONDARY_AUTO_CENTERING_TL                     0x080280
+#define SECONDARY_AUTO_CENTERING_TL_TOP                 26:16
+#define SECONDARY_AUTO_CENTERING_TL_LEFT                10:0
+
+#define SECONDARY_AUTO_CENTERING_BR                     0x080284
+#define SECONDARY_AUTO_CENTERING_BR_BOTTOM              26:16
+#define SECONDARY_AUTO_CENTERING_BR_RIGHT               10:0
+
+/* SM750LE new register to control panel output */
+#define DISPLAY_CONTROL_750LE                           0x80288
+#define DISPLAY_CONTROL_750LE_RESERVED                  31:5
+#define DISPLAY_CONTROL_750LE_PANEL                     4:4
+#define DISPLAY_CONTROL_750LE_PANEL_NORMAL              0
+#define DISPLAY_CONTROL_750LE_PANEL_TRISTATE            1
+#define DISPLAY_CONTROL_750LE_EN                        3:3
+#define DISPLAY_CONTROL_750LE_EN_LOW                    0
+#define DISPLAY_CONTROL_750LE_EN_HIGH                   1
+#define DISPLAY_CONTROL_750LE_BIAS                      2:2
+#define DISPLAY_CONTROL_750LE_BIAS_LOW                  0
+#define DISPLAY_CONTROL_750LE_BIAS_HIGH                 1
+#define DISPLAY_CONTROL_750LE_DATA                      1:1
+#define DISPLAY_CONTROL_750LE_DATA_DISABLE              0
+#define DISPLAY_CONTROL_750LE_DATA_ENABLE               1
+#define DISPLAY_CONTROL_750LE_VDD                       0:0 
+#define DISPLAY_CONTROL_750LE_VDD_LOW                   0
+#define DISPLAY_CONTROL_750LE_VDD_HIGH                  1
+
+/* SM750LE new register for display interrtup control */
+#define RAW_INT_750LE                                    0x080290
+#define RAW_INT_750LE_RESERVED1                          31:3
+#define RAW_INT_750LE_SECONDARY_VSYNC                    2:2
+#define RAW_INT_750LE_SECONDARY_VSYNC_INACTIVE           0
+#define RAW_INT_750LE_SECONDARY_VSYNC_ACTIVE             1
+#define RAW_INT_750LE_SECONDARY_VSYNC_CLEAR              1
+#define RAW_INT_750LE_PRIMARY_VSYNC                      1:1
+#define RAW_INT_750LE_PRIMARY_VSYNC_INACTIVE             0
+#define RAW_INT_750LE_PRIMARY_VSYNC_ACTIVE               1
+#define RAW_INT_750LE_PRIMARY_VSYNC_CLEAR                1
+#define RAW_INT_750LE_VGA_VSYNC                          0:0
+#define RAW_INT_750LE_VGA_VSYNC_INACTIVE                 0
+#define RAW_INT_750LE_VGA_VSYNC_ACTIVE                   1
+#define RAW_INT_750LE_VGA_VSYNC_CLEAR                    1
+
+#define INT_STATUS_750LE                                 0x080294
+#define INT_STATUS_750LE_RESERVED1                       31:3
+#define INT_STATUS_750LE_SECONDARY_VSYNC                 2:2
+#define INT_STATUS_750LE_SECONDARY_VSYNC_INACTIVE        0
+#define INT_STATUS_750LE_SECONDARY_VSYNC_ACTIVE          1
+#define INT_STATUS_750LE_PRIMARY_VSYNC                   1:1
+#define INT_STATUS_750LE_PRIMARY_VSYNC_INACTIVE          0
+#define INT_STATUS_750LE_PRIMARY_VSYNC_ACTIVE            1
+#define INT_STATUS_750LE_VGA_VSYNC                       0:0
+#define INT_STATUS_750LE_VGA_VSYNC_INACTIVE              0
+#define INT_STATUS_750LE_VGA_VSYNC_ACTIVE                1
+
+#define INT_MASK_750LE                                   0x080298
+#define INT_MASK_750LE_RESERVED1                         31:3
+#define INT_MASK_750LE_SECONDARY_VSYNC                   2:2
+#define INT_MASK_750LE_SECONDARY_VSYNC_DISABLE           0
+#define INT_MASK_750LE_SECONDARY_VSYNC_ENABLE            1
+#define INT_MASK_750LE_PRIMARY_VSYNC                     1:1
+#define INT_MASK_750LE_PRIMARY_VSYNC_DISABLE             0
+#define INT_MASK_750LE_PRIMARY_VSYNC_ENABLE              1
+#define INT_MASK_750LE_VGA_VSYNC                         0:0
+#define INT_MASK_750LE_VGA_VSYNC_DISABLE                 0
+#define INT_MASK_750LE_VGA_VSYNC_ENABLE                  1
+
+/* SM750HS new register and values for PLL control */
+#define CRT_PLL1_750HS                         0x802a8    
+#define CRT_PLL1_750HS_25MHZ                   0x00
+#define CRT_PLL1_750HS_40MHZ                   0x01
+#define CRT_PLL1_750HS_65MHZ                   0x03
+#define CRT_PLL1_750HS_78MHZ                   0x05
+#define CRT_PLL1_750HS_74MHZ                   0x04
+#define CRT_PLL1_750HS_80MHZ                   0x05
+#define CRT_PLL1_750HS_108MHZ                  0x06
+#define CRT_PLL1_750HS_162MHZ                  0x21
+#define CRT_PLL1_750HS_148MHZ                  0x20
+#define CRT_PLL1_750HS_193MHZ                  0x22
+
+/*
+#define CRT_PLL1_750HS_F_25MHZ	               0x1D40A02
+#define CRT_PLL1_750HS_F_40MHZ	               0x3940801
+#define CRT_PLL1_750HS_F_65MHZ	               0x3940D01
+#define CRT_PLL1_750HS_F_78MHZ	               0x1540F82
+#define CRT_PLL1_750HS_F_74MHZ	               0x1541D82
+#define CRT_PLL1_750HS_F_80MHZ	               0x3941001
+#define CRT_PLL1_750HS_F_108MHZ	               0x3941B01
+#define CRT_PLL1_750HS_F_162MHZ	               0x3942881
+#define CRT_PLL1_750HS_F_148MHZ	               0x1541D82
+#define CRT_PLL1_750HS_F_193MHZ	               0x1542682
+*/
+#define CRT_PLL1_750HS_F_25MHZ	               0x23d40f02
+#define CRT_PLL1_750HS_F_40MHZ	               0x23940801
+#define CRT_PLL1_750HS_F_65MHZ	               0x23940d01
+#define CRT_PLL1_750HS_F_78MHZ	               0x23540F82
+#define CRT_PLL1_750HS_F_74MHZ	               0x23941dc2
+#define CRT_PLL1_750HS_F_80MHZ	               0x23941001
+#define CRT_PLL1_750HS_F_80MHZ_1152	        0x23540fc2
+#define CRT_PLL1_750HS_F_108MHZ	               0x23b41b01
+#define CRT_PLL1_750HS_F_162MHZ	               0x23480681
+#define CRT_PLL1_750HS_F_148MHZ	               0x23541dc2
+#define CRT_PLL1_750HS_F_193MHZ	               0x234807c1
+
+#define CRT_PLL1_750HS_A_25MHZ	               0x1D40A02
+#define CRT_PLL1_750HS_A_40MHZ	               0x3940801
+#define CRT_PLL1_750HS_A_65MHZ	               0x3940D01
+#define CRT_PLL1_750HS_A_78MHZ	               0x1540F82
+#define CRT_PLL1_750HS_A_74MHZ	               0x1541D82
+#define CRT_PLL1_750HS_A_80MHZ	               0x3941001
+#define CRT_PLL1_750HS_A_108MHZ	               0x3941B01
+#define CRT_PLL1_750HS_A_162MHZ	               0x3942881
+#define CRT_PLL1_750HS_A_148MHZ	               0x1541D82
+#define CRT_PLL1_750HS_A_193MHZ	               0x1542682
+
+#define CRT_PLL2_750HS                         0x802ac
+#define CRT_PLL2_750HS_25MHZ                   0x0
+#define CRT_PLL2_750HS_40MHZ                   0x0
+#define CRT_PLL2_750HS_65MHZ                   0x0
+#define CRT_PLL2_750HS_78MHZ                   0x0
+#define CRT_PLL2_750HS_74MHZ                   0x0
+#define CRT_PLL2_750HS_80MHZ                   0x0
+#define CRT_PLL2_750HS_108MHZ                  0x0
+#define CRT_PLL2_750HS_162MHZ                  0x0
+#define CRT_PLL2_750HS_148MHZ                  0x0
+#define CRT_PLL2_750HS_193MHZ                  0x0
+
+#define CRT_PLL2_750HS_F_25MHZ	               0x206B851E
+#define CRT_PLL2_750HS_F_40MHZ	               0x30000000
+#define CRT_PLL2_750HS_F_65MHZ	               0x40000000
+#define CRT_PLL2_750HS_F_78MHZ	               0x50E147AE
+#define CRT_PLL2_750HS_F_74MHZ	               0x602B6AE7
+#define CRT_PLL2_750HS_F_80MHZ	               0x70000000
+#define CRT_PLL2_750HS_F_108MHZ	               0x80000000
+#define CRT_PLL2_750HS_F_162MHZ	               0xA0000000
+#define CRT_PLL2_750HS_F_148MHZ	               0xB0CCCCCD
+#define CRT_PLL2_750HS_F_193MHZ	               0xC0872B02
+
+#define CRT_PLL2_750HS_A_25MHZ	               0x206B851E
+#define CRT_PLL2_750HS_A_40MHZ	               0x30000000
+#define CRT_PLL2_750HS_A_65MHZ	               0x40000000
+#define CRT_PLL2_750HS_A_78MHZ	               0x50E147AE
+#define CRT_PLL2_750HS_A_74MHZ	               0x602B6AE7
+#define CRT_PLL2_750HS_A_80MHZ	               0x70000000
+#define CRT_PLL2_750HS_A_108MHZ	               0x80000000
+#define CRT_PLL2_750HS_A_162MHZ	               0xA0000000
+#define CRT_PLL2_750HS_A_148MHZ	               0xB0CCCCCD
+#define CRT_PLL2_750HS_A_193MHZ	               0xC0872B02
+
+/* SM750HS, the following PLL are for BIOS to set VGA modes.
+   DDK don't use them. Just keep here for the record. */
+#define VGA1_PLL1_750HS                               0x802b0
+#define VGA1_PLL2_750HS                               0x802b4
+#define VGA2_PLL1_750HS                               0x802b8
+#define VGA2_PLL2_750HS                               0x802bc
+
+/* Palette RAM */
+
+/* Panel Pallete register starts at 0x080400 ~ 0x0807FC */
+#define PRIMARY_PALETTE_RAM                             0x080400
+
+/* Panel Pallete register starts at 0x080C00 ~ 0x080FFC */
+#define SECONDARY_PALETTE_RAM                           0x080C00
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_regde.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_regde.h
new file mode 100644
index 000000000000..70c26e3575b0
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_regde.h
@@ -0,0 +1,359 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  RegDE.h --- Voyager GX SDK 
+*  This file contains the definitions for the Drawing Engine registers.
+* 
+*******************************************************************/
+/* 2D registers. */
+
+#define DE_SOURCE                                       0x100000
+#define DE_SOURCE_WRAP                                  31:31
+#define DE_SOURCE_WRAP_DISABLE                          0
+#define DE_SOURCE_WRAP_ENABLE                           1
+
+/* 
+ * The following definitions are used in different setting 
+ */
+
+/* Use these definitions in XY addressing mode or linear addressing mode. */
+#define DE_SOURCE_X_K1                                  27:16
+#define DE_SOURCE_Y_K2                                  11:0
+
+/* Use this definition in host write mode for mono. The Y_K2 is not used
+   in host write mode. */
+#define DE_SOURCE_X_K1_MONO                             20:16
+
+/* Use these definitions in Bresenham line drawing mode. */
+#define DE_SOURCE_X_K1_LINE                             29:16
+#define DE_SOURCE_Y_K2_LINE                             13:0
+
+#define DE_DESTINATION                                  0x100004
+#define DE_DESTINATION_WRAP                             31:31
+#define DE_DESTINATION_WRAP_DISABLE                     0
+#define DE_DESTINATION_WRAP_ENABLE                      1
+#if 1
+    #define DE_DESTINATION_X                            27:16
+    #define DE_DESTINATION_Y                            11:0
+#else
+    #define DE_DESTINATION_X                            28:16
+    #define DE_DESTINATION_Y                            15:0
+#endif
+
+#define DE_DIMENSION                                    0x100008
+#define DE_DIMENSION_X                                  28:16
+#define DE_DIMENSION_Y_ET                               15:0
+
+#define DE_CONTROL                                      0x10000C
+#define DE_CONTROL_STATUS                               31:31
+#define DE_CONTROL_STATUS_STOP                          0
+#define DE_CONTROL_STATUS_START                         1
+#define DE_CONTROL_PATTERN                              30:30
+#define DE_CONTROL_PATTERN_MONO                         0
+#define DE_CONTROL_PATTERN_COLOR                        1
+#define DE_CONTROL_UPDATE_DESTINATION_X                 29:29
+#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE         0
+#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE          1
+#define DE_CONTROL_QUICK_START                          28:28
+#define DE_CONTROL_QUICK_START_DISABLE                  0
+#define DE_CONTROL_QUICK_START_ENABLE                   1
+#define DE_CONTROL_DIRECTION                            27:27
+#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT              0
+#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT              1
+#define DE_CONTROL_MAJOR                                26:26
+#define DE_CONTROL_MAJOR_X                              0
+#define DE_CONTROL_MAJOR_Y                              1
+#define DE_CONTROL_STEP_X                               25:25
+#define DE_CONTROL_STEP_X_POSITIVE                      0
+#define DE_CONTROL_STEP_X_NEGATIVE                      1
+#define DE_CONTROL_STEP_Y                               24:24
+#define DE_CONTROL_STEP_Y_POSITIVE                      0
+#define DE_CONTROL_STEP_Y_NEGATIVE                      1
+#define DE_CONTROL_STRETCH                              23:23
+#define DE_CONTROL_STRETCH_DISABLE                      0
+#define DE_CONTROL_STRETCH_ENABLE                       1
+#define DE_CONTROL_HOST                                 22:22
+#define DE_CONTROL_HOST_COLOR                           0
+#define DE_CONTROL_HOST_MONO                            1
+#define DE_CONTROL_LAST_PIXEL                           21:21
+#define DE_CONTROL_LAST_PIXEL_OFF                       0
+#define DE_CONTROL_LAST_PIXEL_ON                        1
+#define DE_CONTROL_COMMAND                              20:16
+#define DE_CONTROL_COMMAND_BITBLT                       0
+#define DE_CONTROL_COMMAND_RECTANGLE_FILL               1
+#define DE_CONTROL_COMMAND_DE_TILE                      2
+#define DE_CONTROL_COMMAND_TRAPEZOID_FILL               3
+#define DE_CONTROL_COMMAND_ALPHA_BLEND                  4
+#define DE_CONTROL_COMMAND_RLE_STRIP                    5
+#define DE_CONTROL_COMMAND_SHORT_STROKE                 6
+#define DE_CONTROL_COMMAND_LINE_DRAW                    7
+#define DE_CONTROL_COMMAND_HOST_WRITE                   8
+#define DE_CONTROL_COMMAND_HOST_READ                    9
+#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP         10
+#define DE_CONTROL_COMMAND_ROTATE                       11
+#define DE_CONTROL_COMMAND_FONT                         12
+#define DE_CONTROL_COMMAND_TEXTURE_LOAD                 15
+#define DE_CONTROL_ROP_SELECT                           15:15
+#define DE_CONTROL_ROP_SELECT_ROP3                      0
+#define DE_CONTROL_ROP_SELECT_ROP2                      1
+#define DE_CONTROL_ROP2_SOURCE                          14:14
+#define DE_CONTROL_ROP2_SOURCE_BITMAP                   0
+#define DE_CONTROL_ROP2_SOURCE_PATTERN                  1
+#define DE_CONTROL_MONO_DATA                            13:12
+#define DE_CONTROL_MONO_DATA_NOT_PACKED                 0
+#define DE_CONTROL_MONO_DATA_8_PACKED                   1
+#define DE_CONTROL_MONO_DATA_16_PACKED                  2
+#define DE_CONTROL_MONO_DATA_32_PACKED                  3
+#define DE_CONTROL_REPEAT_ROTATE                        11:11
+#define DE_CONTROL_REPEAT_ROTATE_DISABLE                0
+#define DE_CONTROL_REPEAT_ROTATE_ENABLE                 1
+#define DE_CONTROL_TRANSPARENCY_MATCH                   10:10
+#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE            0
+#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT       1
+#define DE_CONTROL_TRANSPARENCY_SELECT                  9:9
+#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE           0
+#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION      1
+#define DE_CONTROL_TRANSPARENCY                         8:8
+#define DE_CONTROL_TRANSPARENCY_DISABLE                 0
+#define DE_CONTROL_TRANSPARENCY_ENABLE                  1
+#define DE_CONTROL_ROP                                  7:0
+
+/* Pseudo fields. */
+
+#define DE_CONTROL_SHORT_STROKE_DIR                     27:24
+#define DE_CONTROL_SHORT_STROKE_DIR_225                 0
+#define DE_CONTROL_SHORT_STROKE_DIR_135                 1
+#define DE_CONTROL_SHORT_STROKE_DIR_315                 2
+#define DE_CONTROL_SHORT_STROKE_DIR_45                  3
+#define DE_CONTROL_SHORT_STROKE_DIR_270                 4
+#define DE_CONTROL_SHORT_STROKE_DIR_90                  5
+#define DE_CONTROL_SHORT_STROKE_DIR_180                 8
+#define DE_CONTROL_SHORT_STROKE_DIR_0                   10
+#define DE_CONTROL_ROTATION                             25:24
+#define DE_CONTROL_ROTATION_0                           0
+#define DE_CONTROL_ROTATION_270                         1
+#define DE_CONTROL_ROTATION_90                          2
+#define DE_CONTROL_ROTATION_180                         3
+
+#define DE_PITCH                                        0x100010
+#define DE_PITCH_DESTINATION                            28:16
+#define DE_PITCH_SOURCE                                 12:0
+
+#define DE_FOREGROUND                                   0x100014
+#define DE_FOREGROUND_COLOR                             31:0
+
+#define DE_BACKGROUND                                   0x100018
+#define DE_BACKGROUND_COLOR                             31:0
+
+#define DE_STRETCH_FORMAT                               0x10001C
+#define DE_STRETCH_FORMAT_PATTERN_XY                    30:30
+#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL             0
+#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE          1
+#define DE_STRETCH_FORMAT_PATTERN_Y                     29:27
+#define DE_STRETCH_FORMAT_PATTERN_X                     25:23
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT                  21:20
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8                0
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16               1
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32               2
+#define DE_STRETCH_FORMAT_ADDRESSING                    19:16
+#define DE_STRETCH_FORMAT_ADDRESSING_XY                 0
+#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR             15
+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT                 11:0
+
+#define DE_COLOR_COMPARE                                0x100020
+#define DE_COLOR_COMPARE_COLOR                          23:0
+
+#define DE_COLOR_COMPARE_MASK                           0x100024
+#define DE_COLOR_COMPARE_MASK_MASKS                     23:0
+
+#define DE_MASKS                                        0x100028
+#define DE_MASKS_BYTE_MASK                              31:16
+#define DE_MASKS_BIT_MASK                               15:0
+
+#define DE_CLIP_TL                                      0x10002C
+#define DE_CLIP_TL_TOP                                  31:16
+#define DE_CLIP_TL_STATUS                               13:13
+#define DE_CLIP_TL_STATUS_DISABLE                       0
+#define DE_CLIP_TL_STATUS_ENABLE                        1
+#define DE_CLIP_TL_INHIBIT                              12:12
+#define DE_CLIP_TL_INHIBIT_OUTSIDE                      0
+#define DE_CLIP_TL_INHIBIT_INSIDE                       1
+#define DE_CLIP_TL_LEFT                                 11:0
+
+#define DE_CLIP_BR                                      0x100030
+#define DE_CLIP_BR_BOTTOM                               31:16
+#define DE_CLIP_BR_RIGHT                                12:0
+
+#define DE_MONO_PATTERN_LOW                             0x100034
+#define DE_MONO_PATTERN_LOW_PATTERN                     31:0
+
+#define DE_MONO_PATTERN_HIGH                            0x100038
+#define DE_MONO_PATTERN_HIGH_PATTERN                    31:0
+
+#define DE_WINDOW_WIDTH                                 0x10003C
+#define DE_WINDOW_WIDTH_DESTINATION                     28:16
+#define DE_WINDOW_WIDTH_SOURCE                          12:0
+
+#define DE_WINDOW_SOURCE_BASE                           0x100040
+#define DE_WINDOW_SOURCE_BASE_EXT                       27:27
+#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL                 0
+#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL              1
+#define DE_WINDOW_SOURCE_BASE_CS                        26:26
+#define DE_WINDOW_SOURCE_BASE_CS_0                      0
+#define DE_WINDOW_SOURCE_BASE_CS_1                      1
+#define DE_WINDOW_SOURCE_BASE_ADDRESS                   25:0
+
+#define DE_WINDOW_DESTINATION_BASE                      0x100044
+#define DE_WINDOW_DESTINATION_BASE_EXT                  27:27
+#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL            0
+#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL         1
+#define DE_WINDOW_DESTINATION_BASE_CS                   26:26
+#define DE_WINDOW_DESTINATION_BASE_CS_0                 0
+#define DE_WINDOW_DESTINATION_BASE_CS_1                 1
+#define DE_WINDOW_DESTINATION_BASE_ADDRESS              25:0
+
+#define DE_ALPHA                                        0x100048
+#define DE_ALPHA_VALUE                                  7:0
+
+#define DE_WRAP                                         0x10004C
+#define DE_WRAP_X                                       31:16
+#define DE_WRAP_Y                                       15:0
+
+#define DE_STATUS                                       0x100050
+#define DE_STATUS_CSC                                   1:1
+#define DE_STATUS_CSC_CLEAR                             0
+#define DE_STATUS_CSC_NOT_ACTIVE                        0
+#define DE_STATUS_CSC_ACTIVE                            1
+#define DE_STATUS_2D                                    0:0
+#define DE_STATUS_2D_CLEAR                              0
+#define DE_STATUS_2D_NOT_ACTIVE                         0
+#define DE_STATUS_2D_ACTIVE                             1
+
+/* New register for SM750LE */
+#define DE_STATE1                                        0x100054
+#define DE_STATE1_DE_ABORT                               0:0
+#define DE_STATE1_DE_ABORT_OFF                           0
+#define DE_STATE1_DE_ABORT_ON                            1
+
+#define DE_STATE2                                        0x100058
+#define DE_STATE2_DE_FIFO                                3:3
+#define DE_STATE2_DE_FIFO_NOTEMPTY                       0
+#define DE_STATE2_DE_FIFO_EMPTY                          1
+#define DE_STATE2_DE_STATUS                              2:2
+#define DE_STATE2_DE_STATUS_IDLE                         0
+#define DE_STATE2_DE_STATUS_BUSY                         1
+#define DE_STATE2_DE_MEM_FIFO                            1:1
+#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY                   0
+#define DE_STATE2_DE_MEM_FIFO_EMPTY                      1
+#define DE_STATE2_DE_RESERVED                            0:0
+
+/* Color Space Conversion registers. */
+
+#define CSC_Y_SOURCE_BASE                               0x1000C8
+#define CSC_Y_SOURCE_BASE_EXT                           27:27
+#define CSC_Y_SOURCE_BASE_EXT_LOCAL                     0
+#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL                  1
+#define CSC_Y_SOURCE_BASE_CS                            26:26
+#define CSC_Y_SOURCE_BASE_CS_0                          0
+#define CSC_Y_SOURCE_BASE_CS_1                          1
+#define CSC_Y_SOURCE_BASE_ADDRESS                       25:0
+
+#define CSC_CONSTANTS                                   0x1000CC
+#define CSC_CONSTANTS_Y                                 31:24
+#define CSC_CONSTANTS_R                                 23:16
+#define CSC_CONSTANTS_G                                 15:8
+#define CSC_CONSTANTS_B                                 7:0
+
+#define CSC_Y_SOURCE_X                                  0x1000D0
+#define CSC_Y_SOURCE_X_INTEGER                          26:16
+#define CSC_Y_SOURCE_X_FRACTION                         15:3
+
+#define CSC_Y_SOURCE_Y                                  0x1000D4
+#define CSC_Y_SOURCE_Y_INTEGER                          27:16
+#define CSC_Y_SOURCE_Y_FRACTION                         15:3
+
+#define CSC_U_SOURCE_BASE                               0x1000D8
+#define CSC_U_SOURCE_BASE_EXT                           27:27
+#define CSC_U_SOURCE_BASE_EXT_LOCAL                     0
+#define CSC_U_SOURCE_BASE_EXT_EXTERNAL                  1
+#define CSC_U_SOURCE_BASE_CS                            26:26
+#define CSC_U_SOURCE_BASE_CS_0                          0
+#define CSC_U_SOURCE_BASE_CS_1                          1
+#define CSC_U_SOURCE_BASE_ADDRESS                       25:0
+
+#define CSC_V_SOURCE_BASE                               0x1000DC
+#define CSC_V_SOURCE_BASE_EXT                           27:27
+#define CSC_V_SOURCE_BASE_EXT_LOCAL                     0
+#define CSC_V_SOURCE_BASE_EXT_EXTERNAL                  1
+#define CSC_V_SOURCE_BASE_CS                            26:26
+#define CSC_V_SOURCE_BASE_CS_0                          0
+#define CSC_V_SOURCE_BASE_CS_1                          1
+#define CSC_V_SOURCE_BASE_ADDRESS                       25:0
+
+#define CSC_SOURCE_DIMENSION                            0x1000E0
+#define CSC_SOURCE_DIMENSION_X                          31:16
+#define CSC_SOURCE_DIMENSION_Y                          15:0
+
+#define CSC_SOURCE_PITCH                                0x1000E4
+#define CSC_SOURCE_PITCH_Y                              31:16
+#define CSC_SOURCE_PITCH_UV                             15:0
+
+#define CSC_DESTINATION                                 0x1000E8
+#define CSC_DESTINATION_WRAP                            31:31
+#define CSC_DESTINATION_WRAP_DISABLE                    0
+#define CSC_DESTINATION_WRAP_ENABLE                     1
+#define CSC_DESTINATION_X                               27:16
+#define CSC_DESTINATION_Y                               11:0
+
+#define CSC_DESTINATION_DIMENSION                       0x1000EC
+#define CSC_DESTINATION_DIMENSION_X                     31:16
+#define CSC_DESTINATION_DIMENSION_Y                     15:0
+
+#define CSC_DESTINATION_PITCH                           0x1000F0
+#define CSC_DESTINATION_PITCH_X                         31:16
+#define CSC_DESTINATION_PITCH_Y                         15:0
+
+#define CSC_SCALE_FACTOR                                0x1000F4
+#define CSC_SCALE_FACTOR_HORIZONTAL                     31:16
+#define CSC_SCALE_FACTOR_VERTICAL                       15:0
+
+#define CSC_DESTINATION_BASE                            0x1000F8
+#define CSC_DESTINATION_BASE_EXT                        27:27
+#define CSC_DESTINATION_BASE_EXT_LOCAL                  0
+#define CSC_DESTINATION_BASE_EXT_EXTERNAL               1
+#define CSC_DESTINATION_BASE_CS                         26:26
+#define CSC_DESTINATION_BASE_CS_0                       0
+#define CSC_DESTINATION_BASE_CS_1                       1
+#define CSC_DESTINATION_BASE_ADDRESS                    25:0
+
+#define CSC_CONTROL                                     0x1000FC
+#define CSC_CONTROL_STATUS                              31:31
+#define CSC_CONTROL_STATUS_STOP                         0
+#define CSC_CONTROL_STATUS_START                        1
+#define CSC_CONTROL_SOURCE_FORMAT                       30:28
+#define CSC_CONTROL_SOURCE_FORMAT_YUV422                0
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420I               1
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420                2
+#define CSC_CONTROL_SOURCE_FORMAT_YVU9                  3
+#define CSC_CONTROL_SOURCE_FORMAT_IYU1                  4
+#define CSC_CONTROL_SOURCE_FORMAT_IYU2                  5
+#define CSC_CONTROL_SOURCE_FORMAT_RGB565                6
+#define CSC_CONTROL_SOURCE_FORMAT_RGB8888               7
+#define CSC_CONTROL_DESTINATION_FORMAT                  27:26
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB565           0
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888          1
+#define CSC_CONTROL_HORIZONTAL_FILTER                   25:25
+#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE           0
+#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE            1
+#define CSC_CONTROL_VERTICAL_FILTER                     24:24
+#define CSC_CONTROL_VERTICAL_FILTER_DISABLE             0
+#define CSC_CONTROL_VERTICAL_FILTER_ENABLE              1
+#define CSC_CONTROL_BYTE_ORDER                          23:23
+#define CSC_CONTROL_BYTE_ORDER_YUYV                     0
+#define CSC_CONTROL_BYTE_ORDER_UYVY                     1
+
+#define DE_DATA_PORT                                    0x110000
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_reggpio.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_reggpio.h
new file mode 100644
index 000000000000..eb08a8000ca0
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_reggpio.h
@@ -0,0 +1,239 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  RegGPIO.h --- Voyager GX SDK 
+*  This file contains the definitions for the GPIO registers.
+* 
+*******************************************************************/
+#define GPIO_DATA                                       0x010000
+#define GPIO_DATA_31                                    31:31
+#define GPIO_DATA_30                                    30:30
+#define GPIO_DATA_29                                    29:29
+#define GPIO_DATA_28                                    28:28
+#define GPIO_DATA_27                                    27:27
+#define GPIO_DATA_26                                    26:26
+#define GPIO_DATA_25                                    25:25
+#define GPIO_DATA_24                                    24:24
+#define GPIO_DATA_23                                    23:23
+#define GPIO_DATA_22                                    22:22
+#define GPIO_DATA_21                                    21:21
+#define GPIO_DATA_20                                    20:20
+#define GPIO_DATA_19                                    19:19
+#define GPIO_DATA_18                                    18:18
+#define GPIO_DATA_17                                    17:17
+#define GPIO_DATA_16                                    16:16
+#define GPIO_DATA_15                                    15:15
+#define GPIO_DATA_14                                    14:14
+#define GPIO_DATA_13                                    13:13
+#define GPIO_DATA_12                                    12:12
+#define GPIO_DATA_11                                    11:11
+#define GPIO_DATA_10                                    10:10
+#define GPIO_DATA_9                                     9:9
+#define GPIO_DATA_8                                     8:8
+#define GPIO_DATA_7                                     7:7
+#define GPIO_DATA_6                                     6:6
+#define GPIO_DATA_5                                     5:5
+#define GPIO_DATA_4                                     4:4
+#define GPIO_DATA_3                                     3:3
+#define GPIO_DATA_2                                     2:2
+#define GPIO_DATA_1                                     1:1
+#define GPIO_DATA_0                                     0:0
+
+#define GPIO_DATA_DIRECTION                             0x010004
+#define GPIO_DATA_DIRECTION_31                          31:31
+#define GPIO_DATA_DIRECTION_31_INPUT                    0
+#define GPIO_DATA_DIRECTION_31_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_30                          30:30
+#define GPIO_DATA_DIRECTION_30_INPUT                    0
+#define GPIO_DATA_DIRECTION_30_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_29                          29:29
+#define GPIO_DATA_DIRECTION_29_INPUT                    0
+#define GPIO_DATA_DIRECTION_29_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_28                          28:28
+#define GPIO_DATA_DIRECTION_28_INPUT                    0
+#define GPIO_DATA_DIRECTION_28_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_27                          27:27
+#define GPIO_DATA_DIRECTION_27_INPUT                    0
+#define GPIO_DATA_DIRECTION_27_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_26                          26:26
+#define GPIO_DATA_DIRECTION_26_INPUT                    0
+#define GPIO_DATA_DIRECTION_26_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_25                          25:25
+#define GPIO_DATA_DIRECTION_25_INPUT                    0
+#define GPIO_DATA_DIRECTION_25_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_24                          24:24
+#define GPIO_DATA_DIRECTION_24_INPUT                    0
+#define GPIO_DATA_DIRECTION_24_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_23                          23:23
+#define GPIO_DATA_DIRECTION_23_INPUT                    0
+#define GPIO_DATA_DIRECTION_23_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_22                          22:22
+#define GPIO_DATA_DIRECTION_22_INPUT                    0
+#define GPIO_DATA_DIRECTION_22_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_21                          21:21
+#define GPIO_DATA_DIRECTION_21_INPUT                    0
+#define GPIO_DATA_DIRECTION_21_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_20                          20:20
+#define GPIO_DATA_DIRECTION_20_INPUT                    0
+#define GPIO_DATA_DIRECTION_20_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_19                          19:19
+#define GPIO_DATA_DIRECTION_19_INPUT                    0
+#define GPIO_DATA_DIRECTION_19_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_18                          18:18
+#define GPIO_DATA_DIRECTION_18_INPUT                    0
+#define GPIO_DATA_DIRECTION_18_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_17                          17:17
+#define GPIO_DATA_DIRECTION_17_INPUT                    0
+#define GPIO_DATA_DIRECTION_17_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_16                          16:16
+#define GPIO_DATA_DIRECTION_16_INPUT                    0
+#define GPIO_DATA_DIRECTION_16_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_15                          15:15
+#define GPIO_DATA_DIRECTION_15_INPUT                    0
+#define GPIO_DATA_DIRECTION_15_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_14                          14:14
+#define GPIO_DATA_DIRECTION_14_INPUT                    0
+#define GPIO_DATA_DIRECTION_14_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_13                          13:13
+#define GPIO_DATA_DIRECTION_13_INPUT                    0
+#define GPIO_DATA_DIRECTION_13_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_12                          12:12
+#define GPIO_DATA_DIRECTION_12_INPUT                    0
+#define GPIO_DATA_DIRECTION_12_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_11                          11:11
+#define GPIO_DATA_DIRECTION_11_INPUT                    0
+#define GPIO_DATA_DIRECTION_11_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_10                          10:10
+#define GPIO_DATA_DIRECTION_10_INPUT                    0
+#define GPIO_DATA_DIRECTION_10_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_9                           9:9
+#define GPIO_DATA_DIRECTION_9_INPUT                     0
+#define GPIO_DATA_DIRECTION_9_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_8                           8:8
+#define GPIO_DATA_DIRECTION_8_INPUT                     0
+#define GPIO_DATA_DIRECTION_8_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_7                           7:7
+#define GPIO_DATA_DIRECTION_7_INPUT                     0
+#define GPIO_DATA_DIRECTION_7_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_6                           6:6
+#define GPIO_DATA_DIRECTION_6_INPUT                     0
+#define GPIO_DATA_DIRECTION_6_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_5                           5:5
+#define GPIO_DATA_DIRECTION_5_INPUT                     0
+#define GPIO_DATA_DIRECTION_5_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_4                           4:4
+#define GPIO_DATA_DIRECTION_4_INPUT                     0
+#define GPIO_DATA_DIRECTION_4_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_3                           3:3
+#define GPIO_DATA_DIRECTION_3_INPUT                     0
+#define GPIO_DATA_DIRECTION_3_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_2                           2:2
+#define GPIO_DATA_DIRECTION_2_INPUT                     0
+#define GPIO_DATA_DIRECTION_2_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_1                           1:1
+#define GPIO_DATA_DIRECTION_1_INPUT                     0
+#define GPIO_DATA_DIRECTION_1_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_0                           0:0
+#define GPIO_DATA_DIRECTION_0_INPUT                     0
+#define GPIO_DATA_DIRECTION_0_OUTPUT                    1
+
+#define GPIO_INTERRUPT_SETUP                            0x010008
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31                 22:22
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30                 21:21
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29                 20:20
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28                 19:19
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27                 18:18
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26                 17:17
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25                 16:16
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31                  14:14
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30                  13:13
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29                  12:12
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28                  11:11
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27                  10:10
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26                  9:9
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25                  8:8
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ENABLE_31                  6:6
+#define GPIO_INTERRUPT_SETUP_ENABLE_31_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_31_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_30                  5:5
+#define GPIO_INTERRUPT_SETUP_ENABLE_30_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_30_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_29                  4:4
+#define GPIO_INTERRUPT_SETUP_ENABLE_29_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_29_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_28                  3:3
+#define GPIO_INTERRUPT_SETUP_ENABLE_28_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_28_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_27                  2:2
+#define GPIO_INTERRUPT_SETUP_ENABLE_27_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_27_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_26                  1:1
+#define GPIO_INTERRUPT_SETUP_ENABLE_26_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_26_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_25                  0:0
+#define GPIO_INTERRUPT_SETUP_ENABLE_25_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_25_INTERRUPT        1
+
+#define GPIO_INTERRUPT_STATUS                           0x01000C
+#define GPIO_INTERRUPT_STATUS_31                        22:22
+#define GPIO_INTERRUPT_STATUS_31_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_31_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_31_RESET                  1
+#define GPIO_INTERRUPT_STATUS_30                        21:21
+#define GPIO_INTERRUPT_STATUS_30_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_30_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_30_RESET                  1
+#define GPIO_INTERRUPT_STATUS_29                        20:20
+#define GPIO_INTERRUPT_STATUS_29_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_29_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_29_RESET                  1
+#define GPIO_INTERRUPT_STATUS_28                        19:19
+#define GPIO_INTERRUPT_STATUS_28_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_28_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_28_RESET                  1
+#define GPIO_INTERRUPT_STATUS_27                        18:18
+#define GPIO_INTERRUPT_STATUS_27_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_27_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_27_RESET                  1
+#define GPIO_INTERRUPT_STATUS_26                        17:17
+#define GPIO_INTERRUPT_STATUS_26_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_26_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_26_RESET                  1
+#define GPIO_INTERRUPT_STATUS_25                        16:16
+#define GPIO_INTERRUPT_STATUS_25_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_25_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_25_RESET                  1
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_regi2c.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_regi2c.h
new file mode 100644
index 000000000000..62555c6424c2
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_regi2c.h
@@ -0,0 +1,69 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  RegI2C.h --- Voyager GX SDK 
+*  This file contains the definitions for the HW I2C registers.
+* 
+*******************************************************************/
+#define I2C_BYTE_COUNT                                  0x010040
+#define I2C_BYTE_COUNT_COUNT                            3:0
+
+#define I2C_CTRL                                        0x010041
+#define I2C_CTRL_INT                                    4:4
+#define I2C_CTRL_INT_DISABLE                            0
+#define I2C_CTRL_INT_ENABLE                             1
+#define I2C_CTRL_CTRL                                   2:2
+#define I2C_CTRL_CTRL_STOP                              0
+#define I2C_CTRL_CTRL_START                             1
+#define I2C_CTRL_MODE                                   1:1
+#define I2C_CTRL_MODE_STANDARD                          0
+#define I2C_CTRL_MODE_FAST                              1
+#define I2C_CTRL_EN                                     0:0
+#define I2C_CTRL_EN_DISABLE                             0
+#define I2C_CTRL_EN_ENABLE                              1
+
+#define I2C_STATUS                                      0x010042
+#define I2C_STATUS_TX                                   3:3
+#define I2C_STATUS_TX_PROGRESS                          0
+#define I2C_STATUS_TX_COMPLETED                         1
+#define I2C_STATUS_ERR                                  2:2
+#define I2C_STATUS_ERR_NORMAL                           0
+#define I2C_STATUS_ERR_ERROR                            1
+#define I2C_STATUS_ERR_CLEAR                            0
+#define I2C_STATUS_ACK                                  1:1
+#define I2C_STATUS_ACK_RECEIVED                         0
+#define I2C_STATUS_ACK_NOT                              1
+#define I2C_STATUS_BSY                                  0:0
+#define I2C_STATUS_BSY_IDLE                             0
+#define I2C_STATUS_BSY_BUSY                             1
+
+#define I2C_RESET                                       0x010042
+#define I2C_RESET_BUS_ERROR                             2:2
+#define I2C_RESET_BUS_ERROR_CLEAR                       0
+
+#define I2C_SLAVE_ADDRESS                               0x010043
+#define I2C_SLAVE_ADDRESS_ADDRESS                       7:1
+#define I2C_SLAVE_ADDRESS_RW                            0:0
+#define I2C_SLAVE_ADDRESS_RW_W                          0
+#define I2C_SLAVE_ADDRESS_RW_R                          1
+
+#define I2C_DATA0                                       0x010044
+#define I2C_DATA1                                       0x010045
+#define I2C_DATA2                                       0x010046
+#define I2C_DATA3                                       0x010047
+#define I2C_DATA4                                       0x010048
+#define I2C_DATA5                                       0x010049
+#define I2C_DATA6                                       0x01004A
+#define I2C_DATA7                                       0x01004B
+#define I2C_DATA8                                       0x01004C
+#define I2C_DATA9                                       0x01004D
+#define I2C_DATA10                                      0x01004E
+#define I2C_DATA11                                      0x01004F
+#define I2C_DATA12                                      0x010050
+#define I2C_DATA13                                      0x010051
+#define I2C_DATA14                                      0x010052
+#define I2C_DATA15                                      0x010053
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_regsc.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_regsc.h
new file mode 100644
index 000000000000..e70d39b6bfd5
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_regsc.h
@@ -0,0 +1,900 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  RegSC.h --- SM718 SDK 
+*  This file contains the definitions for the System Configuration registers.
+* 
+*******************************************************************/
+#define SYSTEM_CTRL                                   0x000000
+#define SYSTEM_CTRL_DPMS                              31:30
+#define SYSTEM_CTRL_DPMS_VPHP                         0
+#define SYSTEM_CTRL_DPMS_VPHN                         1
+#define SYSTEM_CTRL_DPMS_VNHP                         2
+#define SYSTEM_CTRL_DPMS_VNHN                         3
+#define SYSTEM_CTRL_PCI_BURST                         29:29
+#define SYSTEM_CTRL_PCI_BURST_OFF                     0
+#define SYSTEM_CTRL_PCI_BURST_ON                      1
+#define SYSTEM_CTRL_PCI_MASTER                        25:25
+#define SYSTEM_CTRL_PCI_MASTER_OFF                    0
+#define SYSTEM_CTRL_PCI_MASTER_ON                     1
+#define SYSTEM_CTRL_LATENCY_TIMER                     24:24
+#define SYSTEM_CTRL_LATENCY_TIMER_ON                  0
+#define SYSTEM_CTRL_LATENCY_TIMER_OFF                 1
+#define SYSTEM_CTRL_DE_FIFO                           23:23
+#define SYSTEM_CTRL_DE_FIFO_NOTEMPTY                  0
+#define SYSTEM_CTRL_DE_FIFO_EMPTY                     1
+#define SYSTEM_CTRL_DE_STATUS                         22:22
+#define SYSTEM_CTRL_DE_STATUS_IDLE                    0
+#define SYSTEM_CTRL_DE_STATUS_BUSY                    1
+#define SYSTEM_CTRL_DE_MEM_FIFO                       21:21
+#define SYSTEM_CTRL_DE_MEM_FIFO_NOTEMPTY              0
+#define SYSTEM_CTRL_DE_MEM_FIFO_EMPTY                 1
+#define SYSTEM_CTRL_CSC_STATUS                        20:20
+#define SYSTEM_CTRL_CSC_STATUS_IDLE                   0
+#define SYSTEM_CTRL_CSC_STATUS_BUSY                   1
+#define SYSTEM_CTRL_SECONDARY_VSYNC                   19:19
+#define SYSTEM_CTRL_SECONDARY_VSYNC_INACTIVE          0
+#define SYSTEM_CTRL_SECONDARY_VSYNC_ACTIVE            1
+#define SYSTEM_CTRL_PRIMARY_VSYNC                     18:18
+#define SYSTEM_CTRL_PRIMARY_VSYNC_INACTIVE            0
+#define SYSTEM_CTRL_PRIMARY_VSYNC_ACTIVE              1
+#define SYSTEM_CTRL_CURRENT_BUFFER                    17:17
+#define SYSTEM_CTRL_CURRENT_BUFFER_NORMAL             0
+#define SYSTEM_CTRL_CURRENT_BUFFER_FLIP_PENDING       1
+#define SYSTEM_CTRL_DMA_STATUS                        16:16
+#define SYSTEM_CTRL_DMA_STATUS_IDLE                   0
+#define SYSTEM_CTRL_DMA_STATUS_BUSY                   1
+#define SYSTEM_CTRL_PCI_BURST_READ                    15:15
+#define SYSTEM_CTRL_PCI_BURST_READ_OFF                0
+#define SYSTEM_CTRL_PCI_BURST_READ_ON                 1
+#define SYSTEM_CTRL_DE_ABORT                          13:13
+#define SYSTEM_CTRL_DE_ABORT_OFF                      0
+#define SYSTEM_CTRL_DE_ABORT_ON                       1
+#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK                11:11
+#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK_OFF            0
+#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK_ON             1
+#define SYSTEM_CTRL_PCI_RETRY                         7:7
+#define SYSTEM_CTRL_PCI_RETRY_ON                      0
+#define SYSTEM_CTRL_PCI_RETRY_OFF                     1
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE         5:4
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_1       0
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_2       1
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_4       2
+#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_8       3
+#define SYSTEM_CTRL_CRT_TRISTATE                      3:3
+#define SYSTEM_CTRL_CRT_TRISTATE_OFF                  0
+#define SYSTEM_CTRL_CRT_TRISTATE_ON                   1
+#define SYSTEM_CTRL_PCIMEM_TRISTATE                   2:2
+#define SYSTEM_CTRL_PCIMEM_TRISTATE_OFF               0
+#define SYSTEM_CTRL_PCIMEM_TRISTATE_ON                1
+#define SYSTEM_CTRL_LOCALMEM_TRISTATE                 1:1
+#define SYSTEM_CTRL_LOCALMEM_TRISTATE_OFF             0
+#define SYSTEM_CTRL_LOCALMEM_TRISTATE_ON              1
+#define SYSTEM_CTRL_PANEL_TRISTATE                    0:0
+#define SYSTEM_CTRL_PANEL_TRISTATE_OFF                0
+#define SYSTEM_CTRL_PANEL_TRISTATE_ON                 1
+
+#define MISC_CTRL                                     0x000004
+#define MISC_CTRL_DRAM_RERESH_COUNT                   27:27
+#define MISC_CTRL_DRAM_RERESH_COUNT_1ROW              0
+#define MISC_CTRL_DRAM_RERESH_COUNT_3ROW              1
+#define MISC_CTRL_DRAM_REFRESH_TIME                   26:25
+#define MISC_CTRL_DRAM_REFRESH_TIME_8                 0
+#define MISC_CTRL_DRAM_REFRESH_TIME_16                1
+#define MISC_CTRL_DRAM_REFRESH_TIME_32                2
+#define MISC_CTRL_DRAM_REFRESH_TIME_64                3
+#define MISC_CTRL_INT_OUTPUT                          24:24
+#define MISC_CTRL_INT_OUTPUT_NORMAL                   0
+#define MISC_CTRL_INT_OUTPUT_INVERT                   1
+#define MISC_CTRL_PLL_CLK_COUNT                       23:23
+#define MISC_CTRL_PLL_CLK_COUNT_OFF                   0
+#define MISC_CTRL_PLL_CLK_COUNT_ON                    1
+#define MISC_CTRL_DAC_POWER                           20:20
+#define MISC_CTRL_DAC_POWER_ON                        0
+#define MISC_CTRL_DAC_POWER_OFF                       1
+#define MISC_CTRL_CLK_SELECT                          16:16
+#define MISC_CTRL_CLK_SELECT_OSC                      0
+#define MISC_CTRL_CLK_SELECT_TESTCLK                  1
+#define MISC_CTRL_DRAM_COLUMN_SIZE                    15:14
+#define MISC_CTRL_DRAM_COLUMN_SIZE_256                0
+#define MISC_CTRL_DRAM_COLUMN_SIZE_512                1
+#define MISC_CTRL_DRAM_COLUMN_SIZE_1024               2
+#define MISC_CTRL_LOCALMEM_SIZE                       13:12
+#define MISC_CTRL_LOCALMEM_SIZE_8M                    3
+#define MISC_CTRL_LOCALMEM_SIZE_16M                   0
+#define MISC_CTRL_LOCALMEM_SIZE_32M                   1
+#define MISC_CTRL_LOCALMEM_SIZE_64M                   2
+#define MISC_CTRL_DRAM_TWTR                           11:11
+#define MISC_CTRL_DRAM_TWTR_2CLK                      0
+#define MISC_CTRL_DRAM_TWTR_1CLK                      1
+#define MISC_CTRL_DRAM_TWR                            10:10
+#define MISC_CTRL_DRAM_TWR_3CLK                       0
+#define MISC_CTRL_DRAM_TWR_2CLK                       1
+#define MISC_CTRL_DRAM_TRP                            9:9
+#define MISC_CTRL_DRAM_TRP_3CLK                       0
+#define MISC_CTRL_DRAM_TRP_4CLK                       1
+#define MISC_CTRL_DRAM_TRFC                           8:8
+#define MISC_CTRL_DRAM_TRFC_12CLK                     0
+#define MISC_CTRL_DRAM_TRFC_14CLK                     1
+#define MISC_CTRL_DRAM_TRAS                           7:7
+#define MISC_CTRL_DRAM_TRAS_7CLK                      0
+#define MISC_CTRL_DRAM_TRAS_8CLK                      1
+#define MISC_CTRL_LOCALMEM_RESET                      6:6
+#define MISC_CTRL_LOCALMEM_RESET_RESET                0
+#define MISC_CTRL_LOCALMEM_RESET_NORMAL               1
+#define MISC_CTRL_LOCALMEM_STATE                      5:5
+#define MISC_CTRL_LOCALMEM_STATE_ACTIVE               0
+#define MISC_CTRL_LOCALMEM_STATE_INACTIVE             1
+#define MISC_CTRL_CPU_CAS_LATENCY                     4:4
+#define MISC_CTRL_CPU_CAS_LATENCY_2CLK                0
+#define MISC_CTRL_CPU_CAS_LATENCY_3CLK                1
+#define MISC_CTRL_DLL                                 3:3
+#define MISC_CTRL_DLL_ON                              0
+#define MISC_CTRL_DLL_OFF                             1
+#define MISC_CTRL_DRAM_OUTPUT                         2:2
+#define MISC_CTRL_DRAM_OUTPUT_LOW                     0
+#define MISC_CTRL_DRAM_OUTPUT_HIGH                    1
+#define MISC_CTRL_LOCALMEM_BUS_SIZE                   1:1
+#define MISC_CTRL_LOCALMEM_BUS_SIZE_32                0
+#define MISC_CTRL_LOCALMEM_BUS_SIZE_64                1
+#define MISC_CTRL_EMBEDDED_LOCALMEM                   0:0
+#define MISC_CTRL_EMBEDDED_LOCALMEM_ON                0
+#define MISC_CTRL_EMBEDDED_LOCALMEM_OFF               1
+
+#define GPIO_MUX                                      0x000008
+#define GPIO_MUX_31                                   31:31
+#define GPIO_MUX_31_GPIO                              0
+#define GPIO_MUX_31_I2C                               1
+#define GPIO_MUX_30                                   30:30
+#define GPIO_MUX_30_GPIO                              0
+#define GPIO_MUX_30_I2C                               1
+#define GPIO_MUX_29                                   29:29
+#define GPIO_MUX_29_GPIO                              0
+#define GPIO_MUX_29_SSP1                              1
+#define GPIO_MUX_28                                   28:28
+#define GPIO_MUX_28_GPIO                              0
+#define GPIO_MUX_28_SSP1                              1
+#define GPIO_MUX_27                                   27:27
+#define GPIO_MUX_27_GPIO                              0
+#define GPIO_MUX_27_SSP1                              1
+#define GPIO_MUX_26                                   26:26
+#define GPIO_MUX_26_GPIO                              0
+#define GPIO_MUX_26_SSP1                              1
+#define GPIO_MUX_25                                   25:25
+#define GPIO_MUX_25_GPIO                              0
+#define GPIO_MUX_25_SSP1                              1
+#define GPIO_MUX_24                                   24:24
+#define GPIO_MUX_24_GPIO                              0
+#define GPIO_MUX_24_SSP0                              1
+#define GPIO_MUX_23                                   23:23
+#define GPIO_MUX_23_GPIO                              0
+#define GPIO_MUX_23_SSP0                              1
+#define GPIO_MUX_22                                   22:22
+#define GPIO_MUX_22_GPIO                              0
+#define GPIO_MUX_22_SSP0                              1
+#define GPIO_MUX_21                                   21:21
+#define GPIO_MUX_21_GPIO                              0
+#define GPIO_MUX_21_SSP0                              1
+#define GPIO_MUX_20                                   20:20
+#define GPIO_MUX_20_GPIO                              0
+#define GPIO_MUX_20_SSP0                              1
+#define GPIO_MUX_19                                   19:19
+#define GPIO_MUX_19_GPIO                              0
+#define GPIO_MUX_19_PWM                               1
+#define GPIO_MUX_18                                   18:18
+#define GPIO_MUX_18_GPIO                              0
+#define GPIO_MUX_18_PWM                               1
+#define GPIO_MUX_17                                   17:17
+#define GPIO_MUX_17_GPIO                              0
+#define GPIO_MUX_17_PWM                               1
+#define GPIO_MUX_16                                   16:16
+#define GPIO_MUX_16_GPIO_ZVPORT                       0
+#define GPIO_MUX_16_TEST_DATA                         1
+#define GPIO_MUX_15                                   15:15
+#define GPIO_MUX_15_GPIO_ZVPORT                       0
+#define GPIO_MUX_15_TEST_DATA                         1
+#define GPIO_MUX_14                                   14:14
+#define GPIO_MUX_14_GPIO_ZVPORT                       0
+#define GPIO_MUX_14_TEST_DATA                         1
+#define GPIO_MUX_13                                   13:13
+#define GPIO_MUX_13_GPIO_ZVPORT                       0
+#define GPIO_MUX_13_TEST_DATA                         1
+#define GPIO_MUX_12                                   12:12
+#define GPIO_MUX_12_GPIO_ZVPORT                       0
+#define GPIO_MUX_12_TEST_DATA                         1
+#define GPIO_MUX_11                                   11:11
+#define GPIO_MUX_11_GPIO_ZVPORT                       0
+#define GPIO_MUX_11_TEST_DATA                         1
+#define GPIO_MUX_10                                   10:10
+#define GPIO_MUX_10_GPIO_ZVPORT                       0
+#define GPIO_MUX_10_TEST_DATA                         1
+#define GPIO_MUX_9                                    9:9
+#define GPIO_MUX_9_GPIO_ZVPORT                        0
+#define GPIO_MUX_9_TEST_DATA                          1
+#define GPIO_MUX_8                                    8:8
+#define GPIO_MUX_8_GPIO_ZVPORT                        0
+#define GPIO_MUX_8_TEST_DATA                          1
+#define GPIO_MUX_7                                    7:7
+#define GPIO_MUX_7_GPIO_ZVPORT                        0
+#define GPIO_MUX_7_TEST_DATA                          1
+#define GPIO_MUX_6                                    6:6
+#define GPIO_MUX_6_GPIO_ZVPORT                        0
+#define GPIO_MUX_6_TEST_DATA                          1
+#define GPIO_MUX_5                                    5:5
+#define GPIO_MUX_5_GPIO_ZVPORT                        0
+#define GPIO_MUX_5_TEST_DATA                          1
+#define GPIO_MUX_4                                    4:4
+#define GPIO_MUX_4_GPIO_ZVPORT                        0
+#define GPIO_MUX_4_TEST_DATA                          1
+#define GPIO_MUX_3                                    3:3
+#define GPIO_MUX_3_GPIO_ZVPORT                        0
+#define GPIO_MUX_3_TEST_DATA                          1
+#define GPIO_MUX_2                                    2:2
+#define GPIO_MUX_2_GPIO_ZVPORT                        0
+#define GPIO_MUX_2_TEST_DATA                          1
+#define GPIO_MUX_1                                    1:1
+#define GPIO_MUX_1_GPIO_ZVPORT                        0
+#define GPIO_MUX_1_TEST_DATA                          1
+#define GPIO_MUX_0                                    0:0
+#define GPIO_MUX_0_GPIO_ZVPORT                        0
+#define GPIO_MUX_0_TEST_DATA                          1
+
+#define LOCALMEM_ARBITRATION                          0x00000C
+#define LOCALMEM_ARBITRATION_ROTATE                   28:28
+#define LOCALMEM_ARBITRATION_ROTATE_OFF               0
+#define LOCALMEM_ARBITRATION_ROTATE_ON                1
+#define LOCALMEM_ARBITRATION_VGA                      26:24
+#define LOCALMEM_ARBITRATION_VGA_OFF                  0
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_1           1
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_2           2
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_3           3
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_4           4
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_5           5
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_6           6
+#define LOCALMEM_ARBITRATION_VGA_PRIORITY_7           7
+#define LOCALMEM_ARBITRATION_DMA                      22:20
+#define LOCALMEM_ARBITRATION_DMA_OFF                  0
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_1           1
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_2           2
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_3           3
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_4           4
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_5           5
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_6           6
+#define LOCALMEM_ARBITRATION_DMA_PRIORITY_7           7
+#define LOCALMEM_ARBITRATION_ZVPORT1                  18:16
+#define LOCALMEM_ARBITRATION_ZVPORT1_OFF              0
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_1       1
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_2       2
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_3       3
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_4       4
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_5       5
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_6       6
+#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_7       7
+#define LOCALMEM_ARBITRATION_ZVPORT0                  14:12
+#define LOCALMEM_ARBITRATION_ZVPORT0_OFF              0
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_1       1
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_2       2
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_3       3
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_4       4
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_5       5
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_6       6
+#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_7       7
+#define LOCALMEM_ARBITRATION_VIDEO                    10:8
+#define LOCALMEM_ARBITRATION_VIDEO_OFF                0
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_1         1
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_2         2
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_3         3
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_4         4
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_5         5
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_6         6
+#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_7         7
+#define LOCALMEM_ARBITRATION_PANEL                    6:4
+#define LOCALMEM_ARBITRATION_PANEL_OFF                0
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_1         1
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_2         2
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_3         3
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_4         4
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_5         5
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_6         6
+#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_7         7
+#define LOCALMEM_ARBITRATION_CRT                      2:0
+#define LOCALMEM_ARBITRATION_CRT_OFF                  0
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_1           1
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_2           2
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_3           3
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_4           4
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_5           5
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_6           6
+#define LOCALMEM_ARBITRATION_CRT_PRIORITY_7           7
+
+#define PCIMEM_ARBITRATION                            0x000010
+#define PCIMEM_ARBITRATION_ROTATE                     28:28
+#define PCIMEM_ARBITRATION_ROTATE_OFF                 0
+#define PCIMEM_ARBITRATION_ROTATE_ON                  1
+#define PCIMEM_ARBITRATION_VGA                        26:24
+#define PCIMEM_ARBITRATION_VGA_OFF                    0
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_1             1
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_2             2
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_3             3
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_4             4
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_5             5
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_6             6
+#define PCIMEM_ARBITRATION_VGA_PRIORITY_7             7
+#define PCIMEM_ARBITRATION_DMA                        22:20
+#define PCIMEM_ARBITRATION_DMA_OFF                    0
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_1             1
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_2             2
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_3             3
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_4             4
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_5             5
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_6             6
+#define PCIMEM_ARBITRATION_DMA_PRIORITY_7             7
+#define PCIMEM_ARBITRATION_ZVPORT1                    18:16
+#define PCIMEM_ARBITRATION_ZVPORT1_OFF                0
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_1         1
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_2         2
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_3         3
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_4         4
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_5         5
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_6         6
+#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_7         7
+#define PCIMEM_ARBITRATION_ZVPORT0                    14:12
+#define PCIMEM_ARBITRATION_ZVPORT0_OFF                0
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_1         1
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_2         2
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_3         3
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_4         4
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_5         5
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_6         6
+#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_7         7
+#define PCIMEM_ARBITRATION_VIDEO                      10:8
+#define PCIMEM_ARBITRATION_VIDEO_OFF                  0
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_1           1
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_2           2
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_3           3
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_4           4
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_5           5
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_6           6
+#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_7           7
+#define PCIMEM_ARBITRATION_PANEL                      6:4
+#define PCIMEM_ARBITRATION_PANEL_OFF                  0
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_1           1
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_2           2
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_3           3
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_4           4
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_5           5
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_6           6
+#define PCIMEM_ARBITRATION_PANEL_PRIORITY_7           7
+#define PCIMEM_ARBITRATION_CRT                        2:0
+#define PCIMEM_ARBITRATION_CRT_OFF                    0
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_1             1
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_2             2
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_3             3
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_4             4
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_5             5
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_6             6
+#define PCIMEM_ARBITRATION_CRT_PRIORITY_7             7
+
+#define RAW_INT                                       0x000020
+#define RAW_INT_ZVPORT1_VSYNC                         4:4
+#define RAW_INT_ZVPORT1_VSYNC_INACTIVE                0
+#define RAW_INT_ZVPORT1_VSYNC_ACTIVE                  1
+#define RAW_INT_ZVPORT1_VSYNC_CLEAR                   1
+#define RAW_INT_ZVPORT0_VSYNC                         3:3
+#define RAW_INT_ZVPORT0_VSYNC_INACTIVE                0
+#define RAW_INT_ZVPORT0_VSYNC_ACTIVE                  1
+#define RAW_INT_ZVPORT0_VSYNC_CLEAR                   1
+#define RAW_INT_SECONDARY_VSYNC                       2:2
+#define RAW_INT_SECONDARY_VSYNC_INACTIVE              0
+#define RAW_INT_SECONDARY_VSYNC_ACTIVE                1
+#define RAW_INT_SECONDARY_VSYNC_CLEAR                 1
+#define RAW_INT_PRIMARY_VSYNC                         1:1
+#define RAW_INT_PRIMARY_VSYNC_INACTIVE                0
+#define RAW_INT_PRIMARY_VSYNC_ACTIVE                  1
+#define RAW_INT_PRIMARY_VSYNC_CLEAR                   1
+#define RAW_INT_VGA_VSYNC                             0:0
+#define RAW_INT_VGA_VSYNC_INACTIVE                    0
+#define RAW_INT_VGA_VSYNC_ACTIVE                      1
+#define RAW_INT_VGA_VSYNC_CLEAR                       1
+
+#define INT_STATUS                                    0x000024
+#define INT_STATUS_GPIO31                             31:31
+#define INT_STATUS_GPIO31_INACTIVE                    0
+#define INT_STATUS_GPIO31_ACTIVE                      1
+#define INT_STATUS_GPIO30                             30:30
+#define INT_STATUS_GPIO30_INACTIVE                    0
+#define INT_STATUS_GPIO30_ACTIVE                      1
+#define INT_STATUS_GPIO29                             29:29
+#define INT_STATUS_GPIO29_INACTIVE                    0
+#define INT_STATUS_GPIO29_ACTIVE                      1
+#define INT_STATUS_GPIO28                             28:28
+#define INT_STATUS_GPIO28_INACTIVE                    0
+#define INT_STATUS_GPIO28_ACTIVE                      1
+#define INT_STATUS_GPIO27                             27:27
+#define INT_STATUS_GPIO27_INACTIVE                    0
+#define INT_STATUS_GPIO27_ACTIVE                      1
+#define INT_STATUS_GPIO26                             26:26
+#define INT_STATUS_GPIO26_INACTIVE                    0
+#define INT_STATUS_GPIO26_ACTIVE                      1
+#define INT_STATUS_GPIO25                             25:25
+#define INT_STATUS_GPIO25_INACTIVE                    0
+#define INT_STATUS_GPIO25_ACTIVE                      1
+#define INT_STATUS_I2C                                12:12
+#define INT_STATUS_I2C_INACTIVE                       0
+#define INT_STATUS_I2C_ACTIVE                         1
+#define INT_STATUS_PWM                                11:11
+#define INT_STATUS_PWM_INACTIVE                       0
+#define INT_STATUS_PWM_ACTIVE                         1
+#if 1   /* SM750 new definition (DMA0 is removed in SM750), therefore, the interrupt is
+           moved to the DMA0 location.
+         */
+    #define INT_STATUS_DMA1                           9:9
+    #define INT_STATUS_DMA1_INACTIVE                  0
+    #define INT_STATUS_DMA1_ACTIVE                    1
+#else
+    #define INT_STATUS_DMA1                           10:10
+    #define INT_STATUS_DMA1_INACTIVE                  0
+    #define INT_STATUS_DMA1_ACTIVE                    1
+    #define INT_STATUS_DMA0                           9:9
+    #define INT_STATUS_DMA0_INACTIVE                  0
+    #define INT_STATUS_DMA0_ACTIVE                    1
+#endif
+#define INT_STATUS_PCI                                8:8
+#define INT_STATUS_PCI_INACTIVE                       0
+#define INT_STATUS_PCI_ACTIVE                         1
+#define INT_STATUS_SSP1                               7:7
+#define INT_STATUS_SSP1_INACTIVE                      0
+#define INT_STATUS_SSP1_ACTIVE                        1
+#define INT_STATUS_SSP0                               6:6
+#define INT_STATUS_SSP0_INACTIVE                      0
+#define INT_STATUS_SSP0_ACTIVE                        1
+#define INT_STATUS_DE                                 5:5
+#define INT_STATUS_DE_INACTIVE                        0
+#define INT_STATUS_DE_ACTIVE                          1
+#define INT_STATUS_ZVPORT1_VSYNC                      4:4
+#define INT_STATUS_ZVPORT1_VSYNC_INACTIVE             0
+#define INT_STATUS_ZVPORT1_VSYNC_ACTIVE               1
+#define INT_STATUS_ZVPORT0_VSYNC                      3:3
+#define INT_STATUS_ZVPORT0_VSYNC_INACTIVE             0
+#define INT_STATUS_ZVPORT0_VSYNC_ACTIVE               1
+#define INT_STATUS_SECONDARY_VSYNC                    2:2
+#define INT_STATUS_SECONDARY_VSYNC_INACTIVE           0
+#define INT_STATUS_SECONDARY_VSYNC_ACTIVE             1
+#define INT_STATUS_PRIMARY_VSYNC                      1:1
+#define INT_STATUS_PRIMARY_VSYNC_INACTIVE             0
+#define INT_STATUS_PRIMARY_VSYNC_ACTIVE               1
+#define INT_STATUS_VGA_VSYNC                          0:0
+#define INT_STATUS_VGA_VSYNC_INACTIVE                 0
+#define INT_STATUS_VGA_VSYNC_ACTIVE                   1
+
+#define INT_MASK                                      0x000028
+#define INT_MASK_GPIO31                               31:31
+#define INT_MASK_GPIO31_DISABLE                       0
+#define INT_MASK_GPIO31_ENABLE                        1
+#define INT_MASK_GPIO30                               30:30
+#define INT_MASK_GPIO30_DISABLE                       0
+#define INT_MASK_GPIO30_ENABLE                        1
+#define INT_MASK_GPIO29                               29:29
+#define INT_MASK_GPIO29_DISABLE                       0
+#define INT_MASK_GPIO29_ENABLE                        1
+#define INT_MASK_GPIO28                               28:28
+#define INT_MASK_GPIO28_DISABLE                       0
+#define INT_MASK_GPIO28_ENABLE                        1
+#define INT_MASK_GPIO27                               27:27
+#define INT_MASK_GPIO27_DISABLE                       0
+#define INT_MASK_GPIO27_ENABLE                        1
+#define INT_MASK_GPIO26                               26:26
+#define INT_MASK_GPIO26_DISABLE                       0
+#define INT_MASK_GPIO26_ENABLE                        1
+#define INT_MASK_GPIO25                               25:25
+#define INT_MASK_GPIO25_DISABLE                       0
+#define INT_MASK_GPIO25_ENABLE                        1
+#define INT_MASK_I2C                                  12:12
+#define INT_MASK_I2C_DISABLE                          0
+#define INT_MASK_I2C_ENABLE                           1
+#define INT_MASK_PWM                                  11:11
+#define INT_MASK_PWM_DISABLE                          0
+#define INT_MASK_PWM_ENABLE                           1
+#if 1   /* SM750 new definition (DMA0 is removed in SM750), therefore, the interrupt is
+           moved to the DMA0 location.
+         */
+    #define INT_MASK_DMA1                             9:9
+    #define INT_MASK_DMA1_DISABLE                     0
+    #define INT_MASK_DMA1_ENABLE                      1
+#else
+    #define INT_MASK_DMA1                             10:10
+    #define INT_MASK_DMA1_DISABLE                     0
+    #define INT_MASK_DMA1_ENABLE                      1
+    #define INT_MASK_DMA                              9:9
+    #define INT_MASK_DMA_DISABLE                      0
+    #define INT_MASK_DMA_ENABLE                       1
+#endif
+#define INT_MASK_PCI                                  8:8
+#define INT_MASK_PCI_DISABLE                          0
+#define INT_MASK_PCI_ENABLE                           1
+#define INT_MASK_SSP1                                 7:7
+#define INT_MASK_SSP1_DISABLE                         0
+#define INT_MASK_SSP1_ENABLE                          1
+#define INT_MASK_SSP0                                 6:6
+#define INT_MASK_SSP0_DISABLE                         0
+#define INT_MASK_SSP0_ENABLE                          1
+#define INT_MASK_DE                                   5:5
+#define INT_MASK_DE_DISABLE                           0
+#define INT_MASK_DE_ENABLE                            1
+#define INT_MASK_ZVPORT1_VSYNC                        4:4
+#define INT_MASK_ZVPORT1_VSYNC_DISABLE                0
+#define INT_MASK_ZVPORT1_VSYNC_ENABLE                 1
+#define INT_MASK_ZVPORT0_VSYNC                        3:3
+#define INT_MASK_ZVPORT0_VSYNC_DISABLE                0
+#define INT_MASK_ZVPORT0_VSYNC_ENABLE                 1
+#define INT_MASK_SECONDARY_VSYNC                      2:2
+#define INT_MASK_SECONDARY_VSYNC_DISABLE              0
+#define INT_MASK_SECONDARY_VSYNC_ENABLE               1
+#define INT_MASK_PRIMARY_VSYNC                        1:1
+#define INT_MASK_PRIMARY_VSYNC_DISABLE                0
+#define INT_MASK_PRIMARY_VSYNC_ENABLE                 1
+#define INT_MASK_VGA_VSYNC                            0:0
+#define INT_MASK_VGA_VSYNC_DISABLE                    0
+#define INT_MASK_VGA_VSYNC_ENABLE                     1
+
+#define CURRENT_GATE                                  0x000040
+#define CURRENT_GATE_MCLK                             15:14
+#define CURRENT_GATE_MCLK_DIV_3                       0
+#define CURRENT_GATE_MCLK_DIV_4                       1
+#define CURRENT_GATE_MCLK_DIV_6                       2
+#define CURRENT_GATE_MCLK_DIV_8                       3
+#define CURRENT_GATE_M2XCLK                           13:12
+#define CURRENT_GATE_M2XCLK_DIV_1                     0
+#define CURRENT_GATE_M2XCLK_DIV_2                     1
+#define CURRENT_GATE_M2XCLK_DIV_3                     2
+#define CURRENT_GATE_M2XCLK_DIV_4                     3
+#define CURRENT_GATE_VGA                              10:10
+#define CURRENT_GATE_VGA_OFF                          0
+#define CURRENT_GATE_VGA_ON                           1
+#define CURRENT_GATE_PWM                              9:9
+#define CURRENT_GATE_PWM_OFF                          0
+#define CURRENT_GATE_PWM_ON                           1
+#define CURRENT_GATE_I2C                              8:8
+#define CURRENT_GATE_I2C_OFF                          0
+#define CURRENT_GATE_I2C_ON                           1
+#define CURRENT_GATE_SSP                              7:7
+#define CURRENT_GATE_SSP_OFF                          0
+#define CURRENT_GATE_SSP_ON                           1
+#define CURRENT_GATE_GPIO                             6:6
+#define CURRENT_GATE_GPIO_OFF                         0
+#define CURRENT_GATE_GPIO_ON                          1
+#define CURRENT_GATE_ZVPORT                           5:5
+#define CURRENT_GATE_ZVPORT_OFF                       0
+#define CURRENT_GATE_ZVPORT_ON                        1
+#define CURRENT_GATE_CSC                              4:4
+#define CURRENT_GATE_CSC_OFF                          0
+#define CURRENT_GATE_CSC_ON                           1
+#define CURRENT_GATE_DE                               3:3
+#define CURRENT_GATE_DE_OFF                           0
+#define CURRENT_GATE_DE_ON                            1
+#define CURRENT_GATE_DISPLAY                          2:2
+#define CURRENT_GATE_DISPLAY_OFF                      0
+#define CURRENT_GATE_DISPLAY_ON                       1
+#define CURRENT_GATE_LOCALMEM                         1:1
+#define CURRENT_GATE_LOCALMEM_OFF                     0
+#define CURRENT_GATE_LOCALMEM_ON                      1
+#define CURRENT_GATE_DMA                              0:0
+#define CURRENT_GATE_DMA_OFF                          0
+#define CURRENT_GATE_DMA_ON                           1
+
+#define MODE0_GATE                                    0x000044
+#define MODE0_GATE_MCLK                               15:14
+#define MODE0_GATE_MCLK_112MHZ                        0
+#define MODE0_GATE_MCLK_84MHZ                         1
+#define MODE0_GATE_MCLK_56MHZ                         2
+#define MODE0_GATE_MCLK_42MHZ                         3
+#define MODE0_GATE_M2XCLK                             13:12
+#define MODE0_GATE_M2XCLK_336MHZ                      0
+#define MODE0_GATE_M2XCLK_168MHZ                      1
+#define MODE0_GATE_M2XCLK_112MHZ                      2
+#define MODE0_GATE_M2XCLK_84MHZ                       3
+#define MODE0_GATE_VGA                                10:10
+#define MODE0_GATE_VGA_OFF                            0
+#define MODE0_GATE_VGA_ON                             1
+#define MODE0_GATE_PWM                                9:9
+#define MODE0_GATE_PWM_OFF                            0
+#define MODE0_GATE_PWM_ON                             1
+#define MODE0_GATE_I2C                                8:8
+#define MODE0_GATE_I2C_OFF                            0
+#define MODE0_GATE_I2C_ON                             1
+#define MODE0_GATE_SSP                                7:7
+#define MODE0_GATE_SSP_OFF                            0
+#define MODE0_GATE_SSP_ON                             1
+#define MODE0_GATE_GPIO                               6:6
+#define MODE0_GATE_GPIO_OFF                           0
+#define MODE0_GATE_GPIO_ON                            1
+#define MODE0_GATE_ZVPORT                             5:5
+#define MODE0_GATE_ZVPORT_OFF                         0
+#define MODE0_GATE_ZVPORT_ON                          1
+#define MODE0_GATE_CSC                                4:4
+#define MODE0_GATE_CSC_OFF                            0
+#define MODE0_GATE_CSC_ON                             1
+#define MODE0_GATE_DE                                 3:3
+#define MODE0_GATE_DE_OFF                             0
+#define MODE0_GATE_DE_ON                              1
+#define MODE0_GATE_DISPLAY                            2:2
+#define MODE0_GATE_DISPLAY_OFF                        0
+#define MODE0_GATE_DISPLAY_ON                         1
+#define MODE0_GATE_LOCALMEM                           1:1
+#define MODE0_GATE_LOCALMEM_OFF                       0
+#define MODE0_GATE_LOCALMEM_ON                        1
+#define MODE0_GATE_DMA                                0:0
+#define MODE0_GATE_DMA_OFF                            0
+#define MODE0_GATE_DMA_ON                             1
+
+#define MODE1_GATE                                    0x000048
+#define MODE1_GATE_MCLK                               15:14
+#define MODE1_GATE_MCLK_112MHZ                        0
+#define MODE1_GATE_MCLK_84MHZ                         1
+#define MODE1_GATE_MCLK_56MHZ                         2
+#define MODE1_GATE_MCLK_42MHZ                         3
+#define MODE1_GATE_M2XCLK                             13:12
+#define MODE1_GATE_M2XCLK_336MHZ                      0
+#define MODE1_GATE_M2XCLK_168MHZ                      1
+#define MODE1_GATE_M2XCLK_112MHZ                      2
+#define MODE1_GATE_M2XCLK_84MHZ                       3
+#define MODE1_GATE_VGA                                10:10
+#define MODE1_GATE_VGA_OFF                            0
+#define MODE1_GATE_VGA_ON                             1
+#define MODE1_GATE_PWM                                9:9
+#define MODE1_GATE_PWM_OFF                            0
+#define MODE1_GATE_PWM_ON                             1
+#define MODE1_GATE_I2C                                8:8
+#define MODE1_GATE_I2C_OFF                            0
+#define MODE1_GATE_I2C_ON                             1
+#define MODE1_GATE_SSP                                7:7
+#define MODE1_GATE_SSP_OFF                            0
+#define MODE1_GATE_SSP_ON                             1
+#define MODE1_GATE_GPIO                               6:6
+#define MODE1_GATE_GPIO_OFF                           0
+#define MODE1_GATE_GPIO_ON                            1
+#define MODE1_GATE_ZVPORT                             5:5
+#define MODE1_GATE_ZVPORT_OFF                         0
+#define MODE1_GATE_ZVPORT_ON                          1
+#define MODE1_GATE_CSC                                4:4
+#define MODE1_GATE_CSC_OFF                            0
+#define MODE1_GATE_CSC_ON                             1
+#define MODE1_GATE_DE                                 3:3
+#define MODE1_GATE_DE_OFF                             0
+#define MODE1_GATE_DE_ON                              1
+#define MODE1_GATE_DISPLAY                            2:2
+#define MODE1_GATE_DISPLAY_OFF                        0
+#define MODE1_GATE_DISPLAY_ON                         1
+#define MODE1_GATE_LOCALMEM                           1:1
+#define MODE1_GATE_LOCALMEM_OFF                       0
+#define MODE1_GATE_LOCALMEM_ON                        1
+#define MODE1_GATE_DMA                                0:0
+#define MODE1_GATE_DMA_OFF                            0
+#define MODE1_GATE_DMA_ON                             1
+
+#define POWER_MODE_CTRL                               0x00004C
+#define POWER_MODE_CTRL_OSC_INPUT                     3:3
+#define POWER_MODE_CTRL_OSC_INPUT_OFF                 0
+#define POWER_MODE_CTRL_OSC_INPUT_ON                  1
+#define POWER_MODE_CTRL_ACPI                          2:2
+#define POWER_MODE_CTRL_ACPI_OFF                      0
+#define POWER_MODE_CTRL_ACPI_ON                       1
+#define POWER_MODE_CTRL_MODE                          1:0
+#define POWER_MODE_CTRL_MODE_MODE0                    0
+#define POWER_MODE_CTRL_MODE_MODE1                    1
+#define POWER_MODE_CTRL_MODE_SLEEP                    2
+
+/* This definition is for SM750 */
+#define PCI_MASTER_BASE                               0x000050
+#define PCI_MASTER_BASE_ADDRESS                       7:0
+
+/* This definition is for SM718 */
+#define SM718_PCI_MASTER_BASE                         0x000050
+#define SM718_PCI_MASTER_BASE_ADDRESS                 31:20
+
+#define DEVICE_ID                                     0x000054
+#define DEVICE_ID_DEVICE_ID                           31:16
+#define DEVICE_ID_REVISION_ID                         7:0
+
+#define PLL_CLK_COUNT                                 0x000058
+#define PLL_CLK_COUNT_COUNTER                         15:0
+
+#define PRIMARY_PLL_CTRL                              0x00005C
+#define PRIMARY_PLL_CTRL_BYPASS                       18:18
+#define PRIMARY_PLL_CTRL_BYPASS_OFF                   0
+#define PRIMARY_PLL_CTRL_BYPASS_ON                    1
+#define PRIMARY_PLL_CTRL_POWER                        17:17
+#define PRIMARY_PLL_CTRL_POWER_OFF                    0
+#define PRIMARY_PLL_CTRL_POWER_ON                     1
+#define PRIMARY_PLL_CTRL_INPUT                        16:16
+#define PRIMARY_PLL_CTRL_INPUT_OSC                    0
+#define PRIMARY_PLL_CTRL_INPUT_TESTCLK                1
+#define PRIMARY_PLL_CTRL_POD                          15:14
+#define PRIMARY_PLL_CTRL_OD                           13:12
+#define PRIMARY_PLL_CTRL_N                            11:8
+#define PRIMARY_PLL_CTRL_M                            7:0
+
+#define SECONDARY_PLL_CTRL                            0x000060
+#define SECONDARY_PLL_CTRL_BYPASS                     18:18
+#define SECONDARY_PLL_CTRL_BYPASS_OFF                 0
+#define SECONDARY_PLL_CTRL_BYPASS_ON                  1
+#define SECONDARY_PLL_CTRL_POWER                      17:17
+#define SECONDARY_PLL_CTRL_POWER_OFF                  0
+#define SECONDARY_PLL_CTRL_POWER_ON                   1
+#define SECONDARY_PLL_CTRL_INPUT                      16:16
+#define SECONDARY_PLL_CTRL_INPUT_OSC                  0
+#define SECONDARY_PLL_CTRL_INPUT_TESTCLK              1
+#define SECONDARY_PLL_CTRL_POD                        15:14
+#define SECONDARY_PLL_CTRL_OD                         13:12    
+#define SECONDARY_PLL_CTRL_N                          11:8
+#define SECONDARY_PLL_CTRL_M                          7:0
+
+#define VGA_PLL0_CTRL                                 0x000064
+#define VGA_PLL0_CTRL_BYPASS                          18:18
+#define VGA_PLL0_CTRL_BYPASS_OFF                      0
+#define VGA_PLL0_CTRL_BYPASS_ON                       1
+#define VGA_PLL0_CTRL_POWER                           17:17
+#define VGA_PLL0_CTRL_POWER_OFF                       0
+#define VGA_PLL0_CTRL_POWER_ON                        1
+#define VGA_PLL0_CTRL_INPUT                           16:16
+#define VGA_PLL0_CTRL_INPUT_OSC                       0
+#define VGA_PLL0_CTRL_INPUT_TESTCLK                   1
+#define VGA_PLL0_CTRL_POD                             15:14
+#define VGA_PLL0_CTRL_OD                              13:12
+#define VGA_PLL0_CTRL_N                               11:8
+#define VGA_PLL0_CTRL_M                               7:0
+
+#define VGA_PLL1_CTRL                                 0x000068
+#define VGA_PLL1_CTRL_BYPASS                          18:18
+#define VGA_PLL1_CTRL_BYPASS_OFF                      0
+#define VGA_PLL1_CTRL_BYPASS_ON                       1
+#define VGA_PLL1_CTRL_POWER                           17:17
+#define VGA_PLL1_CTRL_POWER_OFF                       0
+#define VGA_PLL1_CTRL_POWER_ON                        1
+#define VGA_PLL1_CTRL_INPUT                           16:16
+#define VGA_PLL1_CTRL_INPUT_OSC                       0
+#define VGA_PLL1_CTRL_INPUT_TESTCLK                   1
+#define VGA_PLL1_CTRL_POD                             15:14
+#define VGA_PLL1_CTRL_OD                              13:12
+#define VGA_PLL1_CTRL_N                               11:8
+#define VGA_PLL1_CTRL_M                               7:0
+#define VGA_PLL1_MASK                                 0x00FFFFFF
+
+/* Use peekRegisterByte to access this scratch data */
+#define SCRATCH_DATA                                  0x00006b
+/* The following register is used by HW */
+/*#define SCRATCH_DATA                                  0x00006c*/
+
+#define MXCLK_PLL_CTRL                                0x000070
+#define MXCLK_PLL_CTRL_BYPASS                         18:18
+#define MXCLK_PLL_CTRL_BYPASS_OFF                     0
+#define MXCLK_PLL_CTRL_BYPASS_ON                      1
+#define MXCLK_PLL_CTRL_POWER                          17:17
+#define MXCLK_PLL_CTRL_POWER_OFF                      0
+#define MXCLK_PLL_CTRL_POWER_ON                       1
+#define MXCLK_PLL_CTRL_INPUT                          16:16
+#define MXCLK_PLL_CTRL_INPUT_OSC                      0
+#define MXCLK_PLL_CTRL_INPUT_TESTCLK                  1
+#define MXCLK_PLL_CTRL_POD                            15:14
+#define MXCLK_PLL_CTRL_OD                             13:12
+#define MXCLK_PLL_CTRL_N                              11:8
+#define MXCLK_PLL_CTRL_M                              7:0
+
+/* Host Interface registers support. Only applies to SM718 */
+#define HOST_INTERFACE                                0x000074
+#define HOST_INTERFACE_NON_CACHE_ADDRESS              30:17
+/* The following status is read-only. 
+   When SM718 is transitioning back from sleep mode to normal mode, software needs 
+   to poll this bit until it becomes "0" before writing any other command to the chip. */
+#define HOST_INTERFACE_STATUS                         16:16
+#define HOST_INTERFACE_STATUS_NORMAL                  0
+#define HOST_INTERFACE_STATUS_SLEEP                   1
+#define HOST_INTERFACE_CPU                            15:15
+#define HOST_INTERFACE_CPU_32BIT                      0
+#define HOST_INTERFACE_CPU_16BIT                      1
+#define HOST_INTERFACE_XSCALE_INPUT_SOURCE            14:14
+#define HOST_INTERFACE_XSCALE_INPUT_SOURCE_PLL        0
+#define HOST_INTERFACE_XSCALE_INPUT_SOURCE_HCLK       1
+#define HOST_INTERFACE_ENDIAN                         7:7
+#define HOST_INTERFACE_ENDIAN_LITTLE                  0
+#define HOST_INTERFACE_ENDIAN_BIG                     1
+/* The following polarity is determined by GPIO20 pin at reset */
+#define HOST_INTERFACE_HITACHI_POLARITY               6:6
+#define HOST_INTERFACE_HITACHI_POLARITY_ACTIVE_LOW    0
+#define HOST_INTERFACE_HITACHI_POLARITY_ACTIVE_HIGH   1
+#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION        5:5
+#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION_30MB   0
+#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION_62MB   1
+#define HOST_INTERFACE_SH4_READY                      4:3
+#define HOST_INTERFACE_SH4_READY_ONE_CLOCK            0
+#define HOST_INTERFACE_SH4_READY_TWO_CLOCKS           1
+#define HOST_INTERFACE_SH4_READY_CS_CONTROL           2
+/* The following bus type is determined by GPIO19, GPIO18, and GPIO17 pins at reset */
+#define HOST_INTERFACE_BUS_TYPE                       2:0
+#define HOST_INTERFACE_BUS_TYPE_HITACHI_SH3_SH4       0
+#define HOST_INTERFACE_BUS_TYPE_PCI                   1
+#define HOST_INTERFACE_BUS_TYPE_INTEL_XSCALE          2
+#define HOST_INTERFACE_BUS_TYPE_NEC                   6
+
+/* System memory register. Only applies to SM718 */
+#define SYSTEM_MEMORY                                 0x000078
+/* Extend the bus holding when SM718 is a host bust master to access system SDRAM. */
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT            23:20
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_0          0
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_16         1
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_32         2
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_48         3
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_64         4
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_80         5
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_96         6
+#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_112        7
+#define SYSTEM_MEMORY_BURST_LENGTH                    19:17
+#define SYSTEM_MEMORY_BURST_LENGTH_1_WORD             0
+#define SYSTEM_MEMORY_BURST_LENGTH_2_WORDS            1
+#define SYSTEM_MEMORY_BURST_LENGTH_4_WORDS            2
+#define SYSTEM_MEMORY_BURST_LENGTH_8_WORDS            3
+#define SYSTEM_MEMORY_CAS_LATENCY                     16:16
+#define SYSTEM_MEMORY_CAS_LATENCY_2_CLOCKS            0
+#define SYSTEM_MEMORY_CAS_LATENCY_3_CLOCKS            1
+#define SYSTEM_MEMORY_BUS_HOLD_TIME                   15:13
+#define SYSTEM_MEMORY_BUS_HOLD_TIME_FIFO_EMPTY        0
+#define SYSTEM_MEMORY_BUS_HOLD_TIME_8_TRANSACTIONS    1
+#define SYSTEM_MEMORY_BUS_HOLD_TIME_16_TRANSACTIONS   2
+#define SYSTEM_MEMORY_BUS_HOLD_TIME_24_TRANSACTIONS   3
+#define SYSTEM_MEMORY_BUS_HOLD_TIME_32_TRANSACTIONS   4
+#define SYSTEM_MEMORY_COLUMN_SIZE                     12:11
+#define SYSTEM_MEMORY_COLUMN_SIZE_1024_WORDS          0
+#define SYSTEM_MEMORY_COLUMN_SIZE_512_WORDS           2
+#define SYSTEM_MEMORY_COLUMN_SIZE_256_WORDS           3
+#define SYSTEM_MEMORY_SIZE                            10:8
+#define SYSTEM_MEMORY_SIZE_2MB                        0
+#define SYSTEM_MEMORY_SIZE_4MB                        1
+#define SYSTEM_MEMORY_SIZE_64MB                       4
+#define SYSTEM_MEMORY_SIZE_32MB                       5
+#define SYSTEM_MEMORY_SIZE_16MB                       6
+#define SYSTEM_MEMORY_SIZE_8MB                        7
+/* System Memory Active to Pre-charge delay */
+#define SYSTEM_MEMORY_ACTIVE_DELAY                    7:7
+#define SYSTEM_MEMORY_ACTIVE_DELAY_6_CLOCKS           0
+#define SYSTEM_MEMORY_ACTIVE_DELAY_7_CLOCKS           1
+/* System Memory Write to Pre-charge delay */
+#define SYSTEM_MEMORY_WRITE_DELAY                     6:6
+#define SYSTEM_MEMORY_WRITE_DELAY_2_CLOCKS            0
+#define SYSTEM_MEMORY_WRITE_DELAY_1_CLOCK             1
+#define SYSTEM_MEMORY_BANK                            5:5
+#define SYSTEM_MEMORY_BANK_4                          0
+#define SYSTEM_MEMORY_BANK_2                          1
+#define SYSTEM_MEMORY_RESET                           4:4
+#define SYSTEM_MEMORY_RESET_ENABLE                    0
+#define SYSTEM_MEMORY_RESET_DISABLE                   1
+/* Delay time to latch read data for external SDRAM controller (in 1/2 ns step) */
+#define SYSTEM_MEMORY_LATCH_DELAY                     3:1
+#define SYSTEM_MEMORY_LATCH_DELAY_0                   0
+#define SYSTEM_MEMORY_LATCH_DELAY_1                   1
+#define SYSTEM_MEMORY_LATCH_DELAY_2                   2
+#define SYSTEM_MEMORY_LATCH_DELAY_3                   3
+#define SYSTEM_MEMORY_LATCH_DELAY_4                   4
+#define SYSTEM_MEMORY_LATCH_DELAY_5                   5
+#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH         0:0
+#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH_8       0
+#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH_1       1
+
+#define VGA_CONFIGURATION                             0x000088
+#define	VGA_CONFIGURATION_A0000_ACCESS				  7:7
+#define VGA_CONFIGURATION_A0000_ACCESS_DISABLE        0
+#define VGA_CONFIGURATION_A0000_ACCESS_ENABLE         1
+#define VGA_CONFIGURATION_USER_DEFINE                 5:4
+#define VGA_CONFIGURATION_PLL                         2:2
+#define VGA_CONFIGURATION_PLL_VGA                     0
+#define VGA_CONFIGURATION_PLL_PRIMARY                 1
+#define VGA_CONFIGURATION_MODE                        1:1
+#define VGA_CONFIGURATION_MODE_TEXT                   0
+#define VGA_CONFIGURATION_MODE_GRAPHIC                1
+/* The following only applies to SM718 (Strap pin MA Line 11) */
+#define VGA_CONFIGURATION_C0000_ACCESS                0:0
+#define VGA_CONFIGURATION_C0000_ACCESS_DISABLE        0
+#define VGA_CONFIGURATION_C0000_ACCESS_ENABLE         1
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.c
new file mode 100644
index 000000000000..17d7597a6cd3
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.c
@@ -0,0 +1,91 @@
+#ifdef USE_HDMICHIP
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>	
+
+
+#include "siHdmiTx_902x_TPI.h"
+#include "ddk750_hwi2c.h"
+#include "ddk750_swi2c.h"
+
+
+#define SII9022_DEVICE_ID					0xb0
+
+#define i2cWriteReg swI2CWriteReg
+#define i2cReadReg  swI2CReadReg
+
+
+
+unsigned char sii9022xIsConnected(void)	
+{
+	return 1;
+}
+
+__attribute__((unused)) static void dump9022a(uint8_t reg)
+{
+#if 1
+	printk("reg%x=%x\n",reg,i2cReadReg(SII9022A_I2C_ADDRESS,reg));
+#endif
+}
+int sii9022xSetMode(int num)
+{
+	int ret;
+
+	swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
+	siHdmiTx_VideoSel(num);
+	siHdmiTx_AudioSel(0x02);
+	siHdmiTx_TPI_Init();
+	ret = siHdmiTx_VideoSet();
+	i2cWriteReg(SII9022A_I2C_ADDRESS,0x63,0);
+	return ret;
+}
+
+int sii9022xInitChip(void)
+{
+	int  rcc,retries = 10;
+    
+	swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
+	
+	/* enter TPI mode */
+    	i2cWriteReg(SII9022A_I2C_ADDRESS,0xc7,0);
+	do{
+		msleep(1);
+		rcc = i2cReadReg(SII9022A_I2C_ADDRESS,0x1B);
+	}while((rcc != SII9022_DEVICE_ID) && retries--);
+
+	if(rcc != SII9022_DEVICE_ID){
+		printk("cannot detect sii9022a chip:rcc=%x\n",rcc);
+		return -1;
+	}
+	return 0;
+}
+
+byte SysCtrlReg;
+
+int ddk750_GetDDC_9022Access(void)
+{
+	int ret = 0;
+	swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
+	ret = GetDDC_Access(&SysCtrlReg);
+	return ret;	
+}
+
+
+
+int  ddk750_Release9022DDC(void)
+{
+	int ret = ReleaseDDC(SysCtrlReg);
+	return ret;
+}
+
+void ddk750_DoEdidRead(void)
+{
+        DoEdidRead();
+}
+
+
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.h
new file mode 100644
index 000000000000..c47cfeb0e93e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_sii9022.h
@@ -0,0 +1,7 @@
+int sii9022xInitChip(void);
+int sii9022xSetMode(int);
+unsigned char sii9022xIsConnected(void);
+int ddk750_GetDDC_9022Access(void);
+int ddk750_Release9022DDC(void);
+void ddk750_DoEdidRead(void);
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_sw2d.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_sw2d.h
new file mode 100644
index 000000000000..a52f69de32c2
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_sw2d.h
@@ -0,0 +1,200 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  sw2d.h --- SM750/SM718 DDK 
+*  This file contains the function prototype for 2D Function
+*  implementation.
+* 
+*******************************************************************/
+#ifndef _SW2D_H_
+#define _SW2D_H_
+
+/* Some color definitions */
+#define BPP32_RED    0x00ff0000
+#define BPP32_GREEN  0x0000ff00
+#define BPP32_BLUE   0x000000ff
+#define BPP32_WHITE  0x00ffffff
+#define BPP32_GRAY   0x00808080
+#define BPP32_YELLOW 0x00ffff00
+#define BPP32_CYAN   0x0000ffff
+#define BPP32_PINK   0x00ff00ff
+#define BPP32_BLACK  0x00000000
+
+#define BPP16_RED    0x0000f800
+#define BPP16_GREEN  0x000007e0
+#define BPP16_BLUE   0x0000001f
+#define BPP16_WHITE  0x0000ffff
+#define BPP16_GRAY   0x00008410
+#define BPP16_YELLOW 0x0000ffe0
+#define BPP16_CYAN   0x000007ff
+#define BPP16_PINK   0x0000f81f
+#define BPP16_BLACK  0x00000000
+
+#define BPP8_RED     0x000000b4
+#define BPP8_GREEN   0x0000001e
+#define BPP8_BLUE    0x00000005
+#define BPP8_WHITE   0x000000ff
+#define BPP8_GRAY    0x000000ec
+#define BPP8_YELLOW  0x000000d2
+#define BPP8_CYAN    0x00000023
+#define BPP8_PINK    0x000000b9
+#define BPP8_BLACK   0x00000000
+
+/* Raster Op 2 functions */
+#define ROP2_XOR        0x06
+#define ROP2_AND        0x08
+#define ROP2_COPY       0x0C
+#define ROP2_OR         0x0E
+
+#define ROP2_BLACK      0x00
+#define ROP2_DSon       0x01
+#define ROP2_DSna       0x02
+#define ROP2_Sn         0x03
+#define ROP2_SDna       0x04
+#define ROP2_Dn         0x05
+#define ROP2_DSx        0x06
+#define ROP2_SDan       0x07
+#define ROP2_DSa        0x08
+#define ROP2_SDnx       0x09
+#define ROP2_D          0x0A
+#define ROP2_DSno       0x0B
+#define ROP2_S          0x0C
+#define ROP2_SDno       0x0D
+#define ROP2_DSo        0x0E
+#define ROP2_WHITE      0x0F
+
+/* Blt Direction definitions */
+#define TOP_TO_BOTTOM 0
+#define LEFT_TO_RIGHT 0
+#define BOTTOM_TO_TOP 1
+#define RIGHT_TO_LEFT 1
+
+unsigned long swRasterOp2(unsigned long S, unsigned long D, unsigned long rop2);
+
+/*
+ * This function set up a pixel value in the frame buffer.
+ *
+ * Note:
+ * 1) It can only set pixel within the frame buffer.
+ * 2) This function is NOT for drawing surface created in system memory.
+ *
+ */
+void swSetPixel(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x, 
+unsigned long y,        /* Position (X, Y) to set in pixel value */
+unsigned long color,    /* Color */
+unsigned long rop2);     /* ROP value */
+
+/*
+ * This function gets a pixel value in the frame buffer.
+ *
+ * Note:
+ * 1) It can only get pixel within the frame buffer.
+ * 2) This function is NOT for drawing surface created in system memory.
+ * 3) This function always return a 32 bit pixel value disregard bpp = 8, 16, or 32.
+ *    The calling funtion has to type cast the return value into Byte, word or 
+ *    DWord according to BPP.
+ *
+ */
+unsigned long swGetPixel(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x, 
+unsigned long y);        /* Position (X, Y) to set in pixel value */
+
+/*
+ *  This function uses software only method to fill a rectangular area with a specific color.
+ * Input: See comment of code below.
+ * 
+ */
+void swRectFill(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,        /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long color,    /* Fill color */
+unsigned long rop2);    /* ROP value */
+
+/*
+ * This function draws a hollow rectangle, no fills.
+ */
+void swRect(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,        /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long color,    /* border color */
+unsigned long rop2);     /* ROP value */
+
+void swHorizontalLine(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,        /* Starting point (X, Y) of line */
+unsigned long length,   /* Length of line */
+unsigned long color,    /* Color */
+unsigned long rop2);    /* ROP value */
+
+void swVerticalLine(
+unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,        /* Starting point (X, Y) of line */
+unsigned long length,   /* Length of line */
+unsigned long color,    /* Color */
+unsigned long rop2);    /* ROP value */
+
+/* 
+ * Function to draw a line.
+ */
+long swLine(
+    unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long pitch,    /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x0,       /* Starting X Coordinate */
+    unsigned long y0,       /* Starting Y Coordinate */
+    unsigned long x1,       /* Ending X Coordinate */
+    unsigned long y1,       /* Ending Y Coordinate */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/*
+ * Video Memory to Video Memroy data transfer.
+ *
+ * Note: 
+ * 1) All addresses are offset from the beginning for frame buffer.
+ * 2) Both source and destination have to be same bpp (color depth).
+ * 
+ */
+void swVideoMem2VideoMemBlt(
+unsigned long sBase,  /* Address of source: offset in frame buffer */
+unsigned long sPitch, /* Pitch value of source surface in BYTE */
+unsigned long sx,
+unsigned long sy,     /* Starting coordinate of source surface */
+unsigned long dBase,  /* Address of destination: offset in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,   /* color depth of destiination, source must have same bpp */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long rop2);  /* ROP value */
+
+#endif /* _SW2D_H_ */ 
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.c b/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.c
new file mode 100644
index 000000000000..ed958eb49267
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.c
@@ -0,0 +1,814 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  swi2c.c --- SM750/SM718 DDK 
+*  This file contains the source code for I2C using software
+*  implementation.
+* 
+*******************************************************************/
+#include <linux/delay.h>
+
+#include "ddk750_defs.h"
+#include "ddk750_hardware.h"
+#include "ddk750_power.h"
+#include "ddk750_help.h"
+#include "ddk750_swi2c.h"
+
+
+/*******************************************************************
+ * I2C Software Master Driver:   
+ * ===========================
+ * Each i2c cycle is split into 4 sections. Each of these section marks
+ * a point in time where the SCL or SDA may be changed. 
+ * 
+ * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
+ *            +-------------+-------------+-------------+-------------+
+ *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
+ *                 
+ *                                          ____________ _____________
+ * SCL == XXXX _____________ ____________ /
+ *                 
+ * I.e. the SCL may only be changed in section 1. and section 3. while
+ * the SDA may only be changed in section 2. and section 4. The table
+ * below gives the changes for these 2 lines in the varios sections.
+ * 
+ * Section changes Table:        
+ * ======================
+ * blank = no change, L = set bit LOW, H = set bit HIGH
+ *                       
+ *                                | 1.| 2.| 3.| 4.|      
+ *                 ---------------+---+---+---+---+      
+ *                 Tx Start   SDA |   | H |   | L |      
+ *                            SCL | L |   | H |   |      
+ *                 ---------------+---+---+---+---+                
+ *                 Tx Stop    SDA |   | L |   | H |      
+ *                            SCL | L |   | H |   |      
+ *                 ---------------+---+---+---+---+                
+ *                 Tx bit H   SDA |   | H |   |   |      
+ *                            SCL | L |   | H |   |      
+ *                 ---------------+---+---+---+---+                
+ *                 Tx bit L   SDA |   | L |   |   |      
+ *                            SCL | L |   | H |   |      
+ *                 ---------------+---+---+---+---+                
+ *                                  
+ ******************************************************************/
+
+/* GPIO pins used for this I2C. It ranges from 0 to 63. */
+static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL;
+static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA;
+
+/*
+ *  Below is the variable declaration for the GPIO pin register usage
+ *  for the i2c Clock and i2c Data.
+ *
+ *  Note:
+ *      Notice that the GPIO usage for the i2c clock and i2c Data are
+ *      separated. This is to make this code flexible enough when 
+ *      two separate GPIO pins for the clock and data are located
+ *      in two different GPIO register set (worst case).
+ */
+
+/* i2c Clock GPIO Register usage */
+static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
+static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
+static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+/* i2c Data GPIO Register usage */
+static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
+static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
+static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+/*
+ *  This function puts a delay between command
+ */        
+static void swI2CWait(void)
+{
+    int i, Temp;
+
+    for(i=0; i<600; i++)
+    {
+        Temp = i;
+        Temp += i;
+    }
+}
+
+/*
+ *  This function set/reset the SCL GPIO pin
+ *
+ *  Parameters:
+ *      value	- Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ *
+ *  Notes:
+ *      When setting SCL to high, just set the GPIO as input where the pull up
+ *      resistor will pull the signal up. Do not use software to pull up the
+ *      signal because the i2c will fail when other device try to drive the
+ *      signal due to SM50x will drive the signal to always high.
+ */ 
+void swI2CSCL(unsigned char value)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if (value)      /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << g_i2cClockGPIO);	
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+    else            /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+        ulGPIOData &= ~(1 << g_i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << g_i2cClockGPIO);		
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function set/reset the SDA GPIO pin
+ *
+ *  Parameters:
+ *      value	- Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ *
+ *  Notes:
+ *      When setting SCL to high, just set the GPIO as input where the pull up
+ *      resistor will pull the signal up. Do not use software to pull up the
+ *      signal because the i2c will fail when other device try to drive the
+ *      signal due to SM50x will drive the signal to always high.
+ */
+void swI2CSDA(unsigned char value)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if (value)      /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << g_i2cDataGPIO);	
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+    else            /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+        ulGPIOData &= ~(1 << g_i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << g_i2cDataGPIO);		
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function read the data from the SDA GPIO pin
+ *
+ *  Return Value:
+ *      The SDA data bit sent by the Slave
+ */
+static unsigned char swI2CReadSDA(void)
+{
+    unsigned long ulGPIODirection;
+    unsigned long ulGPIOData;
+
+    /* Make sure that the direction is input (High) */
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO)))
+    {
+        ulGPIODirection &= ~(1 << g_i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+
+    /* Now read the SDA line */
+    ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+    if (ulGPIOData & (1 << g_i2cDataGPIO)) 
+        return 1;
+    else 
+        return 0;
+}
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+
+/*
+ *  This function sends ACK signal
+ */
+static void swI2CAck(unsigned char ack)
+{
+	if(ack)
+    {
+        swI2CSCL(0);
+        swI2CSDA(0);
+        swI2CWait();
+        swI2CSCL(1);
+        swI2CWait();
+        swI2CSCL(0);
+        swI2CSDA(0);
+        swI2CWait();
+    }
+    else
+    {
+        swI2CSCL(0);
+        swI2CSDA(1);
+        swI2CWait();
+        swI2CSCL(1);
+        swI2CWait();
+        swI2CSCL(0);
+        swI2CSDA(0);
+        swI2CWait();
+    }
+    return;  /* Single byte read is ok without it. */
+}
+
+/*
+ *  This function sends the start command to the slave device
+ */
+void swI2CStart(void)
+{
+    /* Start I2C */
+    swI2CSDA(1);
+    swI2CSCL(1);
+    swI2CSDA(0);
+}
+
+/*
+ *  This function sends the stop command to the slave device
+ */
+void swI2CStop(void)
+{
+    /* Stop the I2C */
+    swI2CSCL(1);
+    swI2CSDA(0);
+    swI2CSDA(1);
+}
+
+/*
+ *  This function writes one byte to the slave device
+ *
+ *  Parameters:
+ *      data    - Data to be write to the slave device
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to write byte
+ */
+long swI2CWriteByte(unsigned char data) 
+{
+    unsigned char value = data;
+    int i;
+
+    /* Sending the data bit by bit */
+    for (i=0; i<8; i++)
+    {
+        /* Set SCL to low */
+        swI2CSCL(0);
+
+        /* Send data bit */
+        if ((value & 0x80) != 0)
+            swI2CSDA(1);
+        else
+            swI2CSDA(0);
+
+        swI2CWait();
+
+        /* Toggle clk line to one */
+        swI2CSCL(1);
+
+        /* Shift byte to be sent */
+        value = value << 1;
+    }
+
+    /* Set the SCL Low and SDA High (prepare to get input) */
+    swI2CSCL(0);
+    swI2CSDA(1);
+
+    /* Set the SCL High for ack */
+    swI2CWait();
+    swI2CSCL(1);
+
+    /* Read SDA, until SDA==0 */
+    for(i=0; i<0xff; i++) 
+    {
+        swI2CWait();
+        swI2CWait();
+        if (!swI2CReadSDA())
+            break;
+    }
+
+    /* Set the SCL Low and SDA High */
+    swI2CSCL(0);
+    swI2CSDA(1);
+
+    if (i<0xff)
+        return 0;
+    else
+        return (-1);
+}
+
+/*
+ *  This function reads one byte from the slave device
+ *
+ *  Parameters:
+ *      ack	- Flag to indicate either to send the acknowledge
+ *            message to the slave device or not
+ *
+ *  Return Value:
+ *      One byte data read from the Slave device
+ */
+unsigned char swI2CReadByte(unsigned char ack)
+{
+    int i;
+    unsigned char data = 0;
+
+    for(i=7; i>=0; i--)
+    {
+        /* Set the SCL to Low and SDA to High (Input) */
+        swI2CSCL(0);
+        swI2CSDA(1);
+        swI2CWait();
+
+        /* Set the SCL High */
+        swI2CSCL(1);
+        swI2CWait();
+
+        /* Read data bits from SDA */
+        data |= (swI2CReadSDA() << i);
+    }
+
+	swI2CAck(ack);
+
+    return data;
+}
+#pragma GCC pop_options
+
+/*
+ * This function initializes the i2c attributes and bus
+ *
+ * Parameters:
+ *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
+ *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ *      -1   - Fail to initialize the i2c
+ *       0   - Success
+ */
+long swI2CInit(
+    unsigned char i2cClkGPIO, 
+    unsigned char i2cDataGPIO
+)
+{
+    int i;
+    
+    /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
+    if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
+        return (-1);
+    
+    /* Initialize the GPIO pin for the i2c Clock Register */
+    g_i2cClkGPIOMuxReg = GPIO_MUX;   
+    g_i2cClkGPIODataReg = GPIO_DATA;    
+    g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
+    
+    /* Initialize the Clock GPIO Offset */
+    g_i2cClockGPIO = i2cClkGPIO;
+    
+    /* Initialize the GPIO pin for the i2c Data Register */
+    g_i2cDataGPIOMuxReg = GPIO_MUX;    
+    g_i2cDataGPIODataReg = GPIO_DATA;    
+    g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
+    
+    /* Initialize the Data GPIO Offset */
+    g_i2cDataGPIO = i2cDataGPIO;
+
+    /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
+    pokeRegisterDWord(g_i2cClkGPIOMuxReg, 
+                      peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
+    pokeRegisterDWord(g_i2cDataGPIOMuxReg, 
+                      peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
+
+    /* Enable GPIO power */
+    enableGPIO(1);
+
+    /* Clear the i2c lines. */
+    for(i=0; i<9; i++) 
+        swI2CStop();
+
+    return 0;
+}
+
+/*
+ *  This function reads the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      registerIndex   - Slave device's register to be read
+ *
+ *  Return Value:
+ *      Register value
+ */
+unsigned char swI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+)
+{
+    unsigned char data;
+
+    /* Send the Start signal */
+    swI2CStart();
+
+    /* Send the device address */
+    swI2CWriteByte(deviceAddress);                                                  
+
+    /* Send the register index */
+    swI2CWriteByte(registerIndex);               
+
+    /* Get the bus again and get the data from the device read address */
+    swI2CStart();
+    swI2CWriteByte(deviceAddress + 1);
+    data = swI2CReadByte(0);
+
+    /* Stop swI2C and release the bus */
+    swI2CStop();
+
+    return data;
+}
+
+/*
+*   This function reads the slave device's register continuously.
+*
+*  Parameters:
+*      deviceAddress   - i2c Slave device address which register
+*                        to be read from
+*      start_registerIndex   - Slave device's first register(start address) to be read
+*      length  - total length you want to read from the start address
+*      dest    - buffer address which will store the data read from slave device
+*
+*  Return Value:
+*      0: fail 
+*      actual size
+*
+*/
+long swI2CReadReg_Continuous(
+    unsigned char deviceAddress, 
+    unsigned char start_registerIndex,
+    unsigned long length,
+    unsigned char * dest
+)
+{
+    long ret = 128;
+	int i;
+    /* Send the Start signal */
+    swI2CStart();
+
+    /* Send the device address */
+    ret = swI2CWriteByte(deviceAddress);  
+    /* if failed to write, there is no necessary continuing */
+    if(-1 == ret)
+        return 0;
+    
+    /* Send the register index */
+    ret = swI2CWriteByte(start_registerIndex);               
+    /* if failed to write, there is no necessary continuing */
+    if(-1 == ret)
+        return 0;
+
+    /* Get the bus again and get the data from the device read address */
+    swI2CStart();
+    ret = swI2CWriteByte(deviceAddress + 1);
+    /* if failed to write, there is no necessary continuing */
+    if(-1 == ret)
+        return 0;
+
+	
+    for(i = 0;i<(length-1);i++)
+    {
+        dest[i] = swI2CReadByte(1);
+    }
+
+    dest[length-1] =  swI2CReadByte(0);
+    /* Stop swI2C and release the bus */
+    swI2CStop();
+
+    ret = length;
+
+    return ret;
+}
+
+
+
+
+/*
+ *  This function writes a value to the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long swI2CWriteReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+)
+{
+    long returnValue = 0;
+    
+    /* Send the Start signal */
+    swI2CStart();
+#ifndef USE_HDMICHIP  
+    /* Send the device address and read the data. All should return success
+       in order for the writing processed to be successful
+     */
+    if ((swI2CWriteByte(deviceAddress) != 0) ||
+        (swI2CWriteByte(registerIndex) != 0) ||
+        (swI2CWriteByte(data) != 0))
+    {
+        returnValue = -1;
+    }
+#else
+
+	swI2CWriteByte(deviceAddress);
+	swI2CWriteByte(registerIndex);
+	swI2CWriteByte(data);
+#endif
+
+    /* Stop i2c and release the bus */
+    swI2CStop();
+
+    return returnValue;
+}
+
+long adapterI2CInit(
+    unsigned char i2cClkGPIO, 
+    unsigned char i2cDataGPIO
+)
+{
+    int i;
+    
+    /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
+    if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
+        return (-1);
+    
+    /* Initialize the GPIO pin for the i2c Clock Register */
+    g_i2cClkGPIOMuxReg = GPIO_MUX;   
+    g_i2cClkGPIODataReg = GPIO_DATA;    
+    g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
+    
+    /* Initialize the Clock GPIO Offset */
+//    g_i2cClockGPIO = i2cClkGPIO;
+    
+    /* Initialize the GPIO pin for the i2c Data Register */
+    g_i2cDataGPIOMuxReg = GPIO_MUX;    
+    g_i2cDataGPIODataReg = GPIO_DATA;    
+    g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
+    
+    /* Initialize the Data GPIO Offset */
+//    g_i2cDataGPIO = i2cDataGPIO;
+
+    /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
+    pokeRegisterDWord(g_i2cClkGPIOMuxReg, 
+                      peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << i2cClkGPIO));
+    pokeRegisterDWord(g_i2cDataGPIOMuxReg, 
+                      peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << i2cDataGPIO));
+
+    /* Enable GPIO power */
+    enableGPIO(1);
+
+    /* Clear the i2c lines. */
+    for(i=0; i<9; i++) 
+        swI2CStop();
+
+    return 0;
+}
+
+static void adapterI2CSCL(unsigned char value, unsigned char i2cClockGPIO)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if (value) /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+    else /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+        ulGPIOData &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function read the data from the SDA GPIO pin
+ *
+ *  Return Value:
+ *      The SDA data bit sent by the Slave
+ */
+static unsigned char adapterI2CReadSCL(unsigned char i2cClockGPIO)
+{
+    unsigned long ulGPIODirection;
+    unsigned long ulGPIOData;
+
+    /* Make sure that the direction is input (High) */
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if ((ulGPIODirection & (1 << i2cClockGPIO)) != (~(1 << i2cClockGPIO)))
+    {
+        ulGPIODirection &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+
+
+
+    /* Now read the SCL line */
+    ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+    if (ulGPIOData & (1 << i2cClockGPIO))
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static void adapterI2CSDA(unsigned char value, unsigned char i2cDataGPIO)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if (value) /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+    else /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+        ulGPIOData &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function read the data from the SDA GPIO pin
+ *
+ *  Return Value:
+ *      The SDA data bit sent by the Slave
+ */
+static unsigned char adapterI2CReadSDA(unsigned char i2cDataGPIO)
+{
+    unsigned long ulGPIODirection;
+    unsigned long ulGPIOData;
+
+    /* Make sure that the direction is input (High) */
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if ((ulGPIODirection & (1 << i2cDataGPIO)) != (~(1 << i2cDataGPIO)))
+    {
+        ulGPIODirection &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+
+    /* Now read the SDA line */
+    ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+    if (ulGPIOData & (1 << i2cDataGPIO))
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static void smi_ddc_setsda(void *data, int state)
+{
+    struct smi_connector *connector = data;
+    adapterI2CSDA(state, connector->i2c_sda);
+    /* smi_set_i2c_signal(data, I2C_SDA_MASK, state); */
+}
+
+static void smi_ddc_setscl(void *data, int state)
+{
+    struct smi_connector *connector = data;
+    adapterI2CSCL(state, connector->i2c_scl);
+    /* smi_set_i2c_signal(data, I2C_SCL_MASK, state); */
+}
+
+static int smi_ddc_getsda(void *data)
+{
+
+    struct smi_connector *connector = data;
+    return (int)adapterI2CReadSDA(connector->i2c_sda);
+    /* return smi_get_i2c_signal(data, I2C_SDA_MASK); */
+}
+
+static int smi_ddc_getscl(void *data)
+{
+    struct smi_connector *connector = data;
+    return (int)adapterI2CReadSCL(connector->i2c_scl);
+    /* return smi_get_i2c_signal(data, I2C_SCL_MASK); */
+}
+
+static int smi_ddc_create(struct smi_connector *connector)
+{
+    connector->adapter.owner = THIS_MODULE;
+    connector->adapter.class = I2C_CLASS_DDC;
+    snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI SW I2C Bit Bus");
+    connector->adapter.dev.parent = connector->base.dev->dev;
+    i2c_set_adapdata(&connector->adapter, connector);
+    connector->adapter.algo_data = &connector->bit_data;
+
+    connector->bit_data.udelay = 2; /* 0x3ff ticks, 168MHZ */
+    connector->bit_data.timeout = usecs_to_jiffies(2200);
+    connector->bit_data.data = connector;
+    connector->bit_data.setsda = smi_ddc_setsda;
+    connector->bit_data.setscl = smi_ddc_setscl;
+    connector->bit_data.getsda = smi_ddc_getsda;
+    connector->bit_data.getscl = smi_ddc_getscl;
+
+    if (i2c_bit_add_bus(&connector->adapter))
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+long ddk750_AdaptSWI2CInit(struct smi_connector *smi_connector)
+{
+    struct drm_connector *connector = &smi_connector->base;
+    unsigned char i2cClkGPIO;
+    unsigned char i2cDataGPIO;
+
+    if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+    {
+        i2cClkGPIO = 30;
+        i2cDataGPIO = 31;
+    }
+    else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+    {
+        i2cClkGPIO = 17;
+        i2cDataGPIO = 18;
+    }
+    else
+    {
+        return -1;
+    }
+
+    smi_connector->i2c_scl = i2cClkGPIO;
+    smi_connector->i2c_sda = i2cDataGPIO;
+
+    if (adapterI2CInit(i2cClkGPIO, i2cDataGPIO))
+    {
+        return (-1);
+    }
+
+#if 0
+    /* Clear the i2c lines. */
+    {
+        int i = 0;
+        for (i = 0; i < 9; i++)
+            ddk768_swI2CStop();
+    }
+#endif
+
+    udelay(20);
+
+    if (smi_ddc_create(smi_connector))
+    {       
+        return -1;
+    }
+	
+    return 0;
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.h b/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.h
new file mode 100644
index 000000000000..2f6afeacc5e4
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddk750_swi2c.h
@@ -0,0 +1,122 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  swi2c.h --- SM750/SM718 DDK 
+*  This file contains the definitions for i2c using software 
+*  implementation.
+* 
+*******************************************************************/
+#ifndef _SWI2C_H_
+#define _SWI2C_H_
+
+#include "../smi_drv.h"
+
+
+/* Default i2c CLK and Data GPIO. These are the default i2c pins */
+#define DEFAULT_I2C_SCL                     30
+#define DEFAULT_I2C_SDA                     31
+
+/*
+ * This function initializes the i2c attributes and bus
+ *
+ * Parameters:
+ *      i2cClkGPIO  - The GPIO pin to be used as i2c SCL
+ *      i2cDataGPIO - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ *      -1   - Fail to initialize the i2c
+ *       0   - Success
+ */
+long swI2CInit(
+    unsigned char i2cClkGPIO, 
+    unsigned char i2cDataGPIO
+);
+
+/*
+ *  This function reads the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      registerIndex   - Slave device's register to be read
+ *
+ *  Return Value:
+ *      Register value
+ */
+unsigned char swI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+);
+
+/*
+ *   This function reads the slave device's register continuously.
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      start_registerIndex   - Slave device's first register(start address) to be read
+ *      length  - total length you want to read from the start address
+ *      dest    - buffer address which will store the data read from slave device
+ *
+ *  Return Value:
+ *      0: fail 
+ *      actual size
+ */
+long swI2CReadReg_Continuous(
+    unsigned char deviceAddress, 
+    unsigned char start_registerIndex,
+    unsigned long length,
+    unsigned char * dest
+);
+
+
+
+/*
+ *  This function writes a value to the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long swI2CWriteReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+);
+
+/*
+ *  These two functions are used to toggle the data on the SCL and SDA I2C lines.
+ *  The used of these two functions are not recommended unless it is necessary.
+ */
+
+/*
+ *  This function set/reset the SCL GPIO pin
+ *
+ *  Parameters:
+ *      value	- Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ */ 
+void swI2CSCL(unsigned char value);
+
+/*
+ *  This function set/reset the SDA GPIO pin
+ *
+ *  Parameters:
+ *      value	- Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ */
+void swI2CSDA(unsigned char value);
+
+long ddk750_AdaptSWI2CInit(struct smi_connector *smi_connector);
+
+
+
+#endif  /* _SWI2C_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/ddkdebug.h b/drivers/gpu/drm/smifb2/ddk750/ddkdebug.h
new file mode 100644
index 000000000000..aa1df840174f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/ddkdebug.h
@@ -0,0 +1,141 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  ddkdebug.h --- DDK Debug module 
+*  This file contains the definitions for the SMI DDK debugging.
+* 
+*******************************************************************/
+#ifndef _DDKDEBUG_H_
+#define _DDKDEBUG_H_
+
+#ifdef DDKDEBUG
+
+/*********************
+ * Definition  
+ *********************/
+ 
+/* Debug Print Level definitions */
+/* Bit 16 ~ 31 are used by the library. Bit 0 ~ 15 can be used by application */
+#define ERROR_LEVEL                 0x00010000
+#define WARNING_LEVEL               0x00020000
+#define INIT_LEVEL                  0x00040000
+#define DISPLAY_LEVEL               0x00080000
+#define DMA_LEVEL                   0x00100000
+#define DE_LEVEL                    0x00200000
+#define CAPTURE_LEVEL               0x00400000
+#define SSP_LEVEL                   0x00800000
+#define RESERVED8_LEVEL             0x01000000
+#define RESERVED9_LEVEL             0x02000000
+#define RESERVED10_LEVEL            0x04000000
+#define RESERVED11_LEVEL            0x08000000
+#define RESERVED12_LEVEL            0x10000000
+#define RESERVED13_LEVEL            0x20000000
+#define RESERVED14_LEVEL            0x40000000
+#define RESERVED15_LEVEL            0x80000000
+
+#define SYSTEM_LEVEL_MASK           0xFFFF0000
+#define APPLICATION_LEVEL_MASK      0x0000FFFF
+
+/*********************
+ * Structure 
+ *********************/
+typedef enum _ddk_debug_output_t
+{
+    DEBUG_OUTPUT_SCREEN = 0,
+    DEBUG_OUTPUT_FILE,
+    DEBUG_OUTPUT_SERIAL
+} 
+ddk_debug_output_t;
+
+/*********************
+ * MACROS 
+ *********************/
+ 
+/* This function has to be called before calling other DEBUGPIRNT functions. */
+#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) \
+    ddkDebugPrintInit(debugOutput, debugLevelMask)
+
+/* This function enable or disable the debug message. 
+ *  Note:
+ *      This function can be used to enable/disable the debug message
+ *      at certain point of software, so that the debug messages, that
+ *      are printed, are only the important ones.
+ */
+#define DDKDEBUGENABLE(arg)                           \
+    ddkDebugEnable(arg)
+
+/* Calling the DDKDEBUGPRINT needs to have the arg to be enclosed with
+   two of open and close brackets.
+   Example:
+            DDKDEBUGPRINT(("Hello World: %s\n", pszString));
+ */
+#define DDKDEBUGPRINT(arg)                             \
+    ddkDebugPrint arg
+    
+/* This function has to be called when exiting the application.
+   It is necessary to clean up the debug module. */
+#define DDKDEBUGPRINTEXIT()                            \
+    ddkDebugPrintExit()
+
+/*********************
+ * Function prototype 
+ *********************/
+ 
+/*
+ * This function initializes the debug print out system.
+ *  
+ *  Input:
+ *      debugOutput - Output where to print out the debug. It could be 
+ *                    screen, file, or serial port.
+ *      debugLevel  - Debugging level      
+ */
+void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask);
+
+/*
+ *  This function enable or disable the debug message.
+ *  
+ *  Input:
+ *      enableDebugMessage  - Enable/disable the debug message
+ *                            0 - Disable Debug Message
+ *                            1 - Enable Debug Message
+ *
+ *  Note:
+ *      This function can be used to enable/disable the debug message
+ *      at certain point of software, so that the debug messages, that
+ *      are printed, are only the important ones.     
+ */
+void ddkDebugEnable(unsigned char enableDebugMessage);
+
+/*
+ * This function prints out the formatted string.
+ *  
+ *  Input:
+ *      debugLevel  - The level of the debug of which the message is intended for.
+ *      pszFormat   - Format of the printed message      
+ */
+void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...);
+
+/*
+ * This function cleans up (such as closing the debug file, etc...) when
+ * exiting the debug module.      
+ */
+void ddkDebugPrintExit();
+
+#else
+
+/* 
+ * If there is no DEBUG definition, then treat the macro as an empty macro.
+ * Therefore all the debug print will be stripped out. 
+ */
+#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask)
+#define DDKDEBUGENABLE(arg)
+#define DDKDEBUGPRINT(arg)
+#define DDKDEBUGPRINTEXIT()
+
+#endif
+
+#endif /* _DDKDEBUG_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.c b/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.c
new file mode 100644
index 000000000000..4548433b155e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.c
@@ -0,0 +1,3522 @@
+/***************************************************************************
+ *
+ * SIMG PART NUMBER - HDMI Transmitter Driver
+ *
+ * Copyright (C) (2011, Silicon Image)
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *****************************************************************************/
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include "siHdmiTx_902x_TPI.h"
+#include "ddk750_hwi2c.h"
+#include "ddk750_swi2c.h"
+
+#define i2cWriteReg swI2CWriteReg
+#define i2cReadReg  swI2CReadReg
+
+
+
+SIHDMITX_CONFIG		siHdmiTx;
+GLOBAL_SYSTEM 		g_sys;
+GLOBAL_HDCP 		g_hdcp;
+GLOBAL_EDID 		g_edid;
+byte 				tpivmode[3];  // saved TPI Reg0x08/Reg0x09/Reg0x0A values.
+
+bool Sii9024A_HDCP_supported=false;  //if the chip is 9024A, you can support HDCP by set this variable to 1.If the chip is 9022A, it means noting.
+
+
+//bool HDCP_Supported=false;
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////         The following functions are related with target system!!!    //////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//sbit siHdmiTx_HwResetPin = P2^1; 	// Connected to 9022A/4A pin C3 (CRST#)
+
+//extern void DelayMS (word MS);
+//extern byte I2CReadByte ( byte SlaveAddr, byte RegAddr );
+//extern void I2CWriteByte ( byte SlaveAddr, byte RegAddr, byte Data );
+//extern byte I2CReadBlock( byte SlaveAddr, byte RegAddr, byte NBytes, byte * Data );
+//extern byte I2CWriteBlock( byte SlaveAddr, byte RegAddr, byte NBytes, byte * Data );
+//extern byte siiReadSegmentBlockEDID(byte SlaveAddr, byte Segment, byte Offset, byte *Buffer, byte Length);
+
+struct i2c_client *sii902xA = NULL;
+struct i2c_client *siiEDID = NULL;
+struct i2c_client *siiSegEDID = NULL;
+struct i2c_client *siiHDCP = NULL;
+
+
+
+void DelayMS (word MS)
+{
+	mdelay(MS);//call linux kernel delay API function
+}
+
+
+byte I2CReadBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data )
+{
+	byte i = 0;
+	while(i<NBytes){
+		Data[i] = i2cReadReg(SII9022A_I2C_ADDRESS,RegAddr+i);
+		i++;
+	}
+	return IIC_OK;
+}
+
+byte I2CReadEDID(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data )
+{
+	byte i = 0;
+	while(i<NBytes){
+		Data[i] = i2cReadReg(0xA0,RegAddr+i);
+		i++;
+	}
+	return IIC_OK;
+}
+
+
+
+byte I2CWriteBlock( struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data )
+{
+	byte i = 0;
+	while(i < NBytes){
+		i2cWriteReg(SII9022A_I2C_ADDRESS,RegAddr+i,Data[i]);
+		i++;
+	}
+	return IIC_OK;
+}
+
+static s32 i2c_smbus_write_byte_nostop(struct i2c_client *client, u8 value)
+{
+	return IIC_OK;
+}
+
+byte siiReadSegmentBlockEDID(struct i2c_client *client, byte Segment, byte Offset, byte *Buffer, byte Length)
+{
+	int rc;
+	i2c_smbus_write_byte_nostop(siiSegEDID,Segment);
+	rc = I2CReadBlock(client, Offset, Length, Buffer);
+	if (rc < 0)
+		return -EIO;
+	return IIC_OK;
+}
+
+byte ReadByteTPI (byte RegOffset)
+{
+	return i2cReadReg(SII9022A_I2C_ADDRESS,	RegOffset);
+}
+
+void WriteByteTPI (byte RegOffset, byte Data)
+{
+	i2cWriteReg(SII9022A_I2C_ADDRESS,RegOffset,Data);
+}
+
+
+//------------------------------------------------------------------------------
+// Function Name: ReadSetWriteTPI()
+// Function Description: Write "1" to all bits in TPI offset "Offset" that are set
+//                  to "1" in "Pattern"; Leave all other bits in "Offset"
+//                  unchanged.
+//------------------------------------------------------------------------------
+void ReadSetWriteTPI (byte Offset, byte Pattern)
+{
+	byte Tmp;
+	Tmp = ReadByteTPI(Offset);
+	Tmp |= Pattern;
+	WriteByteTPI(Offset, Tmp);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadSetWriteTPI()
+// Function Description: Write "0" to all bits in TPI offset "Offset" that are set
+//                  to "1" in "Pattern"; Leave all other bits in "Offset"
+//                  unchanged.
+//------------------------------------------------------------------------------
+void ReadClearWriteTPI (byte Offset, byte Pattern)
+{
+	byte Tmp;
+	Tmp = ReadByteTPI(Offset);
+	Tmp &= ~Pattern;
+	WriteByteTPI(Offset, Tmp);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadSetWriteTPI()
+// Function Description: Write "Value" to all bits in TPI offset "Offset" that are set
+//                  to "1" in "Mask"; Leave all other bits in "Offset"
+//                  unchanged.
+//------------------------------------------------------------------------------
+void ReadModifyWriteTPI (byte Offset, byte Mask, byte Value)
+{
+	byte Tmp;
+	Tmp = ReadByteTPI(Offset);
+	Tmp &= ~Mask;
+	Tmp |= (Value & Mask);
+	WriteByteTPI(Offset, Tmp);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadBlockTPI()
+// Function Description: Read NBytes from offset Addr of the TPI slave address
+//                      into a byte Buffer pointed to by Data
+//------------------------------------------------------------------------------
+void ReadBlockTPI(byte TPI_Offset, word NBytes, byte * pData)
+{
+	I2CReadBlock(sii902xA,TPI_Offset,NBytes,pData);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: WriteBlockTPI()
+// Function Description: Write NBytes from a byte Buffer pointed to by Data to
+//                      the TPI I2C slave starting at offset Addr
+//------------------------------------------------------------------------------
+void WriteBlockTPI (byte TPI_Offset, word NBytes, byte * pData)
+{
+	I2CWriteBlock(sii902xA,TPI_Offset, NBytes, pData);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadIndexedRegister()
+// Function Description: Read an indexed register value
+//
+//                  Write:
+//                      1. 0xBC => Internal page num
+//                      2. 0xBD => Indexed register offset
+//
+//                  Read:
+//                      3. 0xBE => Returns the indexed register value
+//------------------------------------------------------------------------------
+byte ReadIndexedRegister(byte PageNum, byte RegOffset) 
+{
+	WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum);		// Internal page
+	WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset);	// Indexed register
+	return ReadByteTPI(TPI_INDEXED_VALUE_REG); 		// Return read value
+}
+
+//------------------------------------------------------------------------------
+// Function Name: WriteIndexedRegister()
+// Function Description: Write a value to an indexed register
+//
+//                  Write:
+//                      1. 0xBC => Internal page num
+//                      2. 0xBD => Indexed register offset
+//                      3. 0xBE => Set the indexed register value
+//------------------------------------------------------------------------------
+void WriteIndexedRegister (byte PageNum, byte RegOffset, byte RegValue) 
+{
+	WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum);  // Internal page
+	WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset);  // Indexed register
+	WriteByteTPI(TPI_INDEXED_VALUE_REG, RegValue);    // Read value into buffer
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadModifyWriteIndexedRegister()
+// Function Description: Write "Value" to all bits in TPI offset "Offset" that are set
+//                  to "1" in "Mask"; Leave all other bits in "Offset"
+//                  unchanged.
+//------------------------------------------------------------------------------
+void ReadModifyWriteIndexedRegister(byte PageNum, byte RegOffset, byte Mask, byte Value)
+{
+	byte Tmp;
+	WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum);
+	WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset);
+	Tmp = ReadByteTPI(TPI_INDEXED_VALUE_REG);
+
+	Tmp &= ~Mask;
+	Tmp |= (Value & Mask);
+
+	WriteByteTPI(TPI_INDEXED_VALUE_REG, Tmp);
+}
+
+//------------------------------------------------------------------------------
+void TXHAL_InitPostReset (void) 
+{
+	// Set terminations to default.
+	WriteByteTPI(TMDS_CONT_REG, 0x25);
+	// HW debounce to 64ms (0x14)
+	WriteByteTPI(0x7C, 0x14);
+}
+
+#if 0
+void TxHW_Reset (void)
+{
+	TPI_TRACE_PRINT((">>TxHW_Reset()\n"));
+
+	Sii902xA_plat_data = sii902xA->dev.platform_data;
+	if (Sii902xA_plat_data->reset)
+		Sii902xA_plat_data->reset();
+	/*
+	   siHdmiTx_HwResetPin = LOW;
+	   DelayMS(TX_HW_RESET_PERIOD);
+	   siHdmiTx_HwResetPin = HIGH;
+	   */
+	TXHAL_InitPostReset();
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Function Name: InitializeStateVariables()
+// Function Description: Initialize system state variables
+//------------------------------------------------------------------------------
+void InitializeStateVariables (void)
+{
+	g_sys.tmdsPoweredUp = FALSE;
+	g_sys.hdmiCableConnected = FALSE;
+	g_sys.dsRxPoweredUp = FALSE;
+
+#ifdef DEV_SUPPORT_EDID
+	g_edid.edidDataValid = FALSE;
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Function Name: EnableTMDS()
+// Function Description: Enable TMDS
+//------------------------------------------------------------------------------
+void EnableTMDS (void)
+{	
+	TPI_DEBUG_PRINT(("TMDS -> Enabled\n"));
+	ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK, TMDS_OUTPUT_CONTROL_ACTIVE);
+	WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]);      		// Write register 0x08
+	g_sys.tmdsPoweredUp = TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: DisableTMDS()
+// Function Description: Disable TMDS
+//------------------------------------------------------------------------------
+void DisableTMDS (void)
+{
+	TPI_DEBUG_PRINT(("TMDS -> Disabled\n"));
+	ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK,
+			TMDS_OUTPUT_CONTROL_POWER_DOWN | AV_MUTE_MUTED);
+	g_sys.tmdsPoweredUp = FALSE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: EnableInterrupts()
+// Function Description: Enable the interrupts specified in the input parameter
+//
+// Accepts: A bit pattern with "1" for each interrupt that needs to be
+//                  set in the Interrupt Enable Register (TPI offset 0x3C)
+// Returns: TRUE
+// Globals: none
+//------------------------------------------------------------------------------
+byte EnableInterrupts(byte Interrupt_Pattern)
+{
+	TPI_TRACE_PRINT((">>EnableInterrupts()\n"));
+	ReadSetWriteTPI(TPI_INTERRUPT_ENABLE_REG, Interrupt_Pattern);
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: DisableInterrupts()
+// Function Description: Disable the interrupts specified in the input parameter
+//
+// Accepts: A bit pattern with "1" for each interrupt that needs to be
+//                  cleared in the Interrupt Enable Register (TPI offset 0x3C)
+// Returns: TRUE
+// Globals: none
+//------------------------------------------------------------------------------
+byte DisableInterrupts (byte Interrupt_Pattern)
+{
+	TPI_TRACE_PRINT((">>DisableInterrupts()\n"));
+	ReadClearWriteTPI(TPI_INTERRUPT_ENABLE_REG, Interrupt_Pattern);
+
+	return TRUE;
+}
+
+
+
+#ifdef DEV_SUPPORT_EDID
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////                   EDID                 ///////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static u8 g_CommData [EDID_BLOCK_SIZE];
+
+#define ReadBlockEDID(a,b,c)            		I2CReadEDID(siiEDID, a, b, c)
+#define ReadSegmentBlockEDID(a,b,c,d)   		siiReadSegmentBlockEDID(siiEDID, a, b, d, c)
+
+//------------------------------------------------------------------------------
+// Function Name: GetDDC_Access()
+// Function Description: Request access to DDC bus from the receiver
+//
+// Accepts: none
+// Returns: TRUE or FLASE
+// Globals: none
+//------------------------------------------------------------------------------
+#define T_DDC_ACCESS    50
+
+byte GetDDC_Access (byte* SysCtrlRegVal)
+{
+	byte sysCtrl;
+	byte DDCReqTimeout = T_DDC_ACCESS;
+	byte TPI_ControlImage;
+
+
+	sysCtrl = ReadByteTPI (TPI_SYSTEM_CONTROL_DATA_REG);			// Read and store original value. Will be passed into ReleaseDDC()
+	*SysCtrlRegVal = sysCtrl;
+
+	sysCtrl |= DDC_BUS_REQUEST_REQUESTED;
+	WriteByteTPI (TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl);
+
+	while (DDCReqTimeout--)											// Loop till 0x1A[1] reads "1"
+	{
+		TPI_ControlImage = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG);
+
+		if (TPI_ControlImage & DDC_BUS_GRANT_MASK)					// When 0x1A[1] reads "1"
+		{
+			sysCtrl |= DDC_BUS_GRANT_GRANTED;
+			WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl);		// lock host DDC bus access (0x1A[2:1] = 11)
+			return TRUE;
+		}
+		WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl);			// 0x1A[2] = "1" - Requst the DDC bus
+		DelayMS(200);
+	}
+
+	WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl);				// Failure... restore original value.
+	printk("Get DDC Access failed\n");
+	return FALSE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReleaseDDC()
+// Function Description: Release DDC bus
+//
+// Accepts: none
+// Returns: TRUE if bus released successfully. FALSE if failed.
+// Globals: none
+//------------------------------------------------------------------------------
+byte ReleaseDDC (byte SysCtrlRegVal)
+{
+	byte DDCReqTimeout = T_DDC_ACCESS;
+	byte TPI_ControlImage;
+
+	SysCtrlRegVal &= ~BITS_2_1;					// Just to be sure bits [2:1] are 0 before it is written
+
+	while (DDCReqTimeout--)						// Loop till 0x1A[1] reads "0"
+	{
+		// Cannot use ReadClearWriteTPI() here. A read of TPI_SYSTEM_CONTROL is invalid while DDC is granted.
+		// Doing so will return 0xFF, and cause an invalid value to be written back.
+		//ReadClearWriteTPI(TPI_SYSTEM_CONTROL,BITS_2_1); // 0x1A[2:1] = "0" - release the DDC bus
+
+		WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, SysCtrlRegVal);
+		TPI_ControlImage = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG);
+
+		if (!(TPI_ControlImage & BITS_2_1))		// When 0x1A[2:1] read "0"
+			return TRUE;
+	}
+	printk("failed to release DDC bus control\n");
+	return FALSE;								// Failed to release DDC bus control
+}
+
+//------------------------------------------------------------------------------
+// Function Name: CheckEDID_Header()
+// Function Description: Checks if EDID header is correct per VESA E-EDID standard
+//
+// Accepts: Pointer to 1st EDID block
+// Returns: TRUE or FLASE
+// Globals: EDID data
+//------------------------------------------------------------------------------
+byte CheckEDID_Header (byte *Block)
+{
+	byte i = 0;
+
+	if (Block[i])               // byte 0 must be 0
+		return FALSE;
+
+	for (i = 1; i < 1 + EDID_HDR_NO_OF_FF; i++)
+	{
+		if(Block[i] != 0xFF)    // bytes [1..6] must be 0xFF
+			return FALSE;
+	}
+
+	if (Block[i])               // byte 7 must be 0
+		return FALSE;
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: DoEDID_Checksum()
+// Function Description: Calculte checksum of the 128 byte block pointed to by the
+//                  pointer passed as parameter
+//
+// Accepts: Pointer to a 128 byte block whose checksum needs to be calculated
+// Returns: TRUE or FLASE
+// Globals: EDID data
+//------------------------------------------------------------------------------
+byte DoEDID_Checksum (byte *Block)
+{
+	byte i;
+	byte CheckSum = 0;
+
+	for (i = 0; i < EDID_BLOCK_SIZE; i++)
+		CheckSum += Block[i];
+
+	if (CheckSum)
+		return FALSE;
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ParseEstablishedTiming()
+// Function Description: Parse the established timing section of EDID Block 0 and
+//                  print their decoded meaning to the screen.
+//
+// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored.
+// Returns: none
+// Globals: EDID data
+//------------------------------------------------------------------------------
+#if (CONF__TPI_EDID_PRINT == ENABLE)
+void ParseEstablishedTiming (byte *Data)
+{
+	TPI_EDID_PRINT(("Parsing Established Timing:\n"));
+	TPI_EDID_PRINT(("===========================\n"));
+
+	// Parse Established Timing Byte #0
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_7)
+		TPI_EDID_PRINT(("720 x 400 @ 70Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_6)
+		TPI_EDID_PRINT(("720 x 400 @ 88Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_5)
+		TPI_EDID_PRINT(("640 x 480 @ 60Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_4)
+		TPI_EDID_PRINT(("640 x 480 @ 67Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_3)
+		TPI_EDID_PRINT(("640 x 480 @ 72Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_2)
+		TPI_EDID_PRINT(("640 x 480 @ 75Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_1)
+		TPI_EDID_PRINT(("800 x 600 @ 56Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX] & BIT_0)
+		TPI_EDID_PRINT(("800 x 400 @ 60Hz\n"));
+
+	// Parse Established Timing Byte #1:
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_7)
+		TPI_EDID_PRINT(("800 x 600 @ 72Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_6)
+		TPI_EDID_PRINT(("800 x 600 @ 75Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_5)
+		TPI_EDID_PRINT(("832 x 624 @ 75Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_4)
+		TPI_EDID_PRINT(("1024 x 768 @ 87Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_3)
+		TPI_EDID_PRINT(("1024 x 768 @ 60Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_2)
+		TPI_EDID_PRINT(("1024 x 768 @ 70Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_1)
+		TPI_EDID_PRINT(("1024 x 768 @ 75Hz\n"));
+	if(Data[ESTABLISHED_TIMING_INDEX + 1]  & BIT_0)
+		TPI_EDID_PRINT(("1280 x 1024 @ 75Hz\n"));
+
+	// Parse Established Timing Byte #2:
+	if(Data[ESTABLISHED_TIMING_INDEX + 2] & 0x80)
+		TPI_EDID_PRINT(("1152 x 870 @ 75Hz\n"));
+
+	if((!Data[0])&&(!Data[ESTABLISHED_TIMING_INDEX + 1]  )&&(!Data[2]))
+		TPI_EDID_PRINT(("No established video modes\n"));
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ParseStandardTiming()
+// Function Description: Parse the standard timing section of EDID Block 0 and
+//                  print their decoded meaning to the screen.
+//
+// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored.
+// Returns: none
+// Globals: EDID data
+//------------------------------------------------------------------------------
+void ParseStandardTiming (byte *Data)
+{
+	byte i;
+	byte AR_Code;
+
+	TPI_EDID_PRINT(("Parsing Standard Timing:\n"));
+	TPI_EDID_PRINT(("========================\n"));
+
+	for (i = 0; i < NUM_OF_STANDARD_TIMINGS; i += 2)
+	{
+		if ((Data[STANDARD_TIMING_OFFSET + i] == 0x01) && ((Data[STANDARD_TIMING_OFFSET + i +1]) == 1))
+		{
+			TPI_EDID_PRINT(("Standard Timing Undefined\n")); // per VESA EDID standard, Release A, Revision 1, February 9, 2000, Sec. 3.9
+		}
+		else
+		{
+			TPI_EDID_PRINT(("Horizontal Active pixels: %i\n", (int)((Data[STANDARD_TIMING_OFFSET + i] + 31)*8)));    // per VESA EDID standard, Release A, Revision 1, February 9, 2000, Table 3.15
+
+			AR_Code = (Data[STANDARD_TIMING_OFFSET + i +1] & TWO_MSBITS) >> 6;
+			TPI_EDID_PRINT(("Aspect Ratio: "));
+
+			switch(AR_Code)
+			{
+				case AR16_10:
+					TPI_EDID_PRINT(("16:10\n"));
+					break;
+
+				case AR4_3:
+					TPI_EDID_PRINT(("4:3\n"));
+					break;
+
+				case AR5_4:
+					TPI_EDID_PRINT(("5:4\n"));
+					break;
+
+				case AR16_9:
+					TPI_EDID_PRINT(("16:9\n"));
+					break;
+			}
+		}
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ParseDetailedTiming()
+// Function Description: Parse the detailed timing section of EDID Block 0 and
+//                  print their decoded meaning to the screen.
+//
+// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored.
+//              Offset to the beginning of the Detailed Timing Descriptor data.
+//
+//              Block indicator to distinguish between block #0 and blocks #2, #3
+// Returns: none
+// Globals: EDID data
+//------------------------------------------------------------------------------
+byte ParseDetailedTiming (byte *Data, byte DetailedTimingOffset, byte Block)
+{
+	byte TmpByte;
+	byte i;
+	word TmpWord;
+
+	TmpWord = Data[DetailedTimingOffset + PIX_CLK_OFFSET] +
+		256 * Data[DetailedTimingOffset + PIX_CLK_OFFSET + 1];
+
+	if (TmpWord == 0x00)            // 18 byte partition is used as either for Monitor Name or for Monitor Range Limits or it is unused
+	{
+		if (Block == EDID_BLOCK_0)      // if called from Block #0 and first 2 bytes are 0 => either Monitor Name or for Monitor Range Limits
+		{
+			if (Data[DetailedTimingOffset + 3] == 0xFC) // these 13 bytes are ASCII coded monitor name
+			{
+				TPI_EDID_PRINT(("Monitor Name: "));
+
+				for (i = 0; i < 13; i++)
+				{
+					TPI_EDID_PRINT(("%c", Data[DetailedTimingOffset + 5 + i])); // Display monitor name on SiIMon
+				}
+				TPI_EDID_PRINT(("\n"));
+			}
+
+			else if (Data[DetailedTimingOffset + 3] == 0xFD) // these 13 bytes contain Monitor Range limits, binary coded
+			{
+				TPI_EDID_PRINT(("Monitor Range Limits:\n\n"));
+
+				i = 0;
+				TPI_EDID_PRINT(("Min Vertical Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Max Vertical Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Min Horizontal Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Max Horizontal Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Max Supported pixel clock rate in MHz/10: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Tag for secondary timing formula (00h=not used): %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); //
+				TPI_EDID_PRINT(("Min Vertical Rate in Hz %d\n", (int) Data[DetailedTimingOffset + 5 + i])); //
+				TPI_EDID_PRINT(("\n"));
+			}
+		}
+
+		else if (Block == EDID_BLOCK_2_3)                          // if called from block #2 or #3 and first 2 bytes are 0x00 (padding) then this
+		{                                                                                          // descriptor partition is not used and parsing should be stopped
+			TPI_EDID_PRINT(("No More Detailed descriptors in this block\n"));
+			TPI_EDID_PRINT(("\n"));
+			return FALSE;
+		}
+	}
+
+	else                                            // first 2 bytes are not 0 => this is a detailed timing descriptor from either block
+	{
+		if((Block == EDID_BLOCK_0) && (DetailedTimingOffset == 0x36))
+		{
+			TPI_EDID_PRINT(("\n\n\nParse Results, EDID Block #0, Detailed Descriptor Number 1:\n"));
+			TPI_EDID_PRINT(("===========================================================\n\n"));
+		}
+		else if((Block == EDID_BLOCK_0) && (DetailedTimingOffset == 0x48))
+		{
+			TPI_EDID_PRINT(("\n\n\nParse Results, EDID Block #0, Detailed Descriptor Number 2:\n"));
+			TPI_EDID_PRINT(("===========================================================\n\n"));
+		}
+
+		TPI_EDID_PRINT(("Pixel Clock (MHz * 100): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + H_ACTIVE_OFFSET] +
+			256 * ((Data[DetailedTimingOffset + H_ACTIVE_OFFSET + 2] >> 4) & FOUR_LSBITS);
+		TPI_EDID_PRINT(("Horizontal Active Pixels: %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + H_BLANKING_OFFSET] +
+			256 * (Data[DetailedTimingOffset + H_BLANKING_OFFSET + 1] & FOUR_LSBITS);
+		TPI_EDID_PRINT(("Horizontal Blanking (Pixels): %d\n", (int)TmpWord));
+
+		TmpWord = (Data[DetailedTimingOffset + V_ACTIVE_OFFSET] )+
+			256 * ((Data[DetailedTimingOffset + (V_ACTIVE_OFFSET) + 2] >> 4) & FOUR_LSBITS);
+		TPI_EDID_PRINT(("Vertical Active (Lines): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + V_BLANKING_OFFSET] +
+			256 * (Data[DetailedTimingOffset + V_BLANKING_OFFSET + 1] & LOW_NIBBLE);
+		TPI_EDID_PRINT(("Vertical Blanking (Lines): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + H_SYNC_OFFSET] +
+			256 * ((Data[DetailedTimingOffset + (H_SYNC_OFFSET + 3)] >> 6) & TWO_LSBITS);
+		TPI_EDID_PRINT(("Horizontal Sync Offset (Pixels): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + H_SYNC_PW_OFFSET] +
+			256 * ((Data[DetailedTimingOffset + (H_SYNC_PW_OFFSET + 2)] >> 4) & TWO_LSBITS);
+		TPI_EDID_PRINT(("Horizontal Sync Pulse Width (Pixels): %d\n", (int)TmpWord));
+
+		TmpWord = (Data[DetailedTimingOffset + V_SYNC_OFFSET] >> 4) & FOUR_LSBITS +
+			256 * ((Data[DetailedTimingOffset + (V_SYNC_OFFSET + 1)] >> 2) & TWO_LSBITS);
+		TPI_EDID_PRINT(("Vertical Sync Offset (Lines): %d\n", (int)TmpWord));
+
+		TmpWord = (Data[DetailedTimingOffset + V_SYNC_PW_OFFSET]) & FOUR_LSBITS +
+			256 * (Data[DetailedTimingOffset + (V_SYNC_PW_OFFSET + 1)] & TWO_LSBITS);
+		TPI_EDID_PRINT(("Vertical Sync Pulse Width (Lines): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + H_IMAGE_SIZE_OFFSET] +
+			256 * (((Data[DetailedTimingOffset + (H_IMAGE_SIZE_OFFSET + 2)]) >> 4) & FOUR_LSBITS);
+		TPI_EDID_PRINT(("Horizontal Image Size (mm): %d\n", (int)TmpWord));
+
+		TmpWord = Data[DetailedTimingOffset + V_IMAGE_SIZE_OFFSET] +
+			256 * (Data[DetailedTimingOffset + (V_IMAGE_SIZE_OFFSET + 1)] & FOUR_LSBITS);
+		TPI_EDID_PRINT(("Vertical Image Size (mm): %d\n", (int)TmpWord));
+
+		TmpByte = Data[DetailedTimingOffset + H_BORDER_OFFSET];
+		TPI_EDID_PRINT(("Horizontal Border (Pixels): %d\n", (int)TmpByte));
+
+		TmpByte = Data[DetailedTimingOffset + V_BORDER_OFFSET];
+		TPI_EDID_PRINT(("Vertical Border (Lines): %d\n", (int)TmpByte));
+
+		TmpByte = Data[DetailedTimingOffset + FLAGS_OFFSET];
+		if (TmpByte & BIT_7)
+			TPI_EDID_PRINT(("Interlaced\n"));
+		else
+			TPI_EDID_PRINT(("Non-Interlaced\n"));
+
+		if (!(TmpByte & BIT_5) && !(TmpByte & BIT_6))
+			TPI_EDID_PRINT(("Normal Display, No Stereo\n"));
+		else
+			TPI_EDID_PRINT(("Refer to VESA E-EDID Release A, Revision 1, table 3.17\n"));
+
+		if (!(TmpByte & BIT_3) && !(TmpByte & BIT_4))
+			TPI_EDID_PRINT(("Analog Composite\n"));
+		if ((TmpByte & BIT_3) && !(TmpByte & BIT_4))
+			TPI_EDID_PRINT(("Bipolar Analog Composite\n"));
+		else if (!(TmpByte & BIT_3) && (TmpByte & BIT_4))
+			TPI_EDID_PRINT(("Digital Composite\n"));
+
+		else if ((TmpByte & BIT_3) && (TmpByte & BIT_4))
+			TPI_EDID_PRINT(("Digital Separate\n"));
+
+		TPI_EDID_PRINT(("\n"));
+	}
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ParseBlock_0_TimingDescriptors()
+// Function Description: Parse EDID Block 0 timing descriptors per EEDID 1.3
+//                  standard. printf() values to screen.
+//
+// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored.
+// Returns: none
+// Globals: EDID data
+//------------------------------------------------------------------------------
+void ParseBlock_0_TimingDescriptors (byte *Data)
+{
+	byte i;
+	byte Offset;
+
+	ParseEstablishedTiming(Data);
+	ParseStandardTiming(Data);
+
+	for (i = 0; i < NUM_OF_DETAILED_DESCRIPTORS; i++)
+	{
+		Offset = DETAILED_TIMING_OFFSET + (LONG_DESCR_LEN * i);
+		ParseDetailedTiming(Data, Offset, EDID_BLOCK_0);
+	}
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Function Name: ParseEDID()
+// Function Description: Extract sink properties from its EDID file and save them in
+//                  global structure g_edid.
+//
+// Accepts: none
+// Returns: TRUE or FLASE
+// Globals: EDID data
+// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.
+//------------------------------------------------------------------------------
+byte ParseEDID (byte *pEdid, byte *numExt)
+{
+	byte i, j, k;
+
+	TPI_EDID_PRINT(("\n"));
+	TPI_EDID_PRINT(("EDID DATA (Segment = 0 Block = 0 Offset = %d):\n", (int) EDID_BLOCK_0_OFFSET));
+
+	for (j = 0, i = 0; j < 128; j++)
+	{
+		k = pEdid[j];
+		TPI_EDID_PRINT(("%2.2X ", (int) k));
+		i++;
+
+		if (i == 0x10)
+		{
+			TPI_EDID_PRINT(("\n"));
+			i = 0;
+		}
+	}
+	TPI_EDID_PRINT(("\n"));
+
+	if (!CheckEDID_Header(pEdid))                      //Checks if EDID header is correct per VESA E-EDID standard(/byte 0 must be 0, bytes [1..6] must be 0xFF,byte 7 must be 0)
+	{
+		// first 8 bytes of EDID must be {0, FF, FF, FF, FF, FF, FF, 0}
+		TPI_DEBUG_PRINT(("EDID -> Incorrect Header\n"));
+		return EDID_INCORRECT_HEADER;
+	}
+
+	if (!DoEDID_Checksum(pEdid))
+	{
+		// non-zero EDID checksum
+		TPI_DEBUG_PRINT(("EDID -> Checksum Error\n"));
+		return EDID_CHECKSUM_ERROR;
+	}
+
+#if (CONF__TPI_EDID_PRINT == ENABLE)
+	ParseBlock_0_TimingDescriptors(pEdid);			// Parse EDID Block #0 Desctiptors
+#endif
+
+	*numExt = pEdid[NUM_OF_EXTEN_ADDR];	// read # of extensions from offset 0x7E of block 0
+	TPI_EDID_PRINT(("EDID -> 861 Extensions = %d\n", (int) *numExt));
+
+	if (!(*numExt))
+	{
+		// No extensions to worry about
+		return EDID_NO_861_EXTENSIONS;
+	}
+
+	//return Parse861Extensions(NumOfExtensions);			// Parse 861 Extensions (short and long descriptors);
+	return (EDID_OK);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: Parse861ShortDescriptors()
+// Function Description: Parse CEA-861 extension short descriptors of the EDID block
+//                  passed as a parameter and save them in global structure g_edid.
+//
+// Accepts: A pointer to the EDID 861 Extension block being parsed.
+// Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed.
+// Globals: EDID data
+// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.
+//------------------------------------------------------------------------------
+byte Parse861ShortDescriptors (byte *Data)
+{
+	byte LongDescriptorOffset;
+	byte DataBlockLength;
+	byte DataIndex;
+	byte ExtendedTagCode;
+	byte VSDB_BaseOffset = 0;
+
+	byte V_DescriptorIndex = 0;  // static to support more than one extension
+	byte A_DescriptorIndex = 0;  // static to support more than one extension
+
+	byte TagCode;
+
+	byte i;
+	byte j;
+
+	if (Data[EDID_TAG_ADDR] != EDID_EXTENSION_TAG)
+	{
+		TPI_EDID_PRINT(("EDID -> Extension Tag Error\n"));
+		return EDID_EXT_TAG_ERROR;
+	}
+
+	if (Data[EDID_REV_ADDR] != EDID_REV_THREE)
+	{
+		TPI_EDID_PRINT(("EDID -> Revision Error\n"));
+		return EDID_REV_ADDR_ERROR;
+	}
+
+	LongDescriptorOffset = Data[LONG_DESCR_PTR_IDX];    // block offset where long descriptors start
+
+	g_edid.UnderScan = ((Data[MISC_SUPPORT_IDX]) >> 7) & LSBIT;  // byte #3 of CEA extension version 3
+	g_edid.BasicAudio = ((Data[MISC_SUPPORT_IDX]) >> 6) & LSBIT;
+	g_edid.YCbCr_4_4_4 = ((Data[MISC_SUPPORT_IDX]) >> 5) & LSBIT;
+	g_edid.YCbCr_4_2_2 = ((Data[MISC_SUPPORT_IDX]) >> 4) & LSBIT;
+
+	DataIndex = EDID_DATA_START;            // 4
+
+	while (DataIndex < LongDescriptorOffset)
+	{
+		TagCode = (Data[DataIndex] >> 5) & THREE_LSBITS;
+		DataBlockLength = Data[DataIndex++] & FIVE_LSBITS;
+		if ((DataIndex + DataBlockLength) > LongDescriptorOffset)
+		{
+			TPI_EDID_PRINT(("EDID -> V Descriptor Overflow\n"));
+			return EDID_V_DESCR_OVERFLOW;
+		}
+
+		i = 0;                                  // num of short video descriptors in current data block
+
+		switch (TagCode)
+		{
+			case VIDEO_D_BLOCK:
+				while ((i < DataBlockLength) && (i < MAX_V_DESCRIPTORS))        // each SVD is 1 byte long
+				{
+					g_edid.VideoDescriptor[V_DescriptorIndex++] = Data[DataIndex++];
+					i++;
+				}
+				DataIndex += DataBlockLength - i;   // if there are more STDs than MAX_V_DESCRIPTORS, skip the last ones. Update DataIndex
+
+				TPI_EDID_PRINT(("EDID -> Short Descriptor Video Block\n"));
+				break;
+
+			case AUDIO_D_BLOCK:
+				while (i < DataBlockLength/3)       // each SAD is 3 bytes long
+				{
+					j = 0;
+					while (j < AUDIO_DESCR_SIZE)    // 3
+					{
+						g_edid.AudioDescriptor[A_DescriptorIndex][j++] = Data[DataIndex++];
+					}
+					A_DescriptorIndex++;
+					i++;
+				}
+				TPI_EDID_PRINT(("EDID -> Short Descriptor Audio Block\n"));
+				break;
+
+			case  SPKR_ALLOC_D_BLOCK:
+				g_edid.SpkrAlloc[i++] = Data[DataIndex++];       // although 3 bytes are assigned to Speaker Allocation, only
+				DataIndex += 2;                                     // the first one carries information, so the next two are ignored by this code.
+				TPI_EDID_PRINT(("EDID -> Short Descriptor Speaker Allocation Block\n"));
+				break;
+
+			case USE_EXTENDED_TAG:
+				ExtendedTagCode = Data[DataIndex++];
+
+				switch (ExtendedTagCode)
+				{
+					case VIDEO_CAPABILITY_D_BLOCK:
+						TPI_EDID_PRINT(("EDID -> Short Descriptor Video Capability Block\n"));
+
+						// TO BE ADDED HERE: Save "video capability" parameters in g_edid data structure
+						// Need to modify that structure definition
+						// In the meantime: just increment DataIndex by 1
+						DataIndex += 1;    // replace with reading and saving the proper data per CEA-861 sec. 7.5.6 while incrementing DataIndex
+						break;
+
+					case COLORIMETRY_D_BLOCK:
+						g_edid.ColorimetrySupportFlags = Data[DataIndex++] & BITS_1_0;
+						g_edid.MetadataProfile = Data[DataIndex++] & BITS_2_1_0;
+
+						TPI_EDID_PRINT(("EDID -> Short Descriptor Colorimetry Block\n"));
+						break;
+				}
+				break;
+
+			case VENDOR_SPEC_D_BLOCK:
+				VSDB_BaseOffset = DataIndex - 1;
+
+				if ((Data[DataIndex++] == 0x03) &&    // check if sink is HDMI compatible
+						(Data[DataIndex++] == 0x0C) &&
+						(Data[DataIndex++] == 0x00))
+
+					g_edid.HDMI_Sink = TRUE;
+				else
+					g_edid.HDMI_Sink = FALSE;
+
+				g_edid.CEC_A_B = Data[DataIndex++];  // CEC Physical address
+				g_edid.CEC_C_D = Data[DataIndex++];
+
+#ifdef DEV_SUPPORT_CEC
+				// Take the Address that was passed in the EDID and use this API
+				// to set the physical address for CEC.
+				{
+					word	phyAddr;
+					phyAddr = (word)g_edid.CEC_C_D;	 // Low-order nibbles
+					phyAddr |= ((word)g_edid.CEC_A_B << 8); // Hi-order nibbles
+					// Is the new PA different from the current PA?
+					if (phyAddr != SI_CecGetDevicePA ())
+					{
+						// Yes!  So change the PA
+						SI_CecSetDevicePA (phyAddr);
+					}
+				}
+#endif
+
+				if ((DataIndex + 7) > VSDB_BaseOffset + DataBlockLength)        // Offset of 3D_Present bit in VSDB
+					g_edid._3D_Supported = FALSE;
+				else if (Data[DataIndex + 7] >> 7)
+					g_edid._3D_Supported = TRUE;
+				else
+					g_edid._3D_Supported = FALSE;
+
+				DataIndex += DataBlockLength - HDMI_SIGNATURE_LEN - CEC_PHYS_ADDR_LEN; // Point to start of next block
+				TPI_EDID_PRINT(("EDID -> Short Descriptor Vendor Block\n"));
+				TPI_EDID_PRINT(("\n"));
+				break;
+
+			default:
+				TPI_EDID_PRINT(("EDID -> Unknown Tag Code\n"));
+				return EDID_UNKNOWN_TAG_CODE;
+
+		}                   // End, Switch statement
+	}                       // End, while (DataIndex < LongDescriptorOffset) statement
+
+	return EDID_SHORT_DESCRIPTORS_OK;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: Parse861LongDescriptors()
+// Function Description: Parse CEA-861 extension long descriptors of the EDID block
+//                  passed as a parameter and printf() them to the screen.
+//
+// Accepts: A pointer to the EDID block being parsed
+// Returns: An error code if no long descriptors found; EDID_PARSED_OK if descriptors found.
+// Globals: none
+//------------------------------------------------------------------------------
+byte Parse861LongDescriptors (byte *Data)
+{
+	byte LongDescriptorsOffset;
+	byte DescriptorNum = 1;
+
+	LongDescriptorsOffset = Data[LONG_DESCR_PTR_IDX];   // EDID block offset 2 holds the offset
+
+	if (!LongDescriptorsOffset)                         // per CEA-861-D, table 27
+	{
+		TPI_DEBUG_PRINT(("EDID -> No Detailed Descriptors\n"));
+		return EDID_NO_DETAILED_DESCRIPTORS;
+	}
+
+	// of the 1st 18-byte descriptor
+	while (LongDescriptorsOffset + LONG_DESCR_LEN < EDID_BLOCK_SIZE)
+	{
+		TPI_EDID_PRINT(("Parse Results - CEA-861 Long Descriptor #%d:\n", (int) DescriptorNum));
+		TPI_EDID_PRINT(("===============================================================\n"));
+
+#if (CONF__TPI_EDID_PRINT == ENABLE)
+		if (!ParseDetailedTiming(Data, LongDescriptorsOffset, EDID_BLOCK_2_3))
+			break;
+#endif
+		LongDescriptorsOffset +=  LONG_DESCR_LEN;
+		DescriptorNum++;
+	}
+
+	return EDID_LONG_DESCRIPTORS_OK;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: Parse861Extensions()
+// Function Description: Parse CEA-861 extensions from EDID ROM (EDID blocks beyond
+//                  block #0). Save short descriptors in global structure
+//                  g_edid. printf() long descriptors to the screen.
+//
+// Accepts: The number of extensions in the EDID being parsed
+// Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed.
+// Globals: EDID data
+// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.
+//------------------------------------------------------------------------------
+byte Parse861Extensions (byte NumOfExtensions)
+{
+	byte i,j,k;
+
+	byte ErrCode;
+
+	//byte V_DescriptorIndex = 0;
+	//byte A_DescriptorIndex = 0;
+
+	byte Segment = 0;
+	byte Block = 0;
+	byte Offset = 0;
+
+	g_edid.HDMI_Sink = FALSE;
+
+	do
+	{
+		Block++;
+
+		Offset = 0;
+		if ((Block % 2) > 0)
+		{
+			Offset = EDID_BLOCK_SIZE;
+		}
+
+		Segment = (byte) (Block / 2);
+
+		if (Block == 1)
+		{
+			ReadBlockEDID(EDID_BLOCK_1_OFFSET, EDID_BLOCK_SIZE, g_CommData);    // read first 128 bytes of EDID ROM
+		}
+		else
+		{
+			ReadSegmentBlockEDID(Segment, Offset, EDID_BLOCK_SIZE, g_CommData);     // read next 128 bytes of EDID ROM
+		}
+
+		TPI_TRACE_PRINT(("\n"));
+		TPI_TRACE_PRINT(("EDID DATA (Segment = %d Block = %d Offset = %d):\n", (int) Segment, (int) Block, (int) Offset));
+		for (j=0, i=0; j<128; j++)
+		{
+			k = g_CommData[j];
+			TPI_EDID_PRINT(("%2.2X ", (int) k));
+			i++;
+
+			if (i == 0x10)
+			{
+				TPI_EDID_PRINT(("\n"));
+				i = 0;
+			}
+		}
+		TPI_EDID_PRINT(("\n"));
+
+		if ((NumOfExtensions > 1) && (Block == 1))
+		{
+			continue;
+		}
+
+		ErrCode = Parse861ShortDescriptors(g_CommData);
+		if (ErrCode != EDID_SHORT_DESCRIPTORS_OK)
+		{
+			return ErrCode;
+		}
+
+		ErrCode = Parse861LongDescriptors(g_CommData);
+		if (ErrCode != EDID_LONG_DESCRIPTORS_OK)
+		{
+			return ErrCode;
+		}
+
+	} while (Block < NumOfExtensions);
+
+	return EDID_OK;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: DoEdidRead()
+// Function Description: EDID processing
+//
+// Accepts: none
+// Returns: TRUE or FLASE
+// Globals: none
+//------------------------------------------------------------------------------
+byte DoEdidRead (void)
+{
+	byte SysCtrlReg;
+	byte Result;
+	byte NumOfExtensions;
+
+	// If we already have valid EDID data, ship this whole thing
+	if (g_edid.edidDataValid == FALSE)
+	{
+		// Request access to DDC bus from the receiver
+		if (GetDDC_Access(&SysCtrlReg))
+		{
+			ReadBlockEDID(EDID_BLOCK_0_OFFSET, EDID_BLOCK_SIZE, g_CommData);		// read first 128 bytes of EDID ROM
+			Result = ParseEDID(g_CommData, &NumOfExtensions);
+			if (Result != EDID_OK)
+			{
+				if (Result == EDID_NO_861_EXTENSIONS)
+				{
+					TPI_DEBUG_PRINT (("EDID -> No 861 Extensions\n"));
+					g_edid.HDMI_Sink = FALSE;
+					g_edid.YCbCr_4_4_4 = FALSE;
+					g_edid.YCbCr_4_2_2 = FALSE;
+					g_edid.CEC_A_B = 0x00;
+					g_edid.CEC_C_D = 0x00;
+				}
+				else
+				{
+					TPI_DEBUG_PRINT (("EDID -> Parse FAILED\n"));
+					g_edid.HDMI_Sink = TRUE;
+					g_edid.YCbCr_4_4_4 = FALSE;
+					g_edid.YCbCr_4_2_2 = FALSE;
+					g_edid.CEC_A_B = 0x00;
+					g_edid.CEC_C_D = 0x00;
+				}
+			}
+			else
+			{
+				TPI_DEBUG_PRINT (("EDID -> Parse OK\n"));
+				Result = Parse861Extensions(NumOfExtensions);		// Parse 861 Extensions (short and long descriptors);
+				if (Result != EDID_OK)
+				{
+					TPI_DEBUG_PRINT(("EDID -> Extension Parse FAILED\n"));
+					g_edid.HDMI_Sink = TRUE;
+					g_edid.YCbCr_4_4_4 = FALSE;
+					g_edid.YCbCr_4_2_2 = FALSE;
+					g_edid.CEC_A_B = 0x00;
+					g_edid.CEC_C_D = 0x00;
+				}
+			}
+
+			if (!ReleaseDDC(SysCtrlReg))				// Host must release DDC bus once it is done reading EDID
+			{
+				TPI_DEBUG_PRINT (("EDID -> DDC bus release failed\n"));
+				return EDID_DDC_BUS_RELEASE_FAILURE;
+			}
+		}
+		else
+		{
+			TPI_DEBUG_PRINT (("EDID -> DDC bus request failed\n"));
+			g_edid.HDMI_Sink = TRUE;
+			g_edid.YCbCr_4_4_4 = FALSE;
+			g_edid.YCbCr_4_2_2 = FALSE;
+			g_edid.CEC_A_B = 0x00;
+			g_edid.CEC_C_D = 0x00;
+			return EDID_DDC_BUS_REQ_FAILURE;
+		}
+
+		TPI_DEBUG_PRINT(("EDID -> g_edid.HDMI_Sink = %d\n", (int)g_edid.HDMI_Sink));
+		TPI_DEBUG_PRINT(("EDID -> g_edid.YCbCr_4_4_4 = %d\n", (int)g_edid.YCbCr_4_4_4));
+		TPI_DEBUG_PRINT(("EDID -> g_edid.YCbCr_4_2_2 = %d\n", (int)g_edid.YCbCr_4_2_2));
+		TPI_DEBUG_PRINT(("EDID -> g_edid.CEC_A_B = 0x%x\n", (int)g_edid.CEC_A_B));
+		TPI_DEBUG_PRINT(("EDID -> g_edid.CEC_C_D = 0x%x\n", (int)g_edid.CEC_C_D));
+
+		g_edid.edidDataValid = TRUE;
+	}
+	return 0;
+}
+
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////                  HDCP                 ///////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------
+// Function Name: IsHDCP_Supported()
+// Function Description: Check Tx revision number to find if this Tx supports HDCP
+//                  by reading the HDCP revision number from TPI register 0x30.
+//
+// Accepts: none
+// Returns: TRUE if Tx supports HDCP. FALSE if not.
+// Globals: none
+//------------------------------------------------------------------------------
+byte IsHDCP_Supported (void)
+{
+	byte HDCP_Rev;
+	byte HDCP_Supported;
+
+	TPI_TRACE_PRINT((">>IsHDCP_Supported()\n"));
+
+	HDCP_Supported = TRUE;
+
+	// Check Device ID
+	HDCP_Rev = ReadByteTPI(TPI_HDCP_REVISION_DATA_REG);
+
+	if (HDCP_Rev != (HDCP_MAJOR_REVISION_VALUE | HDCP_MINOR_REVISION_VALUE))
+	{
+		HDCP_Supported = FALSE;
+	}
+
+	// Even if HDCP is supported check for incorrect Device ID // for SiI_9022AYBT_DEVICEID_CHECK
+	HDCP_Rev = ReadByteTPI(TPI_AKSV_1_REG);
+	if (HDCP_Rev == 0x09)
+	{
+		HDCP_Rev = ReadByteTPI(TPI_AKSV_2_REG);
+		if (HDCP_Rev == 0x00)
+		{
+			HDCP_Rev = ReadByteTPI(TPI_AKSV_3_REG);
+			if (HDCP_Rev == 0x02)
+			{
+				HDCP_Rev = ReadByteTPI(TPI_AKSV_4_REG);
+				if (HDCP_Rev == 0x02)
+				{
+					HDCP_Rev = ReadByteTPI(TPI_AKSV_5_REG);
+					if (HDCP_Rev == 0x0a)
+					{
+						HDCP_Supported = FALSE;
+						TPI_TRACE_PRINT((">>sii902xA found, NO HDCP supported\n"));
+					}
+				}
+			}
+		}
+	}
+	return HDCP_Supported;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: AreAKSV_OK()
+// Function Description: Check if AKSVs contain 20 '0' and 20 '1'
+//
+// Accepts: none
+// Returns: TRUE if 20 zeros and 20 ones found in AKSV. FALSE OTHERWISE
+// Globals: none
+//------------------------------------------------------------------------------
+byte AreAKSV_OK (void)
+{
+	byte B_Data[AKSV_SIZE];
+	byte NumOfOnes = 0;
+	byte i, j;
+
+	TPI_TRACE_PRINT((">>AreAKSV_OK()\n"));
+
+	ReadBlockTPI(TPI_AKSV_1_REG, AKSV_SIZE, B_Data);
+
+	for (i=0; i<AKSV_SIZE; i++)
+	{
+		for (j=0; j<BYTE_SIZE; j++)
+		{
+			if (B_Data[i] & 0x01)
+			{
+				NumOfOnes++;
+			}
+			B_Data[i] >>= 1;
+		}
+	}
+	if (NumOfOnes != NUM_OF_ONES_IN_KSV)
+		return FALSE;
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: HDCP_Off()
+// Function Description: Switch hdcp off.
+//------------------------------------------------------------------------------
+void HDCP_Off (void)
+{
+	TPI_TRACE_PRINT((">>HDCP_Off()\n"));
+
+	// AV MUTE
+	ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, AV_MUTE_MASK, AV_MUTE_MUTED);
+	WriteByteTPI(TPI_HDCP_CONTROL_DATA_REG, PROTECTION_LEVEL_MIN);
+
+	g_hdcp.HDCP_Started = FALSE;
+	g_hdcp.HDCP_LinkProtectionLevel = EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: HDCP_On()
+// Function Description: Switch hdcp on.
+//------------------------------------------------------------------------------
+void HDCP_On (void)
+{
+	if (g_hdcp.HDCP_Override == FALSE)
+	{
+		TPI_DEBUG_PRINT(("HDCP Started\n"));
+
+		WriteByteTPI(TPI_HDCP_CONTROL_DATA_REG, PROTECTION_LEVEL_MAX);
+
+		g_hdcp.HDCP_Started = TRUE;
+	}
+	else
+	{
+		g_hdcp.HDCP_Started = FALSE;
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: RestartHDCP()
+// Function Description: Restart HDCP.
+//------------------------------------------------------------------------------
+void RestartHDCP (void)
+{
+	TPI_DEBUG_PRINT (("HDCP -> Restart\n"));
+
+	DisableTMDS();
+	HDCP_Off();
+	EnableTMDS();
+}
+
+//------------------------------------------------------------------------------
+// Function Name: HDCP_Init()
+// Function Description: Tests Tx and Rx support of HDCP. If found, checks if
+//                  and attempts to set the security level accordingly.
+//
+// Accepts: none
+// Returns: TRUE if HW TPI started successfully. FALSE if failed to.
+// Globals: HDCP_TxSupports - initialized to FALSE, set to TRUE if supported by this device
+//		   HDCP_AksvValid - initialized to FALSE, set to TRUE if valid AKSVs are read from this device
+//		   HDCP_Started - initialized to FALSE
+//		   HDCP_LinkProtectionLevel - initialized to (EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE)
+//------------------------------------------------------------------------------
+void HDCP_Init (void)
+{
+	TPI_TRACE_PRINT((">>HDCP_Init()\n"));
+
+	g_hdcp.HDCP_TxSupports = FALSE;
+	g_hdcp.HDCP_AksvValid = FALSE;
+	g_hdcp.HDCP_Started = FALSE;
+	g_hdcp.HDCP_LinkProtectionLevel = EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE;
+
+	// This is TX-related... need only be done once.
+	if (!IsHDCP_Supported())
+	{
+		// The TX does not support HDCP, so authentication will never be attempted.
+		// Video will be shown as soon as TMDS is enabled.
+		TPI_DEBUG_PRINT(("HDCP -> TX does not support HDCP\n"));
+		return;
+	}
+	g_hdcp.HDCP_TxSupports = TRUE;
+
+	// This is TX-related... need only be done once.
+	if (!AreAKSV_OK())
+	{
+		// The TX supports HDCP, but does not have valid AKSVs.
+		// Video will not be shown.
+		TPI_DEBUG_PRINT(("HDCP -> Illegal AKSV\n"));
+		return;
+	}
+	g_hdcp.HDCP_AksvValid = TRUE;
+
+#ifdef KSVFORWARD
+	// Enable the KSV Forwarding feature and the KSV FIFO Intererrupt
+	ReadModifyWriteTPI(TPI_HDCP_CONTROL_DATA_REG, KSV_FORWARD_MASK, KSV_FORWARD_ENABLE);
+	ReadModifyWriteTPI(TPI_KSV_FIFO_READY_INT_EN, KSV_FIFO_READY_EN_MASK, KSV_FIFO_READY_ENABLE);
+#endif
+
+	TPI_DEBUG_PRINT(("HDCP -> Supported by TX, AKSVs valid\n"));
+}
+
+#ifdef READKSV
+//------------------------------------------------------------------------------
+// Function Name: IsRepeater()
+// Function Description: Test if sink is a repeater.
+//
+// Accepts: none
+// Returns: TRUE if sink is a repeater. FALSE if not.
+// Globals: none
+//------------------------------------------------------------------------------
+byte IsRepeater (void)
+{
+	byte RegImage;
+
+	TPI_TRACE_PRINT((">>IsRepeater()\n"));
+
+	RegImage = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG);
+
+	if (RegImage & HDCP_REPEATER_MASK)
+		return TRUE;
+
+	return FALSE;           // not a repeater
+}
+
+//------------------------------------------------------------------------------
+// Function Name: ReadBlockHDCP()
+// Function Description: Read NBytes from offset Addr of the HDCP slave address
+//                      into a byte Buffer pointed to by Data
+//
+// Accepts: HDCP port offset, number of bytes to read and a pointer to the data buffer where 
+//               the data read will be saved
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void ReadBlockHDCP (byte TPI_Offset, word NBytes, byte * pData)
+{
+	I2CReadBlock(siiHDCP, TPI_Offset, NBytes, pData);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: GetKSV()
+// Function Description: Collect all downstrean KSV for verification.
+//
+// Accepts: none
+// Returns: TRUE if KSVs collected successfully. False if not.
+// Globals: KSV_Array[], The buffer is limited to KSV_ARRAY_SIZE due to the 8051 implementation.
+//------------------------------------------------------------------------------
+byte GetKSV (void)
+{
+	byte i;
+	word KeyCount;
+	byte KSV_Array[KSV_ARRAY_SIZE];
+
+	TPI_TRACE_PRINT((">>GetKSV()\n"));
+	ReadBlockHDCP(DDC_BSTATUS_ADDR_L, 1, &i);
+	KeyCount = (i & DEVICE_COUNT_MASK) * 5;
+	if (KeyCount != 0)
+	{
+		ReadBlockHDCP(DDC_KSV_FIFO_ADDR, KeyCount, KSV_Array);
+	}
+
+	/*
+	   TPI_TRACE_PRINT(("KeyCount = %d\n", (int) KeyCount));
+	   for (i=0; i<KeyCount; i++)
+	   {
+	   TPI_TRACE_PRINT(("KSV[%2d] = %2.2X\n", (int) i, (int) KSV_Array[i]));
+	   }
+	   */
+
+	return TRUE;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Function Name: HDCP_CheckStatus()
+// Function Description: Check HDCP status.
+//
+// Accepts: InterruptStatus
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void HDCP_CheckStatus (byte InterruptStatusImage)
+{
+	byte QueryData;
+	byte LinkStatus;
+	byte RegImage;
+	byte NewLinkProtectionLevel;
+
+#ifdef READKSV
+	byte RiCnt;
+#endif
+#ifdef KSVFORWARD
+	byte ksv;
+#endif
+
+	if ((g_hdcp.HDCP_TxSupports == TRUE) && (g_hdcp.HDCP_AksvValid == TRUE))
+	{
+		if ((g_hdcp.HDCP_LinkProtectionLevel == (EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE)) && (g_hdcp.HDCP_Started == FALSE))
+		{
+			QueryData = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG);
+
+			if (QueryData & PROTECTION_TYPE_MASK)   // Is HDCP avaialable
+			{
+				HDCP_On();
+			}
+		}
+
+		// Check if Link Status has changed:
+		if (InterruptStatusImage & SECURITY_CHANGE_EVENT) 
+		{
+			TPI_DEBUG_PRINT (("HDCP -> "));
+
+			LinkStatus = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG);
+			LinkStatus &= LINK_STATUS_MASK;
+
+			ClearInterrupt(SECURITY_CHANGE_EVENT);
+
+			switch (LinkStatus)
+			{
+				case LINK_STATUS_NORMAL:
+					TPI_DEBUG_PRINT (("Link = Normal\n"));
+					break;
+
+				case LINK_STATUS_LINK_LOST:
+					TPI_DEBUG_PRINT (("Link = Lost\n"));
+					RestartHDCP();
+					break;
+
+				case LINK_STATUS_RENEGOTIATION_REQ:
+					TPI_DEBUG_PRINT (("Link = Renegotiation Required\n"));
+					HDCP_Off();
+					HDCP_On();
+					break;
+
+				case LINK_STATUS_LINK_SUSPENDED:
+					TPI_DEBUG_PRINT (("Link = Suspended\n"));
+					HDCP_On();
+					break;
+			}
+		}
+
+		// Check if HDCP state has changed:
+		if (InterruptStatusImage & HDCP_CHANGE_EVENT)
+		{
+			RegImage = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG);
+
+			NewLinkProtectionLevel = RegImage & (EXTENDED_LINK_PROTECTION_MASK | LOCAL_LINK_PROTECTION_MASK);
+			if (NewLinkProtectionLevel != g_hdcp.HDCP_LinkProtectionLevel)
+			{
+				TPI_DEBUG_PRINT (("HDCP -> "));
+
+				g_hdcp.HDCP_LinkProtectionLevel = NewLinkProtectionLevel;
+
+				switch (g_hdcp.HDCP_LinkProtectionLevel)
+				{
+					case (EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE):
+						TPI_DEBUG_PRINT (("Protection = None\n"));
+						RestartHDCP();
+						break;
+
+					case LOCAL_LINK_PROTECTION_SECURE:
+
+						if (IsHDMI_Sink())
+						{
+							ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_MUTE_MASK, AUDIO_MUTE_NORMAL);
+						}
+
+						ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, AV_MUTE_MASK, AV_MUTE_NORMAL);
+						TPI_DEBUG_PRINT (("Protection = Local, Video Unmuted\n"));
+						break;
+
+					case (EXTENDED_LINK_PROTECTION_SECURE | LOCAL_LINK_PROTECTION_SECURE):
+						TPI_DEBUG_PRINT (("Protection = Extended\n"));
+#ifdef READKSV
+						if (IsRepeater())
+						{
+							RiCnt = ReadIndexedRegister(INDEXED_PAGE_0, 0x25);
+							while (RiCnt > 0x70)  // Frame 112
+							{
+								RiCnt = ReadIndexedRegister(INDEXED_PAGE_0, 0x25);
+							}
+							ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, 0x06, 0x06);
+							GetKSV();
+							RiCnt = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG);
+							ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, 0x08, 0x00);
+						}
+#endif
+						break;
+
+					default:
+						TPI_DEBUG_PRINT (("Protection = Extended but not Local?\n"));
+						RestartHDCP();
+						break;
+				}
+			}
+
+#ifdef KSVFORWARD			
+			// Check if KSV FIFO is ready and forward - Bug# 17892
+			// If interrupt never goes off:
+			//   a) KSV formwarding is not enabled
+			//   b) not a repeater
+			//   c) a repeater with device count == 0
+			// and therefore no KSV list to forward
+			if ((ReadByteTPI(TPI_KSV_FIFO_READY_INT) & KSV_FIFO_READY_MASK) == KSV_FIFO_READY_YES)
+			{
+				ReadModifyWriteTPI(TPI_KSV_FIFO_READY_INT, KSV_FIFO_READY_MASK, KSV_FIFO_READY_YES);
+				TPI_DEBUG_PRINT (("KSV Fwd: KSV FIFO has data...\n"));
+				{
+					// While !(last byte has been read from KSV FIFO)
+					// if (count = 0) then a byte is not in the KSV FIFO yet, do not read
+					//   else read a byte from the KSV FIFO and forward it or keep it for revocation check
+					do 
+					{
+						ksv = ReadByteTPI(TPI_KSV_FIFO_STATUS_REG);
+						if (ksv & KSV_FIFO_COUNT_MASK)
+						{
+							TPI_DEBUG_PRINT (("KSV Fwd: KSV FIFO Count = %d, ", (int)(ksv & KSV_FIFO_COUNT_MASK)));
+							ksv = ReadByteTPI(TPI_KSV_FIFO_VALUE_REG);	// Forward or store for revocation check
+							TPI_DEBUG_PRINT (("Value = %d\n", (int)ksv));
+						}
+					} while ((ksv & KSV_FIFO_LAST_MASK) == KSV_FIFO_LAST_NO);
+					TPI_DEBUG_PRINT (("KSV Fwd: Last KSV FIFO forward complete\n"));
+				}
+			}
+#endif
+			ClearInterrupt(HDCP_CHANGE_EVENT);
+		}
+	}
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////             AV CONFIG              ///////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//------------------------------------------------------------------------------
+// Video mode table
+//------------------------------------------------------------------------------
+struct ModeIdType
+{
+	byte Mode_C1;
+	byte Mode_C2;
+	byte SubMode;
+};
+
+struct PxlLnTotalType
+{
+	word Pixels;
+	word Lines;
+} ;
+struct HVPositionType
+{
+	word H;
+	word V;
+};
+
+struct HVResolutionType
+{
+	word H;
+	word V;
+};
+
+struct TagType
+{
+	byte           	RefrTypeVHPol;
+	word           	VFreq;
+	struct PxlLnTotalType 	Total;
+};
+
+struct  _656Type
+{
+	byte IntAdjMode;
+	word HLength;
+	byte VLength;
+	word Top;
+	word Dly;
+	word HBit2HSync;
+	byte VBit2VSync;
+	word Field2Offset;
+};
+
+struct Vspace_Vblank
+{
+	byte VactSpace1;
+	byte VactSpace2;
+	byte Vblank1;
+	byte Vblank2;
+	byte Vblank3;
+};
+
+//
+// WARNING!  The entries in this enum must remian in the samre order as the PC Codes part
+// of the VideoModeTable[].
+//
+typedef	enum
+{
+	PC_640x350_85_08 = 0,
+	PC_640x400_85_08,
+	PC_720x400_70_08,
+	PC_720x400_85_04,
+	PC_640x480_59_94,
+	PC_640x480_72_80,
+	PC_640x480_75_00,
+	PC_640x480_85_00,
+	PC_800x600_56_25,
+	PC_800x600_60_317,
+	PC_800x600_72_19,
+	PC_800x600_75,
+	PC_800x600_85_06,
+	PC_1024x768_60,
+	PC_1024x768_70_07,
+	PC_1024x768_75_03,
+	PC_1024x768_85,
+	PC_1152x864_75,
+	PC_1600x1200_60,
+	PC_1280x768_59_95,
+	PC_1280x768_59_87,
+	PC_280x768_74_89,
+	PC_1280x768_85,
+	PC_1280x960_60,
+	PC_1280x960_85,
+	PC_1280x1024_60,
+	PC_1280x1024_75,
+	PC_1280x1024_85,
+	PC_1360x768_60,
+	PC_1400x105_59_95,
+	PC_1400x105_59_98,
+	PC_1400x105_74_87,
+	PC_1400x105_84_96,
+	PC_1600x1200_65,
+	PC_1600x1200_70,
+	PC_1600x1200_75,
+	PC_1600x1200_85,
+	PC_1792x1344_60,
+	PC_1792x1344_74_997,
+	PC_1856x1392_60,
+	PC_1856x1392_75,
+	PC_1920x1200_59_95,
+	PC_1920x1200_59_88,
+	PC_1920x1200_74_93,
+	PC_1920x1200_84_93,
+	PC_1920x1440_60,
+	PC_1920x1440_75,
+	PC_12560x1440_60,
+	PC_SIZE			// Must be last
+} PcModeCode_t;
+
+struct VModeInfoType
+{
+	struct ModeIdType       	ModeId;
+	dword             		PixClk;
+	struct TagType          		Tag;
+	struct HVPositionType  	Pos;
+	struct HVResolutionType 	Res;
+	byte             		AspectRatio;
+	struct _656Type         		_656;
+	byte             		PixRep;
+	struct Vspace_Vblank 		VsVb;
+	byte             		_3D_Struct;
+};
+
+#define NSM                     0   // No Sub-Mode
+
+#define	DEFAULT_VIDEO_MODE		0	// 640  x 480p @ 60 VGA
+
+#define ProgrVNegHNeg           0x00
+#define ProgrVNegHPos           	0x01
+#define ProgrVPosHNeg           	0x02
+#define ProgrVPosHPos           	0x03
+
+#define InterlaceVNegHNeg   	0x04
+#define InterlaceVPosHNeg      0x05
+#define InterlaceVNgeHPos    	0x06
+#define InterlaceVPosHPos     	0x07
+
+#define VIC_BASE                	0
+#define HDMI_VIC_BASE           43
+#define VIC_3D_BASE             	47
+#define PC_BASE                 	64
+
+// Aspect ratio
+//=================================================
+#define R_4                      		0   // 4:3
+#define R_4or16                  	1   // 4:3 or 16:9
+#define R_16                     		2   // 16:9
+
+//
+// These are the VIC codes that we support in a 3D mode
+//
+#define VIC_FOR_480P_60Hz_4X3			2		// 720p x 480p @60Hz
+#define VIC_FOR_480P_60Hz_16X9			3		// 720p x 480p @60Hz
+#define VIC_FOR_720P_60Hz				4		// 1280 x 720p @60Mhz
+#define VIC_FOR_1080i_60Hz				5		// 1920 x 1080i @60Mhz
+#define VIC_FOR_1080p_60Hz				16		// 1920 x 1080i @60hz
+#define VIC_FOR_720P_50Hz				19		// 1280 x 720p @50Mhz
+#define VIC_FOR_1080i_50Hz				20		// 1920 x 1080i @50Mhz
+#define VIC_FOR_1080p_50Hz				31		// 1920 x 720p @50Hz
+#define VIC_FOR_1080p_24Hz				32		// 1920 x 720p @24Hz
+
+
+static struct VModeInfoType VModesTable[] =
+{
+	//===================================================================================================================================================================================================================================
+	//         VIC                  Refresh type Refresh-Rate Pixel-Totals  Position     Active     Aspect   Int  Length          Hbit  Vbit  Field  Pixel          Vact Space/Blank
+	//        1   2  SubM   PixClk  V/H Position       VFreq   H      V      H    V       H    V    Ratio    Adj  H   V  Top  Dly HSync VSync Offset Repl  Space1 Space2 Blank1 Blank2 Blank3  3D
+	//===================================================================================================================================================================================================================================
+	{{        1,  0, NSM},  2517,  {ProgrVNegHNeg,     6000, { 800,  525}}, {144, 35}, { 640, 480}, R_4,     {0,  96, 2, 33,  48,  16,  10,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 0 - 1.       640  x 480p @ 60 VGA
+	{{        2,  3, NSM},  2700,  {ProgrVNegHNeg,     6000, { 858,  525}}, {122, 36}, { 720, 480}, R_4or16, {0,  62, 6, 30,  60,  19,   9,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 1 - 2,3      720  x 480p
+	{{        4,  0, NSM},  7425,  {ProgrVPosHPos,     6000, {1650,  750}}, {260, 25}, {1280, 720}, R_16,    {0,  40, 5, 20, 220, 110,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 2 - 4        1280 x 720p@60Hz
+	{{        5,  0, NSM},  7425,  {InterlaceVPosHPos, 6000, {2200,  562}}, {192, 20}, {1920,1080}, R_16,    {0,  44, 5, 15, 148,  88,   2, 1100},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 3 - 5        1920 x 1080i
+	{{        6,  7, NSM},  2700,  {InterlaceVNegHNeg, 6000, {1716,  264}}, {119, 18}, { 720, 480}, R_4or16, {3,  62, 3, 15, 114,  17,   5,  429},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 4 - 6,7      1440 x 480i,pix repl
+	{{        8,  9,   1},  2700,  {ProgrVNegHNeg,     6000, {1716,  262}}, {119, 18}, {1440, 240}, R_4or16, {0, 124, 3, 15, 114,  38,   4,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 5 - 8,9(1)   1440 x 240p
+	{{        8,  9,   2},  2700,  {ProgrVNegHNeg,     6000, {1716,  263}}, {119, 18}, {1440, 240}, R_4or16, {0, 124, 3, 15, 114,  38,   4,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 6 - 8,9(2)   1440 x 240p
+	{{       10, 11, NSM},  5400,  {InterlaceVNegHNeg, 6000, {3432,  525}}, {238, 18}, {2880, 480}, R_4or16, {0, 248, 3, 15, 228,  76,   4, 1716},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 7 - 10,11    2880 x 480i
+	{{       12, 13,   1},  5400,  {ProgrVNegHNeg,     6000, {3432,  262}}, {238, 18}, {2880, 240}, R_4or16, {0, 248, 3, 15, 228,  76,   4,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 8 - 12,13(1) 2880 x 240p
+	{{       12, 13,   2},  5400,  {ProgrVNegHNeg,     6000, {3432,  263}}, {238, 18}, {2880, 240}, R_4or16, {0, 248, 3, 15, 228,  76,   4,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 9 - 12,13(2) 2880 x 240p
+	{{       14, 15, NSM},  5400,  {ProgrVNegHNeg,     6000, {1716,  525}}, {244, 36}, {1440, 480}, R_4or16, {0, 124, 6, 30, 120,  32,   9,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 10 - 14,15    1440 x 480p
+	{{       16,  0, NSM}, 14835,  {ProgrVPosHPos,     6000, {2200, 1125}}, {192, 41}, {1920,1080}, R_16,    {0,  44, 5, 36, 148,  88,   4,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 11 - 16       1920 x 1080p
+	{{       17, 18, NSM},  2700,  {ProgrVNegHNeg,     5000, { 864,  625}}, {132, 44}, { 720, 576}, R_4or16, {0,  64, 5, 39,  68,  12,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 12 - 17,18    720  x 576p
+	{{       19,  0, NSM},  7425,  {ProgrVPosHPos,     5000, {1980,  750}}, {260, 25}, {1280, 720}, R_16,    {0,  40, 5, 20, 220, 440,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 13 - 19       1280 x 720p@50Hz
+	{{       20,  0, NSM},  7425,  {InterlaceVPosHPos, 5000, {2640, 1125}}, {192, 20}, {1920,1080}, R_16,    {0,  44, 5, 15, 148, 528,   2, 1320},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 14 - 20       1920 x 1080i
+	{{       21, 22, NSM},  2700,  {InterlaceVNegHNeg, 5000, {1728,  625}}, {132, 22}, { 720, 576}, R_4,     {3,  63, 3, 19, 138,  24,   2,  432},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 15 - 21,22    1440 x 576i
+	{{       23, 24,   1},  2700,  {ProgrVNegHNeg,     5000, {1728,  312}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138,  24,   2,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 16 - 23,24(1) 1440 x 288p
+	{{       23, 24,   2},  2700,  {ProgrVNegHNeg,     5000, {1728,  313}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138,  24,   2,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 17 - 23,24(2) 1440 x 288p
+	{{       23, 24,   3},  2700,  {ProgrVNegHNeg,     5000, {1728,  314}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138,  24,   2,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 18 - 23,24(3) 1440 x 288p
+	{{       25, 26, NSM},  5400,  {InterlaceVNegHNeg, 5000, {3456,  625}}, {264, 22}, {2880, 576}, R_4or16, {0, 252, 3, 19, 276,  48,   2, 1728},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 19 - 25,26    2880 x 576i
+	{{       27, 28,   1},  5400,  {ProgrVNegHNeg,     5000, {3456,  312}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276,  48,   2,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 20 - 27,28(1) 2880 x 288p
+	{{       27, 28,   2},  5400,  {ProgrVNegHNeg,     5000, {3456,  313}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276,  48,   3,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 21 - 27,28(2) 2880 x 288p
+	{{       27, 28,   3},  5400,  {ProgrVNegHNeg,     5000, {3456,  314}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276,  48,   4,    0},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 22 - 27,28(3) 2880 x 288p
+	{{       29, 30, NSM},  5400,  {ProgrVPosHNeg,     5000, {1728,  625}}, {264, 44}, {1440, 576}, R_4or16, {0, 128, 5, 39, 136,  24,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 23 - 29,30    1440 x 576p
+	{{       31,  0, NSM}, 14850,  {ProgrVPosHPos,     5000, {2640, 1125}}, {192, 41}, {1920,1080}, R_16,    {0,  44, 5, 36, 148, 528,   4,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 24 - 31(1)    1920 x 1080p
+	{{       32,  0, NSM},  7417,  {ProgrVPosHPos,     2400, {2750, 1125}}, {192, 41}, {1920,1080}, R_16,    {0,  44, 5, 36, 148, 638,   4,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 25 - 32(2)    1920 x 1080p@24Hz
+	{{       33,  0, NSM},  7425,  {ProgrVPosHPos,     2500, {2640, 1125}}, {192, 41}, {1920,1080}, R_16,    {0,  44, 5, 36, 148, 528,   4,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 26 - 33(3)    1920 x 1080p
+	{{       34,  0, NSM},  7417,  {ProgrVPosHPos,     3000, {2200, 1125}}, {192, 41}, {1920,1080}, R_16,    {0,  44, 5, 36, 148, 528,   4,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 27 - 34(4)    1920 x 1080p
+	{{       35, 36, NSM}, 10800,  {ProgrVNegHNeg,     5994, {3432,  525}}, {488, 36}, {2880, 480}, R_4or16, {0, 248, 6, 30, 240,  64,  10,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 28 - 35, 36   2880 x 480p@59.94/60Hz
+	{{       37, 38, NSM}, 10800,  {ProgrVNegHNeg,     5000, {3456,  625}}, {272, 39}, {2880, 576}, R_4or16, {0, 256, 5, 40, 272,  48,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 29 - 37, 38   2880 x 576p@50Hz
+	{{       39,  0, NSM},  7200,  {InterlaceVNegHNeg, 5000, {2304, 1250}}, {352, 62}, {1920,1080}, R_16,    {0, 168, 5, 87, 184,  32,  24,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 30 - 39       1920 x 1080i@50Hz
+	{{       40,  0, NSM}, 14850,  {InterlaceVPosHPos, 10000,{2640, 1125}}, {192, 20}, {1920,1080}, R_16,    {0,  44, 5, 15, 148, 528,   2, 1320},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 31 - 40       1920 x 1080i@100Hz
+	{{       41,  0, NSM}, 14850,  {InterlaceVPosHPos, 10000,{1980,  750}}, {260, 25}, {1280, 720}, R_16,    {0,  40, 5, 20, 220, 400,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 32 - 41       1280 x 720p@100Hz
+	{{       42, 43, NSM},  5400,  {ProgrVNegHNeg,     10000,{ 864,  144}}, {132, 44}, { 720, 576}, R_4or16, {0,  64, 5, 39,  68,  12,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 33 - 42, 43,  720p x 576p@100Hz
+	{{       44, 45, NSM},  5400,  {InterlaceVNegHNeg, 10000,{ 864,  625}}, {132, 22}, { 720, 576}, R_4or16, {0,  63, 3, 19,  69,  12,   2,  432},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 34 - 44, 45,  720p x 576i@100Hz, pix repl
+	{{       46,  0, NSM}, 14835,  {InterlaceVPosHPos, 11988,{2200, 1125}}, {192, 20}, {1920,1080}, R_16,    {0,  44, 5, 15, 149,  88,   2, 1100},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 35 - 46,      1920 x 1080i@119.88/120Hz
+	{{       47,  0, NSM}, 14835,  {ProgrVPosHPos,     11988,{1650,  750}}, {260, 25}, {1280, 720}, R_16,    {0,  40, 5, 20, 220, 110,   5, 1100},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 36 - 47,      1280 x 720p@119.88/120Hz
+	{{       48, 49, NSM},  5400,  {ProgrVNegHNeg,     11988,{ 858,  525}}, {122, 36}, { 720, 480}, R_4or16, {0,  62, 6, 30,  60,  16,  10,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 37 - 48, 49   720  x 480p@119.88/120Hz
+	{{       50, 51, NSM},  5400,  {InterlaceVNegHNeg, 11988,{ 858,  525}}, {119, 18}, { 720, 480}, R_4or16, {0,  62, 3, 15,  57,  19,   4,  429},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 38 - 50, 51   720  x 480i@119.88/120Hz
+	{{       52, 53, NSM}, 10800,  {ProgrVNegHNeg,     20000,{ 864,  625}}, {132, 44}, { 720, 576}, R_4or16, {0,  64, 5, 39,  68,  12,   5,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 39 - 52, 53,  720  x 576p@200Hz
+	{{       54, 55, NSM}, 10800,  {InterlaceVNegHNeg, 20000,{ 864,  625}}, {132, 22}, { 720, 576}, R_4or16, {0,  63, 3, 19,  69,  12,   2,  432},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 40 - 54, 55,  1440 x 576i @200Hz, pix repl
+	{{       56, 57, NSM}, 10800,  {ProgrVNegHNeg,     24000,{ 858,  525}}, {122, 42}, { 720, 480}, R_4or16, {0,  62, 6, 30,  60,  16,   9,    0},    0,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 41 - 56, 57,  720  x 480p @239.76/240Hz
+	{{       58, 59, NSM}, 10800,  {InterlaceVNegHNeg, 24000,{ 858,  525}}, {119, 18}, { 720, 480}, R_4or16, {0,  62, 3, 15,  57,  19,   4,  429},    1,    {0,     0,     0,     0,    0},    NO_3D_SUPPORT}, // 42 - 58, 59,  1440 x 480i @239.76/240Hz, pix repl
+
+
+	{{PC_BASE  , 0,NSM},    3150,   {ProgrVNegHPos,     8508,   {832, 445}},    {160,63},   {640,350},   R_16,  {0,  64,  3,  60,  96,  32,  32,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 64 - 640x350@85.08
+	{{PC_BASE+1, 0,NSM},    3150,   {ProgrVPosHNeg,     8508,   {832, 445}},    {160,44},   {640,400},   R_16,  {0,  64,  3,  41,  96,  32,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 65 - 640x400@85.08
+	{{PC_BASE+2, 0,NSM},    2700,   {ProgrVPosHNeg,     7008,   {900, 449}},    {0,0},      {720,400},   R_16,  {0,   0,  0,   0,   0,   0,   0,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 66 - 720x400@70.08
+	{{PC_BASE+3, 0,NSM},    3500,   {ProgrVPosHNeg,     8504,   {936, 446}},    {20,45},    {720,400},   R_16,  {0,  72,  3,  42, 108,  36,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 67 - 720x400@85.04
+	{{PC_BASE+4, 0,NSM},    2517,   {ProgrVNegHNeg,     5994,   {800, 525}},    {144,35},   {640,480},   R_4,   {0,  96,  2,  33,  48,  16,  10,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 68 - 640x480@59.94
+	{{PC_BASE+5, 0,NSM},    3150,   {ProgrVNegHNeg,     7281,   {832, 520}},    {144,31},   {640,480},   R_4,   {0,  40,  3,  28, 128, 128,   9,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 69 - 640x480@72.80
+	{{PC_BASE+6, 0,NSM},    3150,   {ProgrVNegHNeg,     7500,   {840, 500}},    {21,19},    {640,480},   R_4,   {0,  64,  3,  28, 128,  24,   9,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 70 - 640x480@75.00
+	{{PC_BASE+7,0,NSM},     3600,   {ProgrVNegHNeg,     8500,   {832, 509}},    {168,28},   {640,480},   R_4,   {0,  56,  3,  25, 128,  24,   9,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 71 - 640x480@85.00
+	{{PC_BASE+8,0,NSM},     3600,   {ProgrVPosHPos,     5625,   {1024, 625}},   {200,24},   {800,600},   R_4,   {0,  72,  2,  22, 128,  24,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 72 - 800x600@56.25
+	{{PC_BASE+9,0,NSM},     4000,   {ProgrVPosHPos,     6032,   {1056, 628}},   {216,27},   {800,600},   R_4,   {0, 128,  4,  23,  88,  40,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 73 - 800x600@60.317
+	{{PC_BASE+10,0,NSM},    5000,   {ProgrVPosHPos,     7219,   {1040, 666}},   {184,29},   {800,600},   R_4,   {0, 120,  6,  23,  64,  56,  37,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 74 - 800x600@72.19
+	{{PC_BASE+11,0,NSM},    4950,   {ProgrVPosHPos,     7500,   {1056, 625}},   {240,24},   {800,600},   R_4,   {0,  80,  3,  21, 160,  16,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 75 - 800x600@75
+	{{PC_BASE+12,0,NSM},    5625,   {ProgrVPosHPos,     8506,   {1048, 631}},   {216,30},   {800,600},   R_4,   {0,  64,  3,  27, 152,  32,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 76 - 800x600@85.06
+	{{PC_BASE+13,0,NSM},    6500,   {ProgrVNegHNeg,     6000,   {1344, 806}},   {296,35},   {1024,768},  R_4,   {0, 136,  6,  29, 160,  24,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 77 - 1024x768@60
+	{{PC_BASE+14,0,NSM},    7500,   {ProgrVNegHNeg,     7007,   {1328, 806}},   {280,35},   {1024,768},  R_4,   {0, 136,  6,  19, 144,  24,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 78 - 1024x768@70.07
+	{{PC_BASE+15,0,NSM},    7875,   {ProgrVPosHPos,     7503,   {1312, 800}},   {272,31},   {1024,768},  R_4,   {0,  96,  3,  28, 176,  16,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 79 - 1024x768@75.03
+	{{PC_BASE+16,0,NSM},    9450,   {ProgrVPosHPos,     8500,   {1376, 808}},   {304,39},   {1024,768},  R_4,   {0,  96,  3,  36, 208,  48,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 80 - 1024x768@85
+	{{PC_BASE+17,0,NSM},   10800,   {ProgrVPosHPos,     7500,   {1600, 900}},   {384,35},   {1152,864},  R_4,   {0, 128,  3,  32, 256,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 81 - 1152x864@75
+	{{PC_BASE+18,0,NSM},   16200,   {ProgrVPosHPos,     6000,   {2160, 1250}},  {496,49},   {1600,1200}, R_4,   {0, 304,  3,  46, 304,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 82 - 1600x1200@60
+	{{PC_BASE+19,0,NSM},    6825,   {ProgrVNegHPos,     6000,   {1440, 790}},   {112,19},   {1280,768},  R_16,  {0,  32,  7,  12,  80,  48,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 83 - 1280x768@59.95
+	{{PC_BASE+20,0,NSM},    7950,   {ProgrVPosHNeg,     5987,   {1664, 798}},   {320,27},   {1280,768},  R_16,  {0, 128,  7,  20, 192,  64,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 84 - 1280x768@59.87
+	{{PC_BASE+21,0,NSM},   10220,   {ProgrVPosHNeg,     6029,   {1696, 805}},   {320,27},   {1280,768},  R_16,  {0, 128,  7,  27, 208,  80,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 85 - 1280x768@74.89
+	{{PC_BASE+22,0,NSM},   11750,   {ProgrVPosHNeg,     8484,   {1712, 809}},   {352,38},   {1280,768},  R_16,  {0, 136,  7,  31, 216,  80,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 86 - 1280x768@85
+	{{PC_BASE+23,0,NSM},   10800,   {ProgrVPosHPos,     6000,   {1800, 1000}},  {424,39},   {1280,960},  R_4,   {0, 112,  3,  36, 312,  96,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 87 - 1280x960@60
+	{{PC_BASE+24,0,NSM},   14850,   {ProgrVPosHPos,     8500,   {1728, 1011}},  {384,50},   {1280,960},  R_4,   {0, 160,  3,  47, 224,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 88 - 1280x960@85
+	{{PC_BASE+25,0,NSM},   10800,   {ProgrVPosHPos,     6002,   {1688, 1066}},  {360,41},   {1280,1024}, R_4,   {0, 112,  3,  38, 248,  48,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 89 - 1280x1024@60
+	{{PC_BASE+26,0,NSM},   13500,   {ProgrVPosHPos,     7502,   {1688, 1066}},  {392,41},   {1280,1024}, R_4,   {0, 144,  3,  38, 248,  16,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 90 - 1280x1024@75
+	{{PC_BASE+27,0,NSM},   15750,   {ProgrVPosHPos,     8502,   {1728, 1072}},  {384,47},   {1280,1024}, R_4,   {0, 160,  3,   4, 224,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 91 - 1280x1024@85
+	{{PC_BASE+28,0,NSM},    8550,   {ProgrVPosHPos,     6002,   {1792, 795}},   {368,24},   {1360,768},  R_16,  {0, 112,  6,  18, 256,  64,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 92 - 1360x768@60
+	{{PC_BASE+29,0,NSM},   10100,   {ProgrVNegHPos,     5995,   {1560, 1080}},  {112,27},   {1400,1050}, R_4,   {0,  32,  4,  23,  80,  48,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 93 - 1400x105@59.95
+	{{PC_BASE+30,0,NSM},   12175,   {ProgrVPosHNeg,     5998,   {1864, 1089}},  {376,36},   {1400,1050}, R_4,   {0, 144,  4,  32, 232,  88,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 94 - 1400x105@59.98
+	{{PC_BASE+31,0,NSM},   15600,   {ProgrVPosHNeg,     7487,   {1896, 1099}},  {392,46},   {1400,1050}, R_4,   {0, 144,  4,  22, 248, 104,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 95 - 1400x105@74.87
+	{{PC_BASE+32,0,NSM},   17950,   {ProgrVPosHNeg,     8496,   {1912, 1105}},  {408,52},   {1400,1050}, R_4,   {0, 152,  4,  48, 256, 104,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 96 - 1400x105@84.96
+	{{PC_BASE+33,0,NSM},   17550,   {ProgrVPosHPos,     6500,   {2160, 1250}},  {496,49},   {1600,1200}, R_4,   {0, 192,  3,  46, 304,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 97 - 1600x1200@65
+	{{PC_BASE+34,0,NSM},   18900,   {ProgrVPosHPos,     7000,   {2160, 1250}},  {496,49},   {1600,1200}, R_4,   {0, 192,  3,  46, 304,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 98 - 1600x1200@70
+	{{PC_BASE+35,0,NSM},   20250,   {ProgrVPosHPos,     7500,   {2160, 1250}},  {496,49},   {1600,1200}, R_4,   {0, 192,  3,  46, 304,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 99 - 1600x1200@75
+	{{PC_BASE+36,0,NSM},   22950,   {ProgrVPosHPos,     8500,   {2160, 1250}},  {496,49},   {1600,1200}, R_4,   {0, 192,  3,  46, 304,  64,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 100 - 1600x1200@85
+	{{PC_BASE+37,0,NSM},   20475,   {ProgrVPosHNeg,     6000,   {2448, 1394}},  {528,49},   {1792,1344}, R_4,   {0, 200,  3,  46, 328, 128,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 101 - 1792x1344@60
+	{{PC_BASE+38,0,NSM},   26100,   {ProgrVPosHNeg,     7500,   {2456, 1417}},  {568,72},   {1792,1344}, R_4,   {0, 216,  3,  69, 352,  96,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 102 - 1792x1344@74.997
+	{{PC_BASE+39,0,NSM},   21825,   {ProgrVPosHNeg,     6000,   {2528, 1439}},  {576,46},   {1856,1392}, R_4,   {0, 224,  3,  43, 352,  96,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 103 - 1856x1392@60
+	{{PC_BASE+40,0,NSM},   28800,   {ProgrVPosHNeg,     7500,   {2560, 1500}},  {576,107},  {1856,1392}, R_4,   {0, 224,  3, 104, 352, 128,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 104 - 1856x1392@75
+	{{PC_BASE+41,0,NSM},   15400,   {ProgrVNegHPos,     5995,   {2080, 1235}},  {112,32},   {1920,1200}, R_16,  {0,  32,  6,  26,  80,  48,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 106 - 1920x1200@59.95
+	{{PC_BASE+42,0,NSM},   19325,   {ProgrVPosHNeg,     5988,   {2592, 1245}},  {536,42},   {1920,1200}, R_16,  {0, 200,  6,  36, 336, 136,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 107 - 1920x1200@59.88
+	{{PC_BASE+43,0,NSM},   24525,   {ProgrVPosHNeg,     7493,   {2608, 1255}},  {552,52},   {1920,1200}, R_16,  {0, 208,  6,  46, 344, 136,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 108 - 1920x1200@74.93
+	{{PC_BASE+44,0,NSM},   28125,   {ProgrVPosHNeg,     8493,   {2624, 1262}},  {560,59},   {1920,1200}, R_16,  {0, 208,  6,  53, 352, 144,   3,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 109 - 1920x1200@84.93
+	{{PC_BASE+45,0,NSM},   23400,   {ProgrVPosHNeg,     6000,   {2600, 1500}},  {552,59},   {1920,1440}, R_4,   {0, 208,  3,  56, 344, 128,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 110 - 1920x1440@60
+	{{PC_BASE+46,0,NSM},   29700,   {ProgrVPosHNeg,     7500,   {2640, 1500}},  {576,59},   {1920,1440}, R_4,   {0, 224,  3,  56, 352, 144,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 111 - 1920x1440@75
+	{{PC_BASE+47,0,NSM},   24150,   {ProgrVPosHNeg,     6000,   {2720, 1481}},  {48,  3},   {2560,1440}, R_16,  {0,  32,  5,  56, 352, 144,   1,       0},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 112 - 2560x1440@60 // %%% need work
+	{{PC_BASE+48,0,NSM},    2700,   {InterlaceVNegHNeg, 6000,   {1716,  264}},  {244,18},   {1440, 480},R_4or16,{3, 124,  3,  15, 114,  17,   5,     429},  0,  {0,     0,     0,     0,    0},   NO_3D_SUPPORT}, // 113 - 1440 x 480i 
+};
+
+
+//------------------------------------------------------------------------------
+// Aspect Ratio table defines the aspect ratio as function of VIC. This table
+// should be used in conjunction with the 861-D part of VModeInfoType VModesTable[]
+// (formats 0 - 59) because some formats that differ only in their AR are grouped
+// together (e.g., formats 2 and 3).
+//------------------------------------------------------------------------------
+static u8 AspectRatioTable[] =
+{
+	R_4,   R_4, R_16, R_16, R_16,  R_4, R_16,  R_4, R_16,  R_4,
+	R_16,  R_4, R_16,  R_4, R_16, R_16,  R_4, R_16, R_16, R_16,
+	R_4,   R_16, R_4, R_16,  R_4, R_16,  R_4, R_16,  R_4, R_16,
+	R_16,  R_16, R_16, R_16,  R_4, R_16,  R_4, R_16, R_16, R_16,
+	R_16,  R_4, R_16,  R_4, R_16, R_16, R_16,  R_4, R_16,  R_4,
+	R_16,  R_4, R_16,  R_4, R_16,  R_4, R_16,  R_4, R_16
+};
+
+//------------------------------------------------------------------------------
+// VIC to Indexc table defines which VideoModeTable entry is appropreate for this VIC code. 
+// Note: This table is valid ONLY for VIC codes in 861-D formats, NOT for HDMI_VIC codes
+// or 3D codes!
+//------------------------------------------------------------------------------
+static u8 VIC2Index[] =
+{
+	0,  0,  1,  1,  2,  3,  4,  4,  5,  5,
+	7,  7,  8,  8, 10, 10, 11, 12, 12, 13,
+	14, 15, 15, 16, 16, 19, 19, 20, 20, 23,
+	23, 24, 25, 26, 27, 28, 28, 29, 29, 30,
+	31, 32, 33, 33, 34, 34, 35, 36, 37, 37,
+	38, 38, 39, 39, 40, 40, 41, 41, 42, 42
+};
+
+//------------------------------------------------------------------------------
+// Function Name: ConvertVIC_To_VM_Index()
+// Function Description: Convert Video Identification Code to the corresponding
+//                  		index of VModesTable[]. Conversion also depends on the 
+//					value of the 3D_Structure parameter in the case of 3D video format.
+// Accepts: VIC to be converted; 3D_Structure value
+// Returns: Index into VModesTable[] corrsponding to VIC
+// Globals: VModesTable[] siHdmiTx
+// Note: Conversion is for 861-D formats, HDMI_VIC or 3D
+//------------------------------------------------------------------------------
+byte ConvertVIC_To_VM_Index (void)
+{
+	byte index;
+
+	//
+	// The global VideoModeDescription contains all the information we need about
+	// the Video mode for use to find its entry in the Videio mode table.
+	//
+	// The first issue.  The "VIC" may be a 891-D VIC code, or it might be an
+	// HDMI_VIC code, or it might be a 3D code.  Each require different handling
+	// to get the proper video mode table index.
+	//
+	if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_CEA_VIC)
+	{
+		//
+		// This is a regular 861-D format VIC, so we use the VIC to Index
+		// table to look up the index.
+		//
+		index = VIC2Index[siHdmiTx.VIC];
+	}
+	else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_HDMI_VIC)
+	{
+		//
+		// HDMI_VIC conversion is simple.  We need to subtract one because the codes start
+		// with one instead of zero.  These values are from HDMI 1.4 Spec Table 8-13. 
+		//
+		if ((siHdmiTx.VIC < 1) || (siHdmiTx.VIC > 4))
+		{
+			index = DEFAULT_VIDEO_MODE;
+		}
+		else
+		{
+			index = (HDMI_VIC_BASE - 1) + siHdmiTx.VIC;
+		}
+	}
+	else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_3D)
+	{
+		//
+		// Currently there are only a few VIC modes that we can do in 3D.  If the VIC code is not
+		// one of these OR if the packing type is not supported for that VIC code, then it is an
+		// error and we go to the default video mode.  See HDMI Spec 1.4 Table H-6.
+		//
+		switch (siHdmiTx.VIC)
+		{
+			case VIC_FOR_480P_60Hz_4X3:
+			case VIC_FOR_480P_60Hz_16X9:
+				// We only support Side-by-Side (Half) for these modes
+				if (siHdmiTx.ThreeDStructure == SIDE_BY_SIDE_HALF)
+					index = VIC_3D_BASE + 0;
+				else
+					index = DEFAULT_VIDEO_MODE;
+				break;
+
+			case VIC_FOR_720P_60Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 1;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_1080i_60Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 2;
+						break;
+					case VMD_3D_FIELDALTERNATIVE:
+						index = VIC_3D_BASE + 3;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_1080p_60Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 4;
+						break;
+					case VMD_3D_LINEALTERNATIVE:
+						index = VIC_3D_BASE + 5;
+						break;
+					case SIDE_BY_SIDE_FULL:
+						index = VIC_3D_BASE + 6;
+						break;
+					case SIDE_BY_SIDE_HALF:
+						index = VIC_3D_BASE + 7;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_720P_50Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 8;
+						break;
+					case VMD_3D_LDEPTH:
+						index = VIC_3D_BASE + 9;
+						break;
+					case VMD_3D_LDEPTHGRAPHICS:
+						index = VIC_3D_BASE + 10;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_1080i_50Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 11;			
+						break;
+					case VMD_3D_FIELDALTERNATIVE:
+						index = VIC_3D_BASE + 12;			
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_1080p_50Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 13;
+						break;
+					case VMD_3D_LINEALTERNATIVE:
+						index = VIC_3D_BASE + 14;
+						break;
+					case SIDE_BY_SIDE_FULL:
+						index = VIC_3D_BASE + 15;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			case VIC_FOR_1080p_24Hz:
+				switch(siHdmiTx.ThreeDStructure)
+				{
+					case FRAME_PACKING:
+						index = VIC_3D_BASE + 16;
+						break;
+					default:
+						index = DEFAULT_VIDEO_MODE;
+						break;
+				}
+				break;
+
+			default:
+				index = DEFAULT_VIDEO_MODE;
+				break;
+		}
+	}
+	else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_PC)
+	{
+		if (siHdmiTx.VIC < PC_SIZE)
+		{
+			index = siHdmiTx.VIC + PC_BASE;
+		}
+		else
+		{
+			index = DEFAULT_VIDEO_MODE;
+		}
+	}
+	else
+	{
+		// This should never happen!  If so, default to first table entry
+		index = DEFAULT_VIDEO_MODE;
+	}
+
+	return index;
+}
+
+
+// Patches
+//========
+byte TPI_REG0x63_SAVED = 0;
+
+//------------------------------------------------------------------------------
+// Function Name: SetEmbeddedSync()
+// Function Description: Set the 9022/4 registers to extract embedded sync.
+//
+// Accepts: Index of video mode to set
+// Returns: TRUE
+// Globals: VModesTable[]
+//------------------------------------------------------------------------------
+byte SetEmbeddedSync (void)
+{
+	byte	ModeTblIndex;
+	word H_Bit_2_H_Sync;
+	word Field2Offset;
+	word H_SyncWidth;
+
+	byte V_Bit_2_V_Sync;
+	byte V_SyncWidth;
+	byte B_Data[8];
+
+	TPI_TRACE_PRINT((">>SetEmbeddedSync()\n"));
+
+	ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x0A, 0x01, 0x01);   //set Output Format YCbCr 4:4:4
+	ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT);	 // set 0x60[7] = 0 for External DE mode
+	WriteByteTPI(TPI_DE_CTRL, 0x30);                           //Vsync and Hsync Polarity settings 1 : Negative(leading edge falls)
+	ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT);       // set 0x60[7] = 1 for Embedded Sync
+
+	ModeTblIndex = ConvertVIC_To_VM_Index(); 
+
+	H_Bit_2_H_Sync = VModesTable[ModeTblIndex]._656.HBit2HSync;
+	Field2Offset = VModesTable[ModeTblIndex]._656.Field2Offset;
+	H_SyncWidth = VModesTable[ModeTblIndex]._656.HLength;
+	V_Bit_2_V_Sync = VModesTable[ModeTblIndex]._656.VBit2VSync;
+	V_SyncWidth = VModesTable[ModeTblIndex]._656.VLength;
+
+	B_Data[0] = H_Bit_2_H_Sync & LOW_BYTE;                  // Setup HBIT_TO_HSYNC 8 LSBits (0x62)
+
+	B_Data[1] = (H_Bit_2_H_Sync >> 8) & TWO_LSBITS;         // HBIT_TO_HSYNC 2 MSBits
+	//B_Data[1] |= BIT_EN_SYNC_EXTRACT;                     // and Enable Embedded Sync to 0x63
+	TPI_REG0x63_SAVED = B_Data[1];
+
+	B_Data[2] = Field2Offset & LOW_BYTE;                    // 8 LSBits of "Field2 Offset" to 0x64
+	B_Data[3] = (Field2Offset >> 8) & LOW_NIBBLE;           // 2 MSBits of "Field2 Offset" to 0x65
+
+	B_Data[4] = H_SyncWidth & LOW_BYTE;
+	B_Data[5] = (H_SyncWidth >> 8) & TWO_LSBITS;                    // HWIDTH to 0x66, 0x67
+	B_Data[6] = V_Bit_2_V_Sync;                                     // VBIT_TO_VSYNC to 0x68
+	B_Data[7] = V_SyncWidth;                                        // VWIDTH to 0x69
+
+	WriteBlockTPI(TPI_HBIT_TO_HSYNC_7_0, 8, &B_Data[0]);
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: EnableEmbeddedSync()
+// Function Description: EnableEmbeddedSync
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void EnableEmbeddedSync (void)
+{
+	TPI_TRACE_PRINT((">>EnableEmbeddedSync()\n"));
+
+	ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT);	 // set 0x60[7] = 0 for DE mode
+	WriteByteTPI(TPI_DE_CTRL, 0x30);
+	ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT);       // set 0x60[7] = 1 for Embedded Sync
+	ReadSetWriteTPI(TPI_DE_CTRL, BIT_6);
+}
+
+//------------------------------------------------------------------------------
+// Function Name: SetDE()
+// Function Description: Set the 9022/4 internal DE generator parameters
+//
+// Accepts: none
+// Returns: DE_SET_OK
+// Globals: none
+//
+// NOTE: 0x60[7] must be set to "0" for the follwing settings to take effect
+//------------------------------------------------------------------------------
+byte SetDE (void)
+{
+	byte RegValue;
+	byte	ModeTblIndex;
+
+	word H_StartPos, V_StartPos;
+	word Htotal, Vtotal;
+	word H_Res, V_Res;
+
+	byte Polarity;
+	byte B_Data[12];
+
+	TPI_TRACE_PRINT((">>SetDE()\n"));
+
+	ModeTblIndex = ConvertVIC_To_VM_Index();
+
+	if (VModesTable[ModeTblIndex]._3D_Struct != NO_3D_SUPPORT)
+	{
+		return DE_CANNOT_BE_SET_WITH_3D_MODE;
+		TPI_TRACE_PRINT((">>SetDE() not allowed with 3D video format\n"));
+	}
+
+	// Make sure that External Sync method is set before enableing the DE Generator:
+	RegValue = ReadByteTPI(TPI_SYNC_GEN_CTRL);
+
+	if (RegValue & BIT_7)
+	{
+		return DE_CANNOT_BE_SET_WITH_EMBEDDED_SYNC;
+	}
+
+	H_StartPos = VModesTable[ModeTblIndex].Pos.H;
+	V_StartPos = VModesTable[ModeTblIndex].Pos.V;
+
+	Htotal = VModesTable[ModeTblIndex].Tag.Total.Pixels;
+	Vtotal = VModesTable[ModeTblIndex].Tag.Total.Lines;
+
+	Polarity = (~VModesTable[ModeTblIndex].Tag.RefrTypeVHPol) & TWO_LSBITS;
+
+	H_Res = VModesTable[ModeTblIndex].Res.H;
+
+	if ((VModesTable[ModeTblIndex].Tag.RefrTypeVHPol & 0x04))
+	{
+		V_Res = (VModesTable[ModeTblIndex].Res.V) >> 1;       //if interlace V-resolution divided by 2
+	}
+	else
+	{
+		V_Res = (VModesTable[ModeTblIndex].Res.V);
+	}
+
+	B_Data[0] = H_StartPos & LOW_BYTE;              // 8 LSB of DE DLY in 0x62
+
+	B_Data[1] = (H_StartPos >> 8) & TWO_LSBITS;     // 2 MSBits of DE DLY to 0x63
+	B_Data[1] |= (Polarity << 4);                   // V and H polarity
+	B_Data[1] |= BIT_EN_DE_GEN;                     // enable DE generator
+
+	B_Data[2] = V_StartPos & SEVEN_LSBITS;      // DE_TOP in 0x64
+	B_Data[3] = 0x00;                           // 0x65 is reserved
+	B_Data[4] = H_Res & LOW_BYTE;               // 8 LSBits of DE_CNT in 0x66
+	B_Data[5] = (H_Res >> 8) & LOW_NIBBLE;      // 4 MSBits of DE_CNT in 0x67
+	B_Data[6] = V_Res & LOW_BYTE;               // 8 LSBits of DE_LIN in 0x68
+	B_Data[7] = (V_Res >> 8) & THREE_LSBITS;    // 3 MSBits of DE_LIN in 0x69
+	B_Data[8] = Htotal & LOW_BYTE;				// 8 LSBits of H_RES in 0x6A
+	B_Data[9] =	(Htotal >> 8) & LOW_NIBBLE;		// 4 MSBITS of H_RES in 0x6B
+	B_Data[10] = Vtotal & LOW_BYTE;				// 8 LSBits of V_RES in 0x6C
+	B_Data[11] = (Vtotal >> 8) & BITS_2_1_0;	// 3 MSBITS of V_RES in 0x6D
+
+	WriteBlockTPI(TPI_DE_DLY, 12, &B_Data[0]);
+	TPI_REG0x63_SAVED = B_Data[1];
+
+	return DE_SET_OK;                               // Write completed successfully
+}
+
+//------------------------------------------------------------------------------
+// Function Name: SetFormat()
+// Function Description: Set the 9022/4 format
+//
+// Accepts: none
+// Returns: DE_SET_OK
+// Globals: none
+//------------------------------------------------------------------------------
+void SetFormat (byte *Data)
+{
+	ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_HDMI); // Set HDMI mode to allow color space conversion
+
+	WriteBlockTPI(TPI_INPUT_FORMAT_REG, 2, Data);   // Program TPI AVI Input and Output Format
+	WriteByteTPI(TPI_END_RIGHT_BAR_MSB, 0x00);	  // Set last byte of TPI AVI InfoFrame for TPI AVI I/O Format to take effect
+
+	if (!IsHDMI_Sink()) 
+	{
+		ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_DVI);
+	}
+
+	if (siHdmiTx.SyncMode == EMBEDDED_SYNC)
+		EnableEmbeddedSync();					// Last byte of TPI AVI InfoFrame resets Embedded Sync Extraction
+}
+
+//------------------------------------------------------------------------------
+// Function Name: printVideoMode()
+// Function Description: print video mode
+//
+// Accepts: siHdmiTx.VIC
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void printVideoMode (void)
+{
+	TPI_TRACE_PRINT((">>Video mode = "));
+
+	switch (siHdmiTx.VIC)
+	{
+		case 6:
+			TPI_TRACE_PRINT(("HDMI_480I60_4X3 \n"));
+			break;
+		case 21:
+			TPI_TRACE_PRINT(("HDMI_576I50_4X3 \n"));
+			break;
+		case 2:
+			TPI_TRACE_PRINT(("HDMI_480P60_4X3 \n"));
+			break;
+		case 17:
+			TPI_TRACE_PRINT(("HDMI_576P50_4X3 \n"));
+			break;
+		case 4:
+			TPI_TRACE_PRINT(("HDMI_720P60 \n"));
+			break;
+		case 19:
+			TPI_TRACE_PRINT(("HDMI_720P50 \n"));
+			break;
+		case 5:
+			TPI_TRACE_PRINT(("HDMI_1080I60 \n"));
+			break;
+		case 20:
+			TPI_TRACE_PRINT(("HDMI_1080I50 \n"));
+			break;
+		case 16:
+			TPI_TRACE_PRINT(("HDMI_1080P60 \n"));
+			break;
+		case 31:
+			TPI_TRACE_PRINT(("HDMI_1080P50 \n"));
+			break;
+		case PC_BASE+13:
+			TPI_TRACE_PRINT(("HDMI_1024_768_60 \n"));
+			break;
+		case PC_BASE+9:
+			TPI_TRACE_PRINT(("HDMI_800_600_60 \n"));
+			break;
+		default:
+			break;
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: InitVideo()
+// Function Description: Set the 9022/4 to the video mode determined by GetVideoMode()
+//
+// Accepts: Index of video mode to set; Flag that distinguishes between
+//                  calling this function after power up and after input
+//                  resolution change
+// Returns: TRUE
+// Globals: VModesTable, VideoCommandImage
+//------------------------------------------------------------------------------
+byte InitVideo (byte TclkSel)
+{
+	byte	ModeTblIndex;
+
+#ifdef DEEP_COLOR
+	byte temp;
+#endif
+	byte B_Data[8];
+
+	byte EMB_Status; //EmbeddedSync set flag
+	byte DE_Status;
+	byte Pattern;
+
+	TPI_TRACE_PRINT((">>InitVideo()\n"));
+	printVideoMode();
+	TPI_TRACE_PRINT((" HF:%d", (int) siHdmiTx.HDMIVideoFormat));
+	TPI_TRACE_PRINT((" VIC:%d", (int) siHdmiTx.VIC));
+	TPI_TRACE_PRINT((" A:%x", (int) siHdmiTx.AspectRatio));
+	TPI_TRACE_PRINT((" CS:%x", (int) siHdmiTx.ColorSpace));
+	TPI_TRACE_PRINT((" CD:%x", (int) siHdmiTx.ColorDepth));
+	TPI_TRACE_PRINT((" CR:%x", (int) siHdmiTx.Colorimetry));
+	TPI_TRACE_PRINT((" SM:%x", (int) siHdmiTx.SyncMode));
+	TPI_TRACE_PRINT((" TCLK:%x", (int) siHdmiTx.TclkSel)); 
+	TPI_TRACE_PRINT((" 3D:%d", (int) siHdmiTx.ThreeDStructure));
+	TPI_TRACE_PRINT((" 3Dx:%d\n", (int) siHdmiTx.ThreeDExtData));
+
+	ModeTblIndex = (byte)ConvertVIC_To_VM_Index();
+
+	Pattern = (TclkSel << 6) & TWO_MSBITS;							// Use TPI 0x08[7:6] for 9022A/24A video clock multiplier
+	ReadSetWriteTPI(TPI_PIX_REPETITION, Pattern);			//TClkSel1:Ratio of output TMDS clock to input video clock,00-x0.5,01- x1 (default),10 -x2,11-x4
+
+	// Take values from VModesTable[]:
+	if( (siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) ||	//480i
+			(siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) )	//576i
+	{
+		if( siHdmiTx.ColorSpace == YCBCR422_8BITS)	//27Mhz pixel clock
+		{
+			B_Data[0] = VModesTable[ModeTblIndex].PixClk & 0x00FF;
+			B_Data[1] = (VModesTable[ModeTblIndex].PixClk >> 8) & 0xFF;
+		}
+		else											//13.5Mhz pixel clock
+		{
+			B_Data[0] = (VModesTable[ModeTblIndex].PixClk /2) & 0x00FF;
+			B_Data[1] = ((VModesTable[ModeTblIndex].PixClk /2) >> 8) & 0xFF;
+		}
+
+	}
+	else
+	{
+		B_Data[0] = VModesTable[ModeTblIndex].PixClk & 0x00FF;			// write Pixel clock to TPI registers 0x00, 0x01
+		B_Data[1] = (VModesTable[ModeTblIndex].PixClk >> 8) & 0xFF;
+	}
+
+	B_Data[2] = VModesTable[ModeTblIndex].Tag.VFreq & 0x00FF;		// write Vertical Frequency to TPI registers 0x02, 0x03
+	B_Data[3] = (VModesTable[ModeTblIndex].Tag.VFreq >> 8) & 0xFF;
+
+	if( (siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) ||	//480i
+			(siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) )	//576i
+	{
+		B_Data[4] = (VModesTable[ModeTblIndex].Tag.Total.Pixels /2) & 0x00FF;	// write total number of pixels to TPI registers 0x04, 0x05
+		B_Data[5] = ((VModesTable[ModeTblIndex].Tag.Total.Pixels /2) >> 8) & 0xFF;
+	}
+	else
+	{
+		B_Data[4] = VModesTable[ModeTblIndex].Tag.Total.Pixels & 0x00FF;	// write total number of pixels to TPI registers 0x04, 0x05
+		B_Data[5] = (VModesTable[ModeTblIndex].Tag.Total.Pixels >> 8) & 0xFF;
+	}
+
+	B_Data[6] = VModesTable[ModeTblIndex].Tag.Total.Lines & 0x00FF;	// write total number of lines to TPI registers 0x06, 0x07
+	B_Data[7] = (VModesTable[ModeTblIndex].Tag.Total.Lines >> 8) & 0xFF;
+
+	WriteBlockTPI(TPI_PIX_CLK_LSB, 8, B_Data);						// Write TPI Mode data.//0x00-0x07 :Video Mode Defines the incoming resolution
+
+	// TPI Input Bus and Pixel Repetition Data
+	// B_Data[0] = Reg0x08;
+	B_Data[0] = 0;  // Set to default 0 for use again
+	//B_Data[0] = (VModesTable[ModeTblIndex].PixRep) & LOW_BYTE;		// Set pixel replication field of 0x08
+	B_Data[0] |= BIT_BUS_24;										// Set 24 bit bus:Input Bus Select. The input data bus can be either one pixel wide or 1/2  pixel wide. The bit defaults to 1 to select full pixel mode. In  1/2  pixel mode, the full pixel is brought in on two successive clock edges (one rising, one falling). 
+	//All parts support 24-bit full-pixel and 12-bit half-pixel input modes.
+	B_Data[0] |= (TclkSel << 6) & TWO_MSBITS;
+
+#ifdef CLOCK_EDGE_FALLING
+	B_Data[0] &= ~BIT_EDGE_RISE;									// Set to falling edge
+#elif defined(CLOCK_EDGE_RISING)
+	B_Data[0] |= BIT_EDGE_RISE;									// Set to rising edge
+#endif
+
+	tpivmode[0] = B_Data[0]; // saved TPI Reg0x08 value.
+	WriteByteTPI(TPI_PIX_REPETITION, B_Data[0]);					// 0x08
+
+	// TPI AVI Input and Output Format Data
+	// B_Data[0] = Reg0x09;
+	// B_Data[1] = Reg0x0A;	
+	B_Data[0] = 0;  // Set to default 0 for use again
+	B_Data[1] = 0;  // Set to default 0 for use again
+
+	if (siHdmiTx.SyncMode == EMBEDDED_SYNC)
+	{
+		EMB_Status = SetEmbeddedSync();
+		EnableEmbeddedSync();    //enablle EmbeddedSync
+	}
+
+	if (siHdmiTx.SyncMode == INTERNAL_DE)
+	{
+		ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT);	// set 0x60[7] = 0 for External Sync
+		DE_Status = SetDE();								// Call SetDE() with Video Mode as a parameter
+	}
+
+	if (siHdmiTx.ColorSpace == RGB)
+		B_Data[0] = (((BITS_IN_RGB | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // reg0x09
+
+	else if (siHdmiTx.ColorSpace == YCBCR444)
+		B_Data[0] = (((BITS_IN_YCBCR444 | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // 0x09
+
+	else if ((siHdmiTx.ColorSpace == YCBCR422_16BITS) ||(siHdmiTx.ColorSpace == YCBCR422_8BITS))
+		B_Data[0] = (((BITS_IN_YCBCR422 | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // 0x09
+
+#ifdef DEEP_COLOR
+	switch (siHdmiTx.ColorDepth)
+	{
+		case 0:  temp = 0x00; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, 0x00); break;
+		case 1:  temp = 0x80; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break;
+		case 2:  temp = 0xC0; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break;
+		case 3:  temp = 0x40; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break;
+		default: temp = 0x00; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, 0x00); break;
+				 //General Control Packet �C Deep color settings require the General Control Packet to be sent once per video field
+				 //with the correct PP and CD information. This must be enabled by software via TPI Deep Color Packet Enable
+				 //Register 0x40[2] = 1, enable transmission of the GCP packet.
+	}
+	B_Data[0] = ((B_Data[0] & 0x3F) | temp);// reg0x09
+#endif
+
+	B_Data[1] = (BITS_OUT_RGB | BITS_OUT_AUTO_RANGE);  //Reg0x0A
+
+	if ((siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) ||	//480i
+			(siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) ||//576i
+			(siHdmiTx.VIC == 2) || (siHdmiTx.VIC == 3) ||	//480p
+			(siHdmiTx.VIC == 17) ||(siHdmiTx.VIC == 18))	//576p
+	{
+		B_Data[1] &= ~BIT_BT_709;
+	}
+	else
+	{
+		B_Data[1] |= BIT_BT_709;
+	}
+
+#ifdef DEEP_COLOR
+	B_Data[1] = ((B_Data[1] & 0x3F) | temp);
+#endif
+
+#ifdef DEV_SUPPORT_EDID
+	if (!IsHDMI_Sink()) 
+	{
+		B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_RGB);
+	}
+	else 
+	{
+		// Set YCbCr color space depending on EDID
+		if (g_edid.YCbCr_4_4_4) 
+		{
+			B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_YCBCR444);
+		}
+		else 
+		{
+			if (g_edid.YCbCr_4_2_2)
+			{
+				B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_YCBCR422);
+			}
+			else
+			{
+				B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_RGB);
+			}
+		}
+	}
+#endif
+
+	tpivmode[1] = B_Data[0];	// saved TPI Reg0x09 value.
+	tpivmode[2] = B_Data[1];  // saved TPI Reg0x0A value.
+	SetFormat(B_Data);
+
+	ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, BIT_2);	// Number HSync pulses from VSync active edge to Video Data Period should be 20 (VS_TO_VIDEO)
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: SetAVI_InfoFrames()
+// Function Description: Load AVI InfoFrame data into registers and send to sink
+//
+// Accepts: An API_Cmd parameter that holds the data to be sent in the InfoFrames
+// Returns: TRUE
+// Globals: none
+//
+// Note:          : Infoframe contents are from spec CEA-861-D
+//
+//------------------------------------------------------------------------------
+byte SetAVI_InfoFrames (void)
+{
+	byte B_Data[SIZE_AVI_INFOFRAME];
+	byte i;
+	byte TmpVal;
+	byte VModeTblIndex;
+
+	TPI_TRACE_PRINT((">>SetAVI_InfoFrames()\n"));
+
+	for (i = 0; i < SIZE_AVI_INFOFRAME; i++)
+		B_Data[i] = 0;
+
+#ifdef DEV_SUPPORT_EDID
+	if (g_edid.YCbCr_4_4_4)
+		TmpVal = 2;
+	else if (g_edid.YCbCr_4_2_2)
+		TmpVal = 1;
+	else
+		TmpVal = 0;
+#else
+	TmpVal = 0;
+#endif
+
+	B_Data[1] = (TmpVal << 5) & BITS_OUT_FORMAT;	// AVI Byte1: Y1Y0 (output format)
+	B_Data[1] |= 0x11;  // A0 = 1; Active format identification data is present in the AVI InfoFrame. // S1:S0 = 01; Overscanned (television).
+
+	if (siHdmiTx.ColorSpace == XVYCC444)                // Extended colorimetry - xvYCC
+	{
+		B_Data[2] = 0xC0;                                          // Extended colorimetry info (B_Data[3] valid (CEA-861D, Table 11)
+
+		if (siHdmiTx.Colorimetry == COLORIMETRY_601)   		// xvYCC601
+			B_Data[3] &= ~BITS_6_5_4;
+
+		else if (siHdmiTx.Colorimetry == COLORIMETRY_709)	// xvYCC709
+			B_Data[3] = (B_Data[3] & ~BITS_6_5_4) | BIT_4;
+	}
+
+	else if (siHdmiTx.Colorimetry == COLORIMETRY_709)		// BT.709
+		B_Data[2] = 0x80;		// AVI Byte2: C1C0
+
+	else if (siHdmiTx.Colorimetry == COLORIMETRY_601)		// BT.601
+		B_Data[2] = 0x40;		// AVI Byte2: C1C0
+
+	else													// Carries no data
+	{													// AVI Byte2: C1C0
+		B_Data[2] &= ~BITS_7_6;							// colorimetry = 0
+		B_Data[3] &= ~BITS_6_5_4;						// Extended colorimetry = 0
+	}
+
+	VModeTblIndex = ConvertVIC_To_VM_Index();
+
+	B_Data[4] = siHdmiTx.VIC;
+
+	//  Set the Aspect Ration info into the Infoframe Byte 2
+	if (siHdmiTx.AspectRatio == VMD_ASPECT_RATIO_16x9)
+	{
+		B_Data[2] |= _16_To_9;                          // AVI Byte2: M1M0
+		// If the Video Mode table says this mode can be 4x3 OR 16x9, and we are pointing to the
+		// table entry that is 4x3, then we bump to the next Video Table entry which will be for 16x9.
+		if ((VModesTable[VModeTblIndex].AspectRatio == R_4or16) && (AspectRatioTable[siHdmiTx.VIC - 1] == R_4))
+		{
+			siHdmiTx.VIC++;
+			B_Data[4]++;
+		}
+	}
+	else
+	{
+		B_Data[2] |= _4_To_3;                       // AVI Byte4: VIC
+	}
+
+	B_Data[2] |= SAME_AS_AR;                        // AVI Byte2: R3..R1 - Set to "Same as Picture Aspect Ratio"
+	B_Data[5] = VModesTable[VModeTblIndex].PixRep;      // AVI Byte5: Pixel Replication - PR3..PR0
+
+	// Calculate AVI InfoFrame ChecKsum
+	B_Data[0] = 0x82 + 0x02 +0x0D;
+	for (i = 1; i < SIZE_AVI_INFOFRAME; i++)
+	{
+		B_Data[0] += B_Data[i];
+	}
+	B_Data[0] = 0x100 - B_Data[0];
+
+	// Write the Inforframe data to the TPI Infoframe registers
+	WriteBlockTPI(TPI_AVI_BYTE_0, SIZE_AVI_INFOFRAME, B_Data);
+
+	if (siHdmiTx.SyncMode == EMBEDDED_SYNC)
+		EnableEmbeddedSync();
+
+	return TRUE;
+}
+
+extern void siHdmiTx_PowerStateD0 (void);
+extern void SetAudioMute (byte audioMute);
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_Init()
+// Function Description: Set the 9022/4 video and video.
+//
+// Accepts: none
+// Returns: none
+// Globals: siHdmiTx
+//------------------------------------------------------------------------------
+void siHdmiTx_Init (void) 
+{
+	TPI_TRACE_PRINT((">>siHdmiTx_Init()\n"));
+
+	// workaround for Bug#18128
+	if (siHdmiTx.ColorDepth == VMD_COLOR_DEPTH_8BIT)
+	{
+		// Yes it is, so force 16bpps first!
+		siHdmiTx.ColorDepth = VMD_COLOR_DEPTH_16BIT;
+		InitVideo(siHdmiTx.TclkSel);
+		// Now put it back to 8bit and go do the expected InitVideo() call
+		siHdmiTx.ColorDepth = VMD_COLOR_DEPTH_8BIT;
+	}
+	// end workaround
+
+	InitVideo(siHdmiTx.TclkSel);			// Set PLL Multiplier to x1 upon power up
+
+	siHdmiTx_PowerStateD0();
+
+	if (IsHDMI_Sink())					// Set InfoFrames only if HDMI output mode
+	{
+		SetAVI_InfoFrames();
+		siHdmiTx_AudioSet();			// set audio interface to basic audio (an external command is needed to set to any other mode
+	}
+	else
+	{
+		SetAudioMute(AUDIO_MUTE_MUTED);
+	}
+
+	// THIS PATCH IS NEEDED BECAUSE SETTING UP AVI InfoFrames CLEARS 0x63 and 0x60[5]
+	if (siHdmiTx.ColorSpace == YCBCR422_8BITS)
+		ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, BIT_5);       // Set 0x60[5] according to input color space.
+
+	// THIS PATCH IS NEEDED BECAUSE SETTING UP AVI InfoFrames CLEARS 0x63
+	TPI_REG0x63_SAVED = 0x30;
+	printk("set 0x63 to %02x\n",TPI_REG0x63_SAVED);
+	WriteByteTPI(TPI_DE_CTRL, TPI_REG0x63_SAVED);
+
+	//==========================================================
+	WriteByteTPI(TPI_YC_Input_Mode, 0x00);
+
+
+	if ((g_hdcp.HDCP_TxSupports == TRUE) && (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED)&&(Sii9024A_HDCP_supported))
+	{
+		if (g_hdcp.HDCP_AksvValid == TRUE)
+		{
+			// AV MUTE
+			TPI_DEBUG_PRINT (("TMDS -> Enabled (Video Muted)\n"));
+			ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, LINK_INTEGRITY_MODE_MASK | TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK,
+					LINK_INTEGRITY_DYNAMIC | TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_MUTED);
+
+			WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]);      		// Write register 0x08
+			g_sys.tmdsPoweredUp = TRUE;
+			EnableInterrupts(HOT_PLUG_EVENT | RX_SENSE_EVENT | AUDIO_ERROR_EVENT | SECURITY_CHANGE_EVENT | HDCP_CHANGE_EVENT);
+		}
+	}
+	else{
+		TPI_DEBUG_PRINT (("TMDS -> Enabled\n"));
+		ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, LINK_INTEGRITY_MODE_MASK | TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, 
+				LINK_INTEGRITY_DYNAMIC | TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_NORMAL);
+
+		WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]);      		// Write register 0x08
+		g_sys.tmdsPoweredUp = TRUE;
+		EnableInterrupts(HOT_PLUG_EVENT | RX_SENSE_EVENT );//| AUDIO_ERROR_EVENT);
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_VideoSet()
+// Function Description: Set the 9022/4 video resolution
+//
+// Accepts: none
+// Returns: Success message if video resolution changed successfully.
+//                  Error Code if resolution change failed
+// Globals: siHdmiTx
+//------------------------------------------------------------------------------
+
+byte siHdmiTx_VideoSet (void)   
+{
+	TPI_TRACE_PRINT((">>siHdmiTx_VideoSet()\n"));
+	// Note: this's necessary for fixing 480i_13.5MHz to 1080p_148.5MHz no display issue.
+	siHdmiTx_TPI_Init();
+	g_sys.hdmiCableConnected = TRUE;
+	g_sys.dsRxPoweredUp = TRUE;
+	siHdmiTx_Init();
+	if (Sii9024A_HDCP_supported)
+		HDCP_CheckStatus( ReadByteTPI(TPI_INTERRUPT_STATUS_REG) );
+
+	return VIDEO_MODE_SET_OK;
+}
+
+
+byte SetAudioInfoFrames(byte ChannelCount,byte CodingType,byte ss,byte Fs, byte SpeakerConfig)
+{
+	byte B_Data[SIZE_AUDIO_INFOFRAME];
+	byte i;
+
+	TPI_TRACE_PRINT((">>SetAudioInfoFrames()\n"));
+
+	for (i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
+		B_Data[i] = 0;
+
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_AUDIO); 
+
+	B_Data[0] = TYPE_AUDIO_INFOFRAMES;
+	B_Data[1] = AUDIO_INFOFRAMES_VERSION;
+	B_Data[2] = AUDIO_INFOFRAMES_LENGTH;
+	B_Data[3] = TYPE_AUDIO_INFOFRAMES + AUDIO_INFOFRAMES_VERSION + AUDIO_INFOFRAMES_LENGTH;
+
+	B_Data[4] = ChannelCount;
+	B_Data[4] |= (CodingType << 4);
+	B_Data[5] = ((Fs & THREE_LSBITS) << 2) | (ss & TWO_LSBITS);
+	B_Data[7] = SpeakerConfig;
+
+	for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
+		B_Data[3] += B_Data[i];
+
+	B_Data[3] = 0x100 - B_Data[3];
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_AUDIO);
+	WriteBlockTPI(MISC_INFO_FRAMES_TYPE, SIZE_AUDIO_INFOFRAME, B_Data);
+	if (siHdmiTx.SyncMode == EMBEDDED_SYNC)
+		EnableEmbeddedSync();
+
+	return TRUE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: SetAudioMute()
+// Function Description: Mute audio
+//
+// Accepts: Mute or unmute.
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void SetAudioMute (byte audioMute)
+{
+	ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_MUTE_MASK, audioMute);
+}
+
+#ifndef F_9022A_9334
+//------------------------------------------------------------------------------
+// Function Name: SetChannelLayout()
+// Function Description: Set up the Channel layout field of internal register 0x2F (0x2F[1])
+//
+// Accepts: Number of audio channels: "0 for 2-Channels ."1" for 8.
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void SetChannelLayout (byte Count)
+{
+	// Indexed register 0x7A:0x2F[1]:
+	WriteByteTPI(TPI_INTERNAL_PAGE_REG, 0x02); // Internal page 2
+	WriteByteTPI(TPI_INDEXED_OFFSET_REG, 0x2F);
+
+	Count &= THREE_LSBITS;
+
+	if (Count == TWO_CHANNEL_LAYOUT)
+	{
+		// Clear 0x2F[1]:
+		ReadClearWriteTPI(TPI_INDEXED_VALUE_REG, BIT_1);
+	}
+
+	else if (Count == EIGHT_CHANNEL_LAYOUT)
+	{
+		// Set 0x2F[1]:
+		ReadSetWriteTPI(TPI_INDEXED_VALUE_REG, BIT_1);
+	}
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_AudioSet()
+// Function Description: Set the 9022/4 audio interface to basic audio.
+//
+// Accepts: none
+// Returns: Success message if audio changed successfully.
+//                  Error Code if resolution change failed
+// Globals: siHdmiTx
+//------------------------------------------------------------------------------
+byte siHdmiTx_AudioSet (void)
+{
+	TPI_TRACE_PRINT((">>siHdmiTx_AudioSet()\n"));
+
+	SetAudioMute(AUDIO_MUTE_MUTED);  // mute output
+
+	if (siHdmiTx.AudioMode == AMODE_I2S)  	// I2S input
+	{
+		ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_SEL_MASK, AUD_IF_I2S);	// 0x26 = 0x80
+		WriteByteTPI(TPI_AUDIO_HANDLING, 0x08 | AUD_DO_NOT_CHECK);	  // 0x25
+	}
+	else									// SPDIF input
+	{
+		ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_SEL_MASK, AUD_IF_SPDIF);	// 0x26 = 0x40
+		WriteByteTPI(TPI_AUDIO_HANDLING, AUD_PASS_BASIC);                   // 0x25 = 0x00
+	}
+
+#ifndef F_9022A_9334
+	if (siHdmiTx.AudioChannels == ACHANNEL_2CH)
+		SetChannelLayout(TWO_CHANNELS);             // Always 2 channesl in S/PDIF
+	else
+		SetChannelLayout(EIGHT_CHANNELS);
+#else
+	if (siHdmiTx.AudioChannels == ACHANNEL_2CH)
+		ReadClearWriteTPI(TPI_AUDIO_INTERFACE_REG, BIT_5); // Use TPI 0x26[5] for 9022A/24A and 9334 channel layout
+	else
+		ReadSetWriteTPI(TPI_AUDIO_INTERFACE_REG, BIT_5); // Use TPI 0x26[5] for 9022A/24A and 9334 channel layout
+#endif
+
+	if (siHdmiTx.AudioMode == AMODE_I2S)  	// I2S input
+	{
+		// I2S - Map channels - replace with call to API MAPI2S
+		WriteByteTPI(TPI_I2S_EN, 0x80); // 0x1F
+
+		if (siHdmiTx.AudioChannels > ACHANNEL_2CH)
+			WriteByteTPI(TPI_I2S_EN, 0x91);
+
+		if (siHdmiTx.AudioChannels > ACHANNEL_4CH)
+			WriteByteTPI(TPI_I2S_EN, 0xA2);
+
+		if (siHdmiTx.AudioChannels > ACHANNEL_6CH)
+			WriteByteTPI(TPI_I2S_EN, 0xB3);
+
+		// I2S - Stream Header Settings - replace with call to API SetI2S_StreamHeader
+		WriteByteTPI(TPI_I2S_CHST_0, 0x00); // 0x21
+		WriteByteTPI(TPI_I2S_CHST_1, 0x00);
+		WriteByteTPI(TPI_I2S_CHST_2, 0x00);
+		WriteByteTPI(TPI_I2S_CHST_3, siHdmiTx.AudioFs);
+		WriteByteTPI(TPI_I2S_CHST_4, (siHdmiTx.AudioFs << 4) |siHdmiTx.AudioWordLength);
+
+		// Oscar 20100929 added for 16bit auido noise issue
+		WriteIndexedRegister(INDEXED_PAGE_1, AUDIO_INPUT_LENGTH, siHdmiTx.AudioWordLength);
+
+		// I2S - Input Configuration
+		WriteByteTPI(TPI_I2S_IN_CFG, siHdmiTx.AudioI2SFormat); //TPI_Reg0x20
+	}
+
+	WriteByteTPI(TPI_AUDIO_SAMPLE_CTRL, REFER_TO_STREAM_HDR);
+	SetAudioInfoFrames(siHdmiTx.AudioChannels & THREE_LSBITS, REFER_TO_STREAM_HDR, REFER_TO_STREAM_HDR, REFER_TO_STREAM_HDR, 0x00); 	
+
+	SetAudioMute(AUDIO_MUTE_NORMAL);  // unmute output
+
+	return AUDIO_MODE_SET_OK;
+}
+
+#ifdef F_9022A_9334
+//------------------------------------------------------------------------------
+// Function Name: SetGBD_InfoFrame()
+// Function Description: Sets and sends the the 9022A/4A GBD InfoFrames.
+//
+// Accepts: none
+// Returns: Success message if GBD packet set successfully. Error
+//                  Code if failed
+// Globals: none
+// NOTE: Currently this function is a place holder. It always returns a Success message
+//------------------------------------------------------------------------------
+byte SetGBD_InfoFrame (void)
+{
+	byte CheckSum;
+
+	TPI_TRACE_PRINT((">>SetGBD_InfoFrame()\n"));
+
+	// Set MPEG InfoFrame Header to GBD InfoFrame Header values:
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_MPEG);                    	// 0xBF = Use MPEG      InfoFrame for GBD - 0x03
+	WriteByteTPI(MISC_INFO_FRAMES_TYPE, TYPE_GBD_INFOFRAME);                        	// 0xC0 = 0x0A
+	WriteByteTPI(MISC_INFO_FRAMES_VER, NEXT_FIELD | GBD_PROFILE | AFFECTED_GAMUT_SEQ_NUM);   // 0x0C1 = 0x81
+	WriteByteTPI(MISC_INFO_FRAMES_LEN, ONLY_PACKET | CURRENT_GAMUT_SEQ_NUM);                         // 0x0C2 = 0x31
+
+	CheckSum = TYPE_GBD_INFOFRAME +
+		NEXT_FIELD +
+		GBD_PROFILE +
+		AFFECTED_GAMUT_SEQ_NUM +
+		ONLY_PACKET +
+		CURRENT_GAMUT_SEQ_NUM;
+
+	CheckSum = 0x100 - CheckSum;
+
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_MPEG);  // Enable and Repeat MPEG InfoFrames
+	WriteByteTPI(MISC_INFO_FRAMES_CHKSUM, CheckSum);                        // 0X00 - Send header only
+
+	return GBD_SET_SUCCESSFULLY;
+}
+#endif
+
+#ifdef DEV_SUPPORT_3D
+//------------------------------------------------------------------------------
+// Function Name: Set_VSIF()
+// Function Description: Construct Vendor Specific InfoFrame for 3D support. use MPEG InfoFrame
+//
+// Accepts: none
+// Returns: none
+// Globals: siHdmiTx
+//------------------------------------------------------------------------------
+// VSIF Constants
+//============================================================
+#define VSIF_TYPE  			0x81
+#define VSIF_VERSION		0x01
+#define VSIF_LEN				0x06
+
+void Set_VSIF (void)
+{
+	byte i;
+	byte Data[SIZE_MPEG_INFOFRAME];		//10
+
+	for (i = 0; i < SIZE_MPEG_INFOFRAME; i++)	
+	{        
+		Data[i] = 0;
+	}
+
+	// Disable transmission of VSIF during re-configuration
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_MPEG);          
+
+	// Header Bytes
+	Data[0] = VSIF_TYPE;            // HB0 Packet Type 0x81
+	Data[1] = VSIF_VERSION; 		// HB1 Version = 0x01
+
+	// PB1 - PB3 contain the 24bit IEEE Registration Identifier
+	Data[4] = 0x03;                     // HDMI Signature LS Byte
+	Data[5] = 0x0C;                     // HDMI Signature middle byte
+	Data[6] = 0x00;                     // HDMI Signature MS Byte
+
+	// PB4 - HDMI_Video_Format into bits 7:5
+	Data[7] = siHdmiTx.HDMIVideoFormat << 5;
+
+	// PB5 - Depending on the video format, this byte will contain either the HDMI_VIC
+	// code in buts 7:0, OR the 3D_Structure in bits 7:4.
+	switch(siHdmiTx.HDMIVideoFormat)
+	{
+		case VMD_HDMIFORMAT_HDMI_VIC:
+			// This is a 2x4K mode, set the HDMI_VIC in buts 7:0.  Values
+			// are from HDMI 1.4 Spec, 8.2.3.1 (Table 8-13).
+			Data[8] = siHdmiTx.VIC;
+			Data[9] = 0;
+			break;
+
+		case VMD_HDMIFORMAT_3D:
+			// This is a 3D mode, set the 3D_Structure in buts 7:4
+			// Bits 3:0 are reseved so set to 0.  Values are from HDMI 1.4
+			// Spec, Appendix H (Table H-2).
+			Data[8] = siHdmiTx.ThreeDStructure << 4;
+			// Add the Extended data field when the 3D format is Side-by-Side(Half).
+			// See Spec Table H-3 for details.			
+			if ((Data[8] >> 4) == VMD_3D_SIDEBYSIDEHALF)
+			{
+				Data[2] = VSIF_LEN;
+				Data[9] = siHdmiTx.ThreeDExtData << 4;;	
+			}
+			else 
+			{
+				Data[2] = VSIF_LEN-1;
+			}
+			break;
+
+		case VMD_HDMIFORMAT_CEA_VIC:
+		default:
+			Data[8] = 0;
+			Data[9] = 0;
+			break;
+	}
+
+	// Packet Bytes
+	Data[3] = VSIF_TYPE+                // PB0 partial checksum
+		VSIF_VERSION+
+		Data[2];
+
+	// Complete the checksum with PB1 through PB7
+	for (i = 4; i < SIZE_MPEG_INFOFRAME; i++)
+	{
+		Data[3] += Data[i];
+	}
+	// Data[3] %= 0x100;
+	Data[3] = 0x100 - Data[3];            // Final checksum
+
+	WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_MPEG);         // Enable and Repeat MPEG/Vendor Specific InfoFrames
+
+	WriteBlockTPI(MISC_INFO_FRAMES_TYPE, SIZE_MPEG_INFOFRAME, Data);             // Write VSIF to MPEG registers and start transmission
+	WriteByteTPI(0xDE, 0x00);		// Set last byte of MPEG InfoFrame for data to be sent to sink.
+}
+#endif
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////                  TPI                     ///////////////////////////////
+///////////////////////*************************///////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+
+//------------------------------------------------------------------------------
+// Function Name: StartTPI()
+// Function Description: Start HW TPI mode by writing 0x00 to TPI address 0xC7.
+//
+// Accepts: none
+// Returns: TRUE if HW TPI started successfully. FALSE if failed to.
+// Globals: none
+//------------------------------------------------------------------------------
+byte StartTPI (void)
+{
+	byte devID = 0x00;
+	word wID = 0x0000;	
+
+	TPI_TRACE_PRINT((">>StartTPI()\n"));
+
+	WriteByteTPI(TPI_ENABLE, 0x00);            // Write "0" to 72:C7 to start HW TPI mode
+
+	DelayMS(100);
+
+	devID = ReadIndexedRegister(INDEXED_PAGE_0, 0x03);
+	wID = devID;
+	wID <<= 8;
+	devID = ReadIndexedRegister(INDEXED_PAGE_0, 0x02);
+	wID |= devID;
+
+	devID = ReadByteTPI(TPI_DEVICE_ID);
+
+	TPI_TRACE_PRINT(("0x%04X\n", (int)wID));
+	TPI_TRACE_PRINT(("%s:%d:devID=0x%04x \n", __func__,__LINE__,devID));
+
+	if (wID == 0x9022)
+		Sii9024A_HDCP_supported = false;
+	if (devID == SII902XA_DEVICE_ID)
+		return TRUE;
+
+	TPI_TRACE_PRINT(("Unsupported TX, devID = 0x%X\n", (int)devID));
+	return FALSE;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_TPI_Init()
+// Function Description: TPI initialization: HW Reset, Interrupt enable.
+//
+// Accepts: none
+// Returns: TRUE or FLASE
+// Globals: none
+//------------------------------------------------------------------------------
+byte siHdmiTx_TPI_Init (void)
+{
+	TPI_TRACE_PRINT(("\n>>siHdmiTx_TPI_Init()\n"));
+	TPI_TRACE_PRINT(("\n%s\n", TPI_FW_VERSION));
+
+	// Chip powers up in D2 mode.
+	g_sys.txPowerState = TX_POWER_STATE_D0;
+
+	InitializeStateVariables();
+
+	// Toggle TX reset pin
+	//TxHW_Reset();							
+	WriteByteTPI(0xF5, 0x00);	
+	// Enable HW TPI mode, check device ID
+	if (StartTPI())
+	{
+		if (Sii9024A_HDCP_supported){
+			g_hdcp.HDCP_Override = FALSE;
+			g_hdcp.HDCPAuthenticated = VMD_HDCP_AUTHENTICATED;
+			HDCP_Init();
+		}
+
+#ifdef DEV_SUPPORT_CEC
+		//SI_CecInit();
+#endif
+
+		EnableInterrupts(HOT_PLUG_EVENT);
+
+		return 0;
+	}
+
+	return EPERM;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: OnDownstreamRxPoweredDown()
+// Function Description: HDMI cable unplug handle.
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void OnDownstreamRxPoweredDown (void)
+{
+	TPI_DEBUG_PRINT (("DSRX -> Powered Down\n"));
+	g_sys.dsRxPoweredUp = FALSE;
+
+	if (g_hdcp.HDCP_Started == TRUE && Sii9024A_HDCP_supported)
+		HDCP_Off();
+	DisableTMDS();
+	ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK,OUTPUT_MODE_DVI);	// Set to DVI output mode to reset HDCP
+}
+
+extern void HotPlugService(void);
+//------------------------------------------------------------------------------
+// Function Name: OnDownstreamRxPoweredUp()
+// Function Description: DSRX power up handle.
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void OnDownstreamRxPoweredUp (void)
+{
+	TPI_DEBUG_PRINT (("DSRX -> Powered Up\n"));
+	g_sys.dsRxPoweredUp = TRUE;
+
+	HotPlugService();
+}
+
+//------------------------------------------------------------------------------
+// Function Name: OnHdmiCableDisconnected()
+// Function Description: HDMI cable unplug handle.
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void OnHdmiCableDisconnected (void)
+{
+	TPI_DEBUG_PRINT (("HDMI Disconnected\n"));
+
+	g_sys.hdmiCableConnected = FALSE;
+
+#ifdef DEV_SUPPORT_EDID
+	g_edid.edidDataValid = FALSE;
+#endif
+
+	OnDownstreamRxPoweredDown();
+}
+
+//------------------------------------------------------------------------------
+// Function Name: OnHdmiCableConnected()
+// Function Description: HDMI cable plug in handle.
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void OnHdmiCableConnected (void)
+{
+	TPI_DEBUG_PRINT (("Cable Connected\n"));
+	// No need to call TPI_Init here unless TX has been powered down on cable removal.
+	//TPI_Init();
+
+	g_sys.hdmiCableConnected = TRUE;
+
+	if ((Sii9024A_HDCP_supported) 
+			&& (g_hdcp.HDCP_TxSupports == TRUE) 
+			&& (g_hdcp.HDCP_AksvValid == TRUE) 
+			&& (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED)) 
+	{
+		WriteIndexedRegister(INDEXED_PAGE_0, 0xCE, 0x00); // Clear BStatus
+		WriteIndexedRegister(INDEXED_PAGE_0, 0xCF, 0x00);
+	}
+
+
+	// Added for EDID read for Michael Wang recommaned by oscar 20100908
+	//siHdmiTx_PowerStateD0();
+	//ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_MUTED);
+
+#ifdef DEV_SUPPORT_EDID
+	DoEdidRead();
+#endif
+
+#ifdef READKSV
+	ReadModifyWriteTPI(0xBB, 0x08, 0x08);
+#endif
+
+	if (IsHDMI_Sink())              // select output mode (HDMI/DVI) according to sink capabilty
+	{
+		TPI_DEBUG_PRINT (("HDMI Sink Detected\n"));
+		ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_HDMI);
+	}
+	else
+	{
+		TPI_DEBUG_PRINT (("DVI Sink Detected\n"));
+		ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_DVI);
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_PowerStateD0()
+// Function Description: Set TX to D0 mode.
+//------------------------------------------------------------------------------
+void siHdmiTx_PowerStateD0 (void)
+{
+	ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D0);
+	TPI_DEBUG_PRINT(("TX Power State D0\n"));
+	g_sys.txPowerState = TX_POWER_STATE_D0;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_PowerStateD2()
+// Function Description: Set TX to D2 mode.
+//------------------------------------------------------------------------------
+void siHdmiTx_PowerStateD2 (void)
+{
+	ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D2);
+	TPI_DEBUG_PRINT(("TX Power State D2\n"));
+	g_sys.txPowerState = TX_POWER_STATE_D2;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_PowerStateD0fromD2()
+// Function Description: Set TX to D0 mode from D2 mode.
+//------------------------------------------------------------------------------
+void siHdmiTx_PowerStateD0fromD2 (void)
+{
+	ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D0);
+
+	if (Sii9024A_HDCP_supported)
+		RestartHDCP();
+	else
+		EnableTMDS();
+
+	TPI_DEBUG_PRINT(("TX Power State D0 from D2\n"));
+	g_sys.txPowerState = TX_POWER_STATE_D0;
+}
+
+//------------------------------------------------------------------------------
+// Function Name: HotPlugService()
+// Function Description: Implement Hot Plug Service Loop activities
+//
+// Accepts: none
+// Returns: An error code that indicates success or cause of failure
+// Globals: LinkProtectionLevel
+//------------------------------------------------------------------------------
+void HotPlugService (void)
+{
+	TPI_TRACE_PRINT((">>HotPlugService()\n"));
+
+	DisableInterrupts(0xFF);
+
+	//siHdmiTx.VIC = g_edid.VideoDescriptor[0];	// use 1st mode supported by sink
+
+	siHdmiTx_Init();
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_TPI_Poll()
+// Function Description: Poll Interrupt Status register for new interrupts
+//
+// Accepts: none
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+
+void siHdmiTx_TPI_Poll (void)
+{
+	byte InterruptStatus;
+
+	if (g_sys.txPowerState == TX_POWER_STATE_D0)
+	{
+		InterruptStatus = ReadByteTPI(TPI_INTERRUPT_STATUS_REG);
+
+		if (InterruptStatus & HOT_PLUG_EVENT)		  //judge if HPD is connected
+		{
+			TPI_DEBUG_PRINT (("HPD	-> "));
+			ReadSetWriteTPI(TPI_INTERRUPT_ENABLE_REG, HOT_PLUG_EVENT);	// Enable HPD interrupt bit
+
+			// Repeat this loop while cable is bouncing:
+			do
+			{
+				WriteByteTPI(TPI_INTERRUPT_STATUS_REG, HOT_PLUG_EVENT);   //Write 1 to interrupt bits to clear the 'pending' status.
+				DelayMS(T_HPD_DELAY); // Delay for metastability protection and to help filter out connection bouncing
+				InterruptStatus = ReadByteTPI(TPI_INTERRUPT_STATUS_REG);	// Read Interrupt status register
+			} while (InterruptStatus & HOT_PLUG_EVENT); 			 // loop as long as HP interrupts recur
+
+			if (((InterruptStatus & HOT_PLUG_STATE) >> 2) != g_sys.hdmiCableConnected)
+			{
+				if (g_sys.hdmiCableConnected == TRUE)
+				{
+					OnHdmiCableDisconnected();
+				}
+				else
+				{
+					OnHdmiCableConnected();
+					ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x0A, 0x08, 0x08);
+				}
+
+				if (g_sys.hdmiCableConnected == FALSE)
+				{
+					return;
+				}
+			}
+		}
+
+		// Check rx power
+		if (((InterruptStatus & RX_SENSE_STATE) >> 3) != g_sys.dsRxPoweredUp)
+		{
+			if (g_sys.hdmiCableConnected == TRUE)
+			{
+				if (g_sys.dsRxPoweredUp == TRUE)
+				{
+					OnDownstreamRxPoweredDown();
+				}
+				else
+				{
+					OnDownstreamRxPoweredUp();
+				}
+			}
+			DelayMS(100); // Delay for metastability protection and to help filter out connection bouncing
+			ClearInterrupt(RX_SENSE_EVENT);
+		}
+
+		// Check if Audio Error event has occurred:
+		if (InterruptStatus & AUDIO_ERROR_EVENT)
+		{
+			//TPI_DEBUG_PRINT (("TP -> Audio Error Event\n"));
+			//	The hardware handles the event without need for host intervention (PR, p. 31)
+			ClearInterrupt(AUDIO_ERROR_EVENT);
+		}
+
+		if ((Sii9024A_HDCP_supported)
+				&& (g_sys.hdmiCableConnected == TRUE)
+				&& (g_sys.dsRxPoweredUp == TRUE)
+				&& (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED))
+		{
+			HDCP_CheckStatus(InterruptStatus);
+		}
+
+#ifdef DEV_SUPPORT_CEC
+		//SI_CecHandler(0 , 0);
+#endif
+	}
+
+}
+
+void siHdmiTx_VideoSel (byte vmode)
+{
+	siHdmiTx.HDMIVideoFormat 	= VMD_HDMIFORMAT_CEA_VIC;
+	siHdmiTx.ColorSpace 		= RGB;
+	siHdmiTx.ColorDepth			= VMD_COLOR_DEPTH_8BIT;
+	siHdmiTx.SyncMode 			= EXTERNAL_HSVSDE;
+//	siHdmiTx.SyncMode 			= 1;
+
+	switch (vmode)
+	{
+		case HDMI_480I60_4X3:
+			siHdmiTx.VIC 		= 6;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_601;
+			siHdmiTx.TclkSel		= X2;
+			break;
+
+		case HDMI_576I50_4X3:
+			siHdmiTx.VIC 		= 21;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_601;
+			siHdmiTx.TclkSel		= X2;
+			break;
+
+		case HDMI_480P60_4X3:
+			siHdmiTx.VIC 		= 2;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_601;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_576P50_4X3:
+			siHdmiTx.VIC 		= 17;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_601;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_720P60:
+			siHdmiTx.VIC 		= 4;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_720P50:
+			siHdmiTx.VIC 		= 19;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_1080I60:
+			siHdmiTx.VIC 		= 5;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_1080I50:
+			siHdmiTx.VIC 		= 20;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_1080P60:
+			siHdmiTx.VIC 		= 16;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_1080P50:
+			siHdmiTx.VIC 		= 31;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_16x9;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+
+		case HDMI_1024_768_60:
+			siHdmiTx.VIC 		= PC_BASE+13;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+		case HDMI_800_600_60:
+			siHdmiTx.VIC 		= PC_BASE+9;
+			siHdmiTx.AspectRatio 	= VMD_ASPECT_RATIO_4x3;
+			siHdmiTx.Colorimetry	= COLORIMETRY_709;
+			siHdmiTx.TclkSel		= X1;
+			break;
+		default:
+			break;
+	}
+}
+
+//------------------------------------------------------------------------------
+// Function Name: siHdmiTx_AudioSel()
+// Function Description: Select output audio mode
+//
+// Accepts: Audio Fs
+// Returns: none
+// Globals: none
+//------------------------------------------------------------------------------
+void siHdmiTx_AudioSel (byte Afs)
+{
+	siHdmiTx.AudioMode			= AMODE_I2S;
+	siHdmiTx.AudioChannels		= ACHANNEL_2CH;
+	siHdmiTx.AudioFs				= Afs;
+	siHdmiTx.AudioWordLength		= ALENGTH_16BITS;
+	siHdmiTx.AudioI2SFormat		= (MCLK256FS << 4) |SCK_SAMPLE_RISING_EDGE |0x00; //last num 0x00-->0x02
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.h b/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.h
new file mode 100644
index 000000000000..662c904ad123
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/siHdmiTx_902x_TPI.h
@@ -0,0 +1,1128 @@
+/***************************************************************************
+*
+* SIMG PART NUMBER -HDMI Transmitter Driver
+*
+* Copyright (C) (2011, Silicon Image)
+*
+* 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 version 2.
+*
+* This program is distributed "as is" WITHOUT ANY WARRANTY of any
+* kind, whether express or implied; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*****************************************************************************/
+
+
+#ifndef _SIHDMITX_902X_TPI_H_
+#define _SIHDMITX_902X_TPI_H_
+
+/* smi added */
+#define SII9022A_I2C_ADDRESS                  0x72
+#ifdef USE_HW_I2C
+#define i2cWriteReg hwI2CWriteReg
+#define i2cReadReg  hwI2CReadReg
+#else
+#define i2cWriteReg swI2CWriteReg
+#define i2cReadReg  swI2CReadReg
+#endif
+
+//--------------------------------------------------------------------
+// typedef
+//--------------------------------------------------------------------
+
+typedef unsigned char		byte;
+typedef unsigned short		word;
+typedef unsigned int		dword;
+
+//--------------------------------------------------------------------
+// System Macro definition
+//--------------------------------------------------------------------
+#define IIC_OK 0
+
+
+#define DEV_SUPPORT_EDID  0
+//#define DEV_SUPPORT_HDCP
+//#define DEV_SUPPORT_CEC
+//#define DEV_SUPPORT_3D
+
+#define CLOCK_EDGE_RISING
+//#define CLOCK_EDGE_FALLING
+
+#define F_9022A_9334
+//#define HW_INT_ENABLE
+
+
+
+//--------------------------------------------------------------------
+// TPI Firmware Version
+//--------------------------------------------------------------------
+static const char TPI_FW_VERSION[] = "TPI Firmware v6.6.3_APP v1.3";
+
+// Generic Constants
+//====================================================
+#define OFF                    0
+#define ON                      1
+
+#define LOW                   0
+#define HIGH                  1
+
+#define DISABLE 	0x00
+#define ENABLE  	0xFF
+
+
+#define MAX_V_DESCRIPTORS				20
+#define MAX_A_DESCRIPTORS				10
+#define MAX_SPEAKER_CONFIGURATIONS	4
+#define AUDIO_DESCR_SIZE			 	3
+
+#define RGB					0
+#define YCBCR444			1
+#define YCBCR422_16BITS		2
+#define YCBCR422_8BITS		3
+#define XVYCC444			4
+
+#define EXTERNAL_HSVSDE	0
+#define INTERNAL_DE			1
+#define EMBEDDED_SYNC		2
+
+#define COLORIMETRY_601	0
+#define COLORIMETRY_709	1
+
+//====================================================
+#define MCLK128FS 			0
+#define MCLK256FS 			1
+#define MCLK384FS 			2
+#define MCLK512FS 			3
+#define MCLK768FS 			4
+#define MCLK1024FS 			5
+#define MCLK1152FS 			6
+#define MCLK192FS 			7
+
+#define SCK_SAMPLE_FALLING_EDGE 	0x00
+#define SCK_SAMPLE_RISING_EDGE 	0x80
+
+//====================================================
+// Video mode define
+#define HDMI_480I60_4X3	1
+#define HDMI_576I50_4X3	2
+#define HDMI_480P60_4X3	3
+#define HDMI_576P50_4X3	4
+#define HDMI_720P60			5
+#define HDMI_720P50			6
+#define HDMI_1080I60		7
+#define HDMI_1080I50		8
+#define HDMI_1080P60		9
+#define HDMI_1080P50		10
+#define HDMI_1024_768_60	11
+#define HDMI_800_600_60		12
+
+
+
+
+
+//====================================================
+#define AMODE_I2S 			0
+#define AMODE_SPDIF 		1
+#define AMODE_HBR 			2
+#define AMODE_DSD 			3
+
+#define ACHANNEL_2CH		1
+#define ACHANNEL_3CH 		2
+#define ACHANNEL_4CH 		3
+#define ACHANNEL_5CH 		4
+#define ACHANNEL_6CH 		5
+#define ACHANNEL_7CH 		6
+#define ACHANNEL_8CH 		7
+
+#define AFS_44K1			0x00
+#define AFS_48K				0x02
+#define AFS_32K				0x03
+#define AFS_88K2			0x08
+#define AFS_768K			0x09
+#define AFS_96K				0x0a
+#define AFS_176K4			0x0c
+#define AFS_192K			0x0e
+
+#define ALENGTH_16BITS		0x02
+#define ALENGTH_17BITS		0x0c
+#define ALENGTH_18BITS		0x04
+#define ALENGTH_19BITS		0x08
+#define ALENGTH_20BITS		0x0a
+#define ALENGTH_21BITS		0x0d
+#define ALENGTH_22BITS		0x05
+#define ALENGTH_23BITS		0x09
+#define ALENGTH_24BITS		0x0b
+
+//====================================================
+typedef struct
+{
+    	byte HDMIVideoFormat;	// 0 = CEA-861 VIC; 1 = HDMI_VIC; 2 = 3D
+    	byte VIC;				// VIC or the HDMI_VIC
+    	byte AspectRatio;		// 4x3 or 16x9
+    	byte ColorSpace;		// 0 = RGB; 1 = YCbCr4:4:4; 2 = YCbCr4:2:2_16bits; 3 = YCbCr4:2:2_8bits; 4 = xvYCC4:4:4
+    	byte ColorDepth;		// 0 = 8bits; 1 = 10bits; 2 = 12bits
+    	byte Colorimetry;		// 0 = 601; 1 = 709
+		byte SyncMode;			// 0 = external HS/VS/DE; 1 = external HS/VS and internal DE; 2 = embedded sync  
+		byte TclkSel;			// 0 = x0.5CLK; 1 = x1CLK; 2 = x2CLK; 3 = x4CLK
+    	byte ThreeDStructure;	// Valid when (HDMIVideoFormat == VMD_HDMIFORMAT_3D)
+		byte ThreeDExtData;		// Valid when (HDMIVideoFormat == VMD_HDMIFORMAT_3D) && (ThreeDStructure == VMD_3D_SIDEBYSIDEHALF)
+
+		byte AudioMode;			// 0 = I2S; 1 = S/PDIF; 2 = HBR; 3 = DSD;
+		byte AudioChannels;		// 1 = 2chs; 2 = 3chs; 3 = 4chs; 4 = 5chs; 5 = 6chs; 6 = 7chs; 7 = 8chs;
+		byte AudioFs;			// 0-44.1kHz; 2-48kHz; 3-32kHz; 8-88.2kHz; 9-768kHz; A-96kHz; C-176.4kHz; E-192kHz; 1/4/5/6/7/B/D/F-not indicated
+     	byte AudioWordLength; 	// 0/1-not available; 2-16 bit; 4-18 bit; 8-19 bit; A-20 bit; C-17 bit; 5-22 bit; 9-23 bit; B-24 bit; D-21 bit
+     	byte AudioI2SFormat;   	// Please refer to TPI reg0x20 for detailed. 
+     						 	//[7]_SCK Sample Edge: 0 = Falling; 1 = Rising
+     						 	//[6:4]_MCLK Multiplier: 000:MCLK=128Fs; 001:MCLK=256Fs; 010:MCLK=384Fs; 011:MCLK=512Fs; 100:MCLK=768Fs; 101:MCLK=1024Fs; 110:MCLK=1152Fs; 111:MCLK=192Fs;   
+     						 	//[3]_WS Polarity-Left when: 0 = WS is low when Left; 1 = WS is high when Left
+     						 	//[2]_SD Justify Data is justified: 0 = Left; 1 = Right
+     						 	//[1]_SD Direction Byte shifted first: 0 = MSB; 1 = LSB
+     						 	//[0]_WS to SD First Bit Shift: 0 = Yes; 1 = No
+
+}SIHDMITX_CONFIG;
+
+//====================================================
+typedef struct
+{
+	byte txPowerState;
+	byte tmdsPoweredUp;
+	byte hdmiCableConnected;
+	byte dsRxPoweredUp;
+	
+}GLOBAL_SYSTEM;
+
+//====================================================
+typedef struct
+{
+	byte HDCP_TxSupports;
+	byte HDCP_AksvValid;
+	byte HDCP_Started;
+	byte HDCP_LinkProtectionLevel;
+	byte HDCP_Override;
+	byte HDCPAuthenticated;
+	
+}GLOBAL_HDCP;
+
+//====================================================
+typedef struct
+{												// for storing EDID parsed data
+	byte edidDataValid;
+	byte VideoDescriptor[MAX_V_DESCRIPTORS];	// maximum number of video descriptors
+	byte AudioDescriptor[MAX_A_DESCRIPTORS][3];	// maximum number of audio descriptors
+	byte SpkrAlloc[MAX_SPEAKER_CONFIGURATIONS];	// maximum number of speaker configurations
+	byte UnderScan;								// "1" if DTV monitor underscans IT video formats by default
+	byte BasicAudio;								// Sink supports Basic Audio
+	byte YCbCr_4_4_4;							// Sink supports YCbCr 4:4:4
+	byte YCbCr_4_2_2;							// Sink supports YCbCr 4:2:2
+	byte HDMI_Sink;								// "1" if HDMI signature found
+	byte CEC_A_B;								// CEC Physical address. See HDMI 1.3 Table 8-6
+	byte CEC_C_D;
+	byte ColorimetrySupportFlags;				// IEC 61966-2-4 colorimetry support: 1 - xvYCC601; 2 - xvYCC709 
+	byte MetadataProfile;
+	byte _3D_Supported;
+	
+} GLOBAL_EDID;
+
+enum EDID_ErrorCodes
+{
+	EDID_OK,
+	EDID_INCORRECT_HEADER,
+	EDID_CHECKSUM_ERROR,
+	EDID_NO_861_EXTENSIONS,
+	EDID_SHORT_DESCRIPTORS_OK,
+	EDID_LONG_DESCRIPTORS_OK,
+	EDID_EXT_TAG_ERROR,
+	EDID_REV_ADDR_ERROR,
+	EDID_V_DESCR_OVERFLOW,
+	EDID_UNKNOWN_TAG_CODE,
+	EDID_NO_DETAILED_DESCRIPTORS,
+	EDID_DDC_BUS_REQ_FAILURE,
+	EDID_DDC_BUS_RELEASE_FAILURE
+};
+
+
+#ifdef DEV_SUPPORT_EDID
+#define IsHDMI_Sink()		(g_edid.HDMI_Sink)
+#define IsCEC_DEVICE()		(((g_edid.CEC_A_B != 0xFF) && (g_edid.CEC_C_D != 0xFF)) ? TRUE : FALSE)
+
+#else
+#define IsHDMI_Sink()		(TRUE)
+#define IsCEC_DEVICE()		(FALSE)
+#endif
+
+
+
+//--------------------------------------------------------------------
+// Debug Definitions
+//--------------------------------------------------------------------
+// Compile debug prints inline or not
+#define CONF__TPI_TRACE_PRINT		(DISABLE)
+#define CONF__TPI_DEBUG_PRINT   	(DISABLE)
+#define CONF__TPI_EDID_PRINT    		(DISABLE)
+#define CONF__CPI_DEBUG_PRINT   	(DISABLE)
+
+
+// Trace Print Macro
+// Note: TPI_TRACE_PRINT Requires double parenthesis
+// Example:  TPI_TRACE_PRINT(("hello, world!\n"));
+#if (CONF__TPI_TRACE_PRINT == ENABLE)
+    #define TPI_TRACE_PRINT(x)	printk x; 
+#else
+	#define TPI_TRACE_PRINT(x)
+#endif
+
+// Debug Print Macro
+// Note: TPI_DEBUG_PRINT Requires double parenthesis
+// Example:  TPI_DEBUG_PRINT(("hello, world!\n"));
+#if (CONF__TPI_DEBUG_PRINT == ENABLE)
+    #define TPI_DEBUG_PRINT(x)	printk x; 
+#else
+    #define TPI_DEBUG_PRINT(x)
+#endif
+
+// EDID Print Macro
+// Note: To enable EDID description printing, both CONF__TPI_EDID_PRINT and CONF__TPI_DEBUG_PRINT must be enabled
+// Note: TPI_EDID_PRINT Requires double parenthesis
+// Example:  TPI_EDID_PRINT(("hello, world!\n"));
+#if (CONF__TPI_EDID_PRINT == ENABLE)
+    #define TPI_EDID_PRINT(x)		TPI_DEBUG_PRINT(x)
+#else
+    #define TPI_EDID_PRINT(x)
+#endif
+
+// CPI Debug Print Macro
+// Note: To enable CPI description printing, both CONF__CPI_DEBUG_PRINT and CONF__TPI_DEBUG_PRINT must be enabled
+// Note: CPI_DEBUG_PRINT Requires double parenthesis
+// Example:  CPI_DEBUG_PRINT(("hello, world!\n"));
+#if (CONF__CPI_DEBUG_PRINT == ENABLE)
+    #define CPI_DEBUG_PRINT(x)	TPI_DEBUG_PRINT(x)
+#else
+    #define CPI_DEBUG_PRINT(x)
+#endif
+
+
+
+enum AV_ConfigErrorCodes
+{
+    DE_CANNOT_BE_SET_WITH_EMBEDDED_SYNC,
+    V_MODE_NOT_SUPPORTED,
+    SET_EMBEDDED_SYC_FAILURE,
+    I2S_MAPPING_SUCCESSFUL,
+    I2S_INPUT_CONFIG_SUCCESSFUL,
+    I2S_HEADER_SET_SUCCESSFUL,
+    EHDMI_ARC_SINGLE_SET_SUCCESSFUL,
+    EHDMI_ARC_COMMON_SET_SUCCESSFUL,
+    EHDMI_HEC_SET_SUCCESSFUL,
+    EHDMI_ARC_CM_WITH_HEC_SET_SUCCESSFUL,
+    AUD_MODE_NOT_SUPPORTED,
+    I2S_NOT_SET,
+    DE_SET_OK,
+    VIDEO_MODE_SET_OK,
+    AUDIO_MODE_SET_OK,
+    GBD_SET_SUCCESSFULLY,
+    DE_CANNOT_BE_SET_WITH_3D_MODE,
+};
+
+
+#define ClearInterrupt(x)       WriteByteTPI(TPI_INTERRUPT_STATUS_REG, x)   // write "1" to clear interrupt bit
+
+// Generic Masks
+//====================================================
+#define LOW_BYTE      0x00FF
+
+#define LOW_NIBBLE	0x0F
+#define HI_NIBBLE  	0xF0
+
+#define MSBIT       	0x80
+#define LSBIT          	0x01
+
+#define BIT_0                   0x01
+#define BIT_1                   0x02
+#define BIT_2                   0x04
+#define BIT_3                   0x08
+#define BIT_4                   0x10
+#define BIT_5                   0x20
+#define BIT_6                   0x40
+#define BIT_7                   0x80
+
+#define TWO_LSBITS        	0x03
+#define THREE_LSBITS   	0x07
+#define FOUR_LSBITS    	0x0F
+#define FIVE_LSBITS    	0x1F
+#define SEVEN_LSBITS    	0x7F
+#define TWO_MSBITS     	0xC0
+#define EIGHT_BITS      	0xFF
+#define BYTE_SIZE        	0x08
+#define BITS_1_0          	0x03
+#define BITS_2_1          	0x06
+#define BITS_2_1_0        	0x07
+#define BITS_3_2              	0x0C
+#define BITS_4_3_2       	0x1C  
+#define BITS_5_4              	0x30
+#define BITS_5_4_3		0x38
+#define BITS_6_5             	0x60
+#define BITS_6_5_4        	0x70
+#define BITS_7_6            	0xC0
+
+#define TPI_INTERNAL_PAGE_REG		0xBC
+#define TPI_INDEXED_OFFSET_REG	0xBD
+#define TPI_INDEXED_VALUE_REG		0xBE
+
+// Interrupt Masks
+//====================================================
+#define HOT_PLUG_EVENT          0x01
+#define RX_SENSE_EVENT          0x02
+#define HOT_PLUG_STATE          0x04
+#define RX_SENSE_STATE          0x08
+
+#define AUDIO_ERROR_EVENT       0x10
+#define SECURITY_CHANGE_EVENT   0x20
+#define V_READY_EVENT           0x40
+#define HDCP_CHANGE_EVENT       0x80
+
+#define NON_MASKABLE_INT		0xFF
+
+// TPI Control Masks
+//====================================================
+
+#define CS_HDMI_RGB         0x00
+#define CS_DVI_RGB          0x03
+
+#define ENABLE_AND_REPEAT	0xC0
+#define EN_AND_RPT_MPEG	0xC3
+#define DISABLE_MPEG		0x03	// Also Vendor Specific InfoFrames
+
+// Pixel Repetition Masks
+//====================================================
+#define BIT_BUS_24          0x20
+#define BIT_BUS_12          0x00
+
+#define BIT_EDGE_RISE       0x10
+
+//Audio Maps
+//====================================================
+#define BIT_AUDIO_MUTE      0x10
+
+// Input/Output Format Masks
+//====================================================
+#define BITS_IN_RGB         0x00
+#define BITS_IN_YCBCR444    0x01
+#define BITS_IN_YCBCR422    0x02
+
+#define BITS_IN_AUTO_RANGE  0x00
+#define BITS_IN_FULL_RANGE  0x04
+#define BITS_IN_LTD_RANGE   0x08
+
+#define BIT_EN_DITHER_10_8  0x40
+#define BIT_EXTENDED_MODE   0x80
+
+#define BITS_OUT_RGB        0x00
+#define BITS_OUT_YCBCR444   0x01
+#define BITS_OUT_YCBCR422   0x02
+
+#define BITS_OUT_AUTO_RANGE 0x00
+#define BITS_OUT_FULL_RANGE 0x04
+#define BITS_OUT_LTD_RANGE  0x08
+
+#define BIT_BT_709          0x10
+
+
+// DE Generator Masks
+//====================================================
+#define BIT_EN_DE_GEN       0x40
+#define DE 					0x00
+#define DeDataNumBytes 		12
+
+// Embedded Sync Masks
+//====================================================
+#define BIT_EN_SYNC_EXTRACT 0x40
+#define EMB                 0x80
+#define EmbDataNumBytes     8
+
+
+// Audio Modes
+//====================================================
+#define AUD_PASS_BASIC      0x00
+#define AUD_PASS_ALL        0x01
+#define AUD_DOWN_SAMPLE     0x02
+#define AUD_DO_NOT_CHECK    0x03
+
+#define REFER_TO_STREAM_HDR     0x00
+#define TWO_CHANNELS            	0x00
+#define EIGHT_CHANNELS          	0x01
+#define AUD_IF_SPDIF            		0x40
+#define AUD_IF_I2S              		0x80
+#define AUD_IF_DSD				0xC0
+#define AUD_IF_HBR				0x04
+
+#define TWO_CHANNEL_LAYOUT      0x00
+#define EIGHT_CHANNEL_LAYOUT    0x20
+
+
+// I2C Slave Addresses
+//====================================================
+#define TX_SLAVE_ADDR       	0x72
+#define CBUS_SLAVE_ADDR     	0xC8
+#define HDCP_SLAVE_ADDR     	0x74
+#define EDID_ROM_ADDR       	0xA0
+#define EDID_SEG_ADDR	    	0x60
+
+// Indexed Register Offsets, Constants
+//====================================================
+#define INDEXED_PAGE_0		0x01
+#define INDEXED_PAGE_1		0x02
+#define INDEXED_PAGE_2		0x03
+
+#define TMDS_CONT_REG          0x82
+
+// DDC Bus Addresses
+//====================================================
+#define DDC_BSTATUS_ADDR_L  0x41
+#define DDC_BSTATUS_ADDR_H  0x42
+#define DDC_KSV_FIFO_ADDR   0x43
+#define KSV_ARRAY_SIZE      128
+
+// DDC Bus Bit Masks
+//====================================================
+#define BIT_DDC_HDMI        0x80
+#define BIT_DDC_REPEATER    0x40
+#define BIT_DDC_FIFO_RDY    0x20
+#define DEVICE_COUNT_MASK   0x7F
+
+// KSV Buffer Size
+//====================================================
+#define DEVICE_COUNT         128    // May be tweaked as needed
+
+// InfoFrames
+//====================================================
+#define SIZE_AVI_INFOFRAME      0x0E     // including checksum byte
+#define BITS_OUT_FORMAT         0x60    // Y1Y0 field
+
+#define _4_To_3                 0x10    // Aspect ratio - 4:3  in InfoFrame DByte 1
+#define _16_To_9                0x20    // Aspect ratio - 16:9 in InfoFrame DByte 1
+#define SAME_AS_AR              0x08    // R3R2R1R0 - in AVI InfoFrame DByte 2
+
+#define BT_601                  0x40
+#define BT_709                  0x80
+
+//#define EN_AUDIO_INFOFRAMES         0xC2
+#define TYPE_AUDIO_INFOFRAMES       0x84
+#define AUDIO_INFOFRAMES_VERSION    0x01
+#define AUDIO_INFOFRAMES_LENGTH     0x0A
+
+#define TYPE_GBD_INFOFRAME       	0x0A
+
+#define ENABLE_AND_REPEAT			0xC0
+
+#define EN_AND_RPT_MPEG				0xC3
+#define DISABLE_MPEG				0x03	// Also Vendor Specific InfoFrames
+
+#define EN_AND_RPT_AUDIO			0xC2
+#define DISABLE_AUDIO				0x02
+
+#define EN_AND_RPT_AVI				0xC0	// Not normally used.  Write to TPI 0x19 instead
+#define DISABLE_AVI					0x00	// But this is used to Disable
+
+#define NEXT_FIELD					0x80
+#define GBD_PROFILE					0x00
+#define AFFECTED_GAMUT_SEQ_NUM		0x01
+
+#define ONLY_PACKET					0x30
+#define CURRENT_GAMUT_SEQ_NUM		0x01
+
+// FPLL Multipliers:
+//====================================================
+
+#define X0d5                      				0x00
+#define X1                      					0x01
+#define X2                      					0x02
+#define X4                      					0x03
+
+// 3D Constants
+//====================================================
+
+#define _3D_STRUC_PRESENT				0x02
+
+// 3D_Stucture Constants
+//====================================================
+#define FRAME_PACKING					0x00
+#define FIELD_ALTERNATIVE				0x01
+#define LINE_ALTERNATIVE				0x02
+#define SIDE_BY_SIDE_FULL				0x03
+#define L_PLUS_DEPTH					0x04
+#define L_PLUS_DEPTH_PLUS_GRAPHICS	0x05
+#define SIDE_BY_SIDE_HALF				0x08
+
+// 3D_Ext_Data Constants
+//====================================================
+#define HORIZ_ODD_LEFT_ODD_RIGHT		0x00
+#define HORIZ_ODD_LEFT_EVEN_RIGHT		0x01
+#define HORIZ_EVEN_LEFT_ODD_RIGHT  		0x02
+#define HORIZ_EVEN_LEFT_EVEN_RIGHT		0x03
+
+#define QUINCUNX_ODD_LEFT_EVEN_RIGHT	0x04
+#define QUINCUNX_ODD_LEFT_ODD_RIGHT		0x05
+#define QUINCUNX_EVEN_LEFT_ODD_RIGHT	0x06
+#define QUINCUNX_EVEN_LEFT_EVEN_RIGHT	0x07
+
+#define NO_3D_SUPPORT					0x0F
+
+// InfoFrame Type Code
+//====================================================
+#define AVI  						0x00 
+#define SPD  						0x01  
+#define AUDIO 						0x02   
+#define MPEG 						0x03 
+#define GEN_1	 					0x04
+#define GEN_2 						0x05  
+#define HDMI_VISF 					0x06 
+#define GBD 						0x07 
+
+// Size of InfoFrame Data types
+#define MAX_SIZE_INFOFRAME_DATA     0x22
+#define SIZE_AVI_INFOFRAME			0x0E	// 14 bytes
+#define SIZE_SPD_INFOFRAME 			0x19	// 25 bytes
+#define SISE_AUDIO_INFOFRAME_IFORM  0x0A    // 10 bytes
+#define SIZE_AUDIO_INFOFRAME		0x0F	// 15 bytes
+#define SIZE_MPRG_HDMI_INFOFRAME    0x1B	// 27 bytes		
+#define SIZE_MPEG_INFOFRAME 		0x0A	// 10 bytes
+#define SIZE_GEN_1_INFOFRAME    	0x1F	// 31 bytes
+#define SIZE_GEN_2_INFOFRAME    	0x1F	// 31 bytes
+#define SIZE_HDMI_VISF_INFOFRAME    0x1E	// 31 bytes
+#define SIZE_GBD_INFOFRAME     		0x1C  	// 28 bytes
+
+#define AVI_INFOFRM_OFFSET          0x0C
+#define OTHER_INFOFRM_OFFSET        0xC4
+#define TPI_INFOFRAME_ACCESS_REG    0xBF
+
+// Serial Communication Buffer constants
+#define MAX_COMMAND_ARGUMENTS       50
+#define GLOBAL_BYTE_BUF_BLOCK_SIZE  131
+
+
+// Video Mode Constants
+//====================================================
+#define VMD_ASPECT_RATIO_4x3			0x01
+#define VMD_ASPECT_RATIO_16x9			0x02
+
+#define VMD_COLOR_SPACE_RGB			0x00
+#define VMD_COLOR_SPACE_YCBCR422		0x01
+#define VMD_COLOR_SPACE_YCBCR444		0x02
+
+#define VMD_COLOR_DEPTH_8BIT			0x00
+#define VMD_COLOR_DEPTH_10BIT			0x01
+#define VMD_COLOR_DEPTH_12BIT			0x02
+#define VMD_COLOR_DEPTH_16BIT			0x03
+
+#define VMD_HDCP_NOT_AUTHENTICATED	0x00
+#define VMD_HDCP_AUTHENTICATED		0x01
+
+#define VMD_HDMIFORMAT_CEA_VIC          	0x00
+#define VMD_HDMIFORMAT_HDMI_VIC         	0x01
+#define VMD_HDMIFORMAT_3D               	0x02
+#define VMD_HDMIFORMAT_PC               	0x03
+
+// These values are from HDMI Spec 1.4 Table H-2
+#define VMD_3D_FRAMEPACKING			0
+#define VMD_3D_FIELDALTERNATIVE		1
+#define VMD_3D_LINEALTERNATIVE		2              
+#define VMD_3D_SIDEBYSIDEFULL			3
+#define VMD_3D_LDEPTH					4
+#define VMD_3D_LDEPTHGRAPHICS			5
+#define VMD_3D_SIDEBYSIDEHALF			8
+
+
+//--------------------------------------------------------------------
+// System Macro Definitions
+//--------------------------------------------------------------------
+#define TX_HW_RESET_PERIOD      200
+#define SII902XA_DEVICE_ID         0xB0
+
+#define T_HPD_DELAY    			10
+
+//--------------------------------------------------------------------
+// HDCP Macro Definitions
+//--------------------------------------------------------------------
+#define AKSV_SIZE              		5
+#define NUM_OF_ONES_IN_KSV	20
+
+//--------------------------------------------------------------------
+// EDID Constants Definition
+//--------------------------------------------------------------------
+#define EDID_BLOCK_0_OFFSET 0x00
+#define EDID_BLOCK_1_OFFSET 0x80
+
+#define EDID_BLOCK_SIZE      128
+#define EDID_HDR_NO_OF_FF   0x06
+#define NUM_OF_EXTEN_ADDR   0x7E
+
+#define EDID_TAG_ADDR       0x00
+#define EDID_REV_ADDR       0x01
+#define EDID_TAG_IDX        0x02
+#define LONG_DESCR_PTR_IDX  0x02
+#define MISC_SUPPORT_IDX    0x03
+
+#define ESTABLISHED_TIMING_INDEX        35      // Offset of Established Timing in EDID block
+#define NUM_OF_STANDARD_TIMINGS          8
+#define STANDARD_TIMING_OFFSET          38
+#define LONG_DESCR_LEN                  18
+#define NUM_OF_DETAILED_DESCRIPTORS      4
+
+#define DETAILED_TIMING_OFFSET        0x36
+
+// Offsets within a Long Descriptors Block
+//====================================================
+#define PIX_CLK_OFFSET                	 	0
+#define H_ACTIVE_OFFSET               	2
+#define H_BLANKING_OFFSET          	3
+#define V_ACTIVE_OFFSET                  	5
+#define V_BLANKING_OFFSET                6
+#define H_SYNC_OFFSET                    	8
+#define H_SYNC_PW_OFFSET                 9
+#define V_SYNC_OFFSET                   	10
+#define V_SYNC_PW_OFFSET                	10
+#define H_IMAGE_SIZE_OFFSET            	12
+#define V_IMAGE_SIZE_OFFSET           	13
+#define H_BORDER_OFFSET                 	15
+#define V_BORDER_OFFSET                 	16
+#define FLAGS_OFFSET                    	17
+
+#define AR16_10                          		0
+#define AR4_3                            		1
+#define AR5_4                            		2
+#define AR16_9                           		3
+
+// Data Block Tag Codes
+//====================================================
+#define AUDIO_D_BLOCK       0x01
+#define VIDEO_D_BLOCK       0x02
+#define VENDOR_SPEC_D_BLOCK 0x03
+#define SPKR_ALLOC_D_BLOCK  0x04
+#define USE_EXTENDED_TAG    0x07
+
+// Extended Data Block Tag Codes
+//====================================================
+#define COLORIMETRY_D_BLOCK 0x05
+
+#define HDMI_SIGNATURE_LEN  0x03
+
+#define CEC_PHYS_ADDR_LEN   0x02
+#define EDID_EXTENSION_TAG  0x02
+#define EDID_REV_THREE      0x03
+#define EDID_DATA_START     0x04
+
+#define EDID_BLOCK_0        0x00
+#define EDID_BLOCK_2_3      0x01
+
+#define VIDEO_CAPABILITY_D_BLOCK 0x00
+
+
+
+
+
+//--------------------------------------------------------------------
+// TPI Register Definition
+//--------------------------------------------------------------------
+
+// TPI Video Mode Data
+#define TPI_PIX_CLK_LSB							(0x00)
+#define TPI_PIX_CLK_MSB							(0x01)
+#define TPI_VERT_FREQ_LSB						(0x02)
+#define TPI_VERT_FREQ_MSB						(0x03)
+#define TPI_TOTAL_PIX_LSB						(0x04)
+#define TPI_TOTAL_PIX_MSB						(0x05)
+#define TPI_TOTAL_LINES_LSB					(0x06)
+#define TPI_TOTAL_LINES_MSB					(0x07)
+
+// Pixel Repetition Data
+#define TPI_PIX_REPETITION						(0x08)
+
+// TPI AVI Input and Output Format Data
+/// AVI Input Format Data
+#define TPI_INPUT_FORMAT_REG					(0x09)
+#define INPUT_COLOR_SPACE_MASK				(BIT_1 | BIT_0)
+#define INPUT_COLOR_SPACE_RGB					(0x00)
+#define INPUT_COLOR_SPACE_YCBCR444			(0x01)
+#define INPUT_COLOR_SPACE_YCBCR422			(0x02)
+#define INPUT_COLOR_SPACE_BLACK_MODE			(0x03)
+
+/// AVI Output Format Data
+#define TPI_OUTPUT_FORMAT_REG					(0x0A)
+#define TPI_YC_Input_Mode						(0x0B)
+
+// TPI InfoFrame related constants
+#define TPI_AVI_INFO_REG_ADDR					(0x0C) // AVI InfoFrame Checksum
+#define TPI_OTHER_INFO_REG_ADDR		  		(0xBF)
+#define TPI_INFO_FRAME_REG_OFFSET				(0xC4)
+
+// TPI AVI InfoFrame Data
+#define TPI_AVI_BYTE_0							(0x0C)
+#define TPI_AVI_BYTE_1							(0x0D)
+#define TPI_AVI_BYTE_2							(0x0E)
+#define TPI_AVI_BYTE_3							(0x0F)
+#define TPI_AVI_BYTE_4							(0x10)
+#define TPI_AVI_BYTE_5							(0x11)
+
+#define TPI_INFO_FRM_DBYTE5					(0xC8)
+#define TPI_INFO_FRM_DBYTE6					(0xC9)
+
+#define TPI_END_TOP_BAR_LSB					(0x12)
+#define TPI_END_TOP_BAR_MSB					(0x13)
+
+#define TPI_START_BTM_BAR_LSB					(0x14)
+#define TPI_START_BTM_BAR_MSB					(0x15)
+
+#define TPI_END_LEFT_BAR_LSB					(0x16)
+#define TPI_END_LEFT_BAR_MSB					(0x17)
+
+#define TPI_END_RIGHT_BAR_LSB					(0x18)
+#define TPI_END_RIGHT_BAR_MSB					(0x19)
+
+// Colorimetry
+#define SET_EX_COLORIMETRY						(0x0C)	// Set TPI_AVI_BYTE_2 to extended colorimetry and use 
+													//TPI_AVI_BYTE_3
+
+#define TPI_SYSTEM_CONTROL_DATA_REG			(0x1A)
+
+#define LINK_INTEGRITY_MODE_MASK				(BIT_6)
+#define LINK_INTEGRITY_STATIC					(0x00)
+#define LINK_INTEGRITY_DYNAMIC					(0x40)
+
+#define TMDS_OUTPUT_CONTROL_MASK				(BIT_4)
+#define TMDS_OUTPUT_CONTROL_ACTIVE			(0x00)
+#define TMDS_OUTPUT_CONTROL_POWER_DOWN	(0x10)
+
+#define AV_MUTE_MASK							(BIT_3)
+#define AV_MUTE_NORMAL						(0x00)
+#define AV_MUTE_MUTED							(0x08)
+
+#define DDC_BUS_REQUEST_MASK					(BIT_2)
+#define DDC_BUS_REQUEST_NOT_USING			(0x00)
+#define DDC_BUS_REQUEST_REQUESTED			(0x04)
+
+#define DDC_BUS_GRANT_MASK					(BIT_1)
+#define DDC_BUS_GRANT_NOT_AVAILABLE			(0x00)
+#define DDC_BUS_GRANT_GRANTED				(0x02)
+
+#define OUTPUT_MODE_MASK						(BIT_0)
+#define OUTPUT_MODE_DVI						(0x00)
+#define OUTPUT_MODE_HDMI						(0x01)
+
+// TPI Identification Registers
+#define TPI_DEVICE_ID							(0x1B)
+#define TPI_DEVICE_REV_ID						(0x1C)
+
+#define TPI_RESERVED2							(0x1D)
+
+#define TPI_DEVICE_POWER_STATE_CTRL_REG		(0x1E)
+
+#define CTRL_PIN_CONTROL_MASK					(BIT_4)
+#define CTRL_PIN_TRISTATE						(0x00)
+#define CTRL_PIN_DRIVEN_TX_BRIDGE				(0x10)
+
+#define TX_POWER_STATE_MASK					(BIT_1 | BIT_0)
+#define TX_POWER_STATE_D0						(0x00)
+#define TX_POWER_STATE_D1						(0x01)
+#define TX_POWER_STATE_D2						(0x02)
+#define TX_POWER_STATE_D3						(0x03)
+
+// Configuration of I2S Interface
+#define TPI_I2S_EN								(0x1F)
+#define TPI_I2S_IN_CFG							(0x20)
+#define SCK_SAMPLE_EDGE						(BIT_7)
+
+// Available only when TPI 0x26[7:6]=10 to select I2S input
+#define TPI_I2S_CHST_0							(0x21)
+#define TPI_I2S_CHST_1							(0x22)
+#define TPI_I2S_CHST_2							(0x23)
+#define TPI_I2S_CHST_3							(0x24)
+#define TPI_I2S_CHST_4							(0x25)
+
+#define AUDIO_INPUT_LENGTH					(0x24)
+
+// Available only when 0x26[7:6]=01
+#define TPI_SPDIF_HEADER						(0x24)
+#define TPI_AUDIO_HANDLING						(0x25)
+
+// Audio Configuration Regiaters
+#define TPI_AUDIO_INTERFACE_REG				(0x26)
+#define AUDIO_MUTE_MASK						(BIT_4)
+#define AUDIO_MUTE_NORMAL						(0x00)
+#define AUDIO_MUTE_MUTED						(0x10)
+
+#define AUDIO_SEL_MASK							(BITS_7_6)
+
+
+#define TPI_AUDIO_SAMPLE_CTRL					(0x27)
+#define TPI_SPEAKER_CFG						(0xC7)
+#define TPI_CODING_TYPE_CHANNEL_COUNT		(0xC4)
+
+//--------------------------------------------------------------------
+// HDCP Implementation
+// HDCP link security logic is implemented in certain transmitters; unique
+//   keys are embedded in each chip as part of the solution. The security 
+//   scheme is fully automatic and handled completely by the hardware.
+//--------------------------------------------------------------------
+
+/// HDCP Query Data Register
+#define TPI_HDCP_QUERY_DATA_REG				(0x29)
+
+#define EXTENDED_LINK_PROTECTION_MASK		(BIT_7)
+#define EXTENDED_LINK_PROTECTION_NONE		(0x00)
+#define EXTENDED_LINK_PROTECTION_SECURE		(0x80)
+
+#define LOCAL_LINK_PROTECTION_MASK			(BIT_6)
+#define LOCAL_LINK_PROTECTION_NONE			(0x00)
+#define LOCAL_LINK_PROTECTION_SECURE			(0x40)
+
+#define LINK_STATUS_MASK						(BIT_5 | BIT_4)
+#define LINK_STATUS_NORMAL					(0x00)
+#define LINK_STATUS_LINK_LOST					(0x10)
+#define LINK_STATUS_RENEGOTIATION_REQ		(0x20)
+#define LINK_STATUS_LINK_SUSPENDED			(0x30)
+
+#define HDCP_REPEATER_MASK					(BIT_3)
+#define HDCP_REPEATER_NO						(0x00)
+#define HDCP_REPEATER_YES						(0x08)
+
+#define CONNECTOR_TYPE_MASK					(BIT_2 | BIT_0)
+#define CONNECTOR_TYPE_DVI						(0x00)
+#define CONNECTOR_TYPE_RSVD					(0x01)
+#define CONNECTOR_TYPE_HDMI					(0x04)
+#define CONNECTOR_TYPE_FUTURE					(0x05)
+
+#define PROTECTION_TYPE_MASK					(BIT_1)
+#define PROTECTION_TYPE_NONE					(0x00)
+#define PROTECTION_TYPE_HDCP					(0x02)
+
+/// HDCP Control Data Register
+#define TPI_HDCP_CONTROL_DATA_REG			(0x2A)
+#define PROTECTION_LEVEL_MASK					(BIT_0)
+#define PROTECTION_LEVEL_MIN					(0x00)
+#define PROTECTION_LEVEL_MAX					(0x01)
+
+#define KSV_FORWARD_MASK						(BIT_4)
+#define KSV_FORWARD_ENABLE					(0x10)
+#define KSV_FORWARD_DISABLE					(0x00)
+
+/// HDCP BKSV Registers
+#define TPI_BKSV_1_REG							(0x2B)
+#define TPI_BKSV_2_REG							(0x2C)
+#define TPI_BKSV_3_REG							(0x2D)
+#define TPI_BKSV_4_REG							(0x2E)
+#define TPI_BKSV_5_REG							(0x2F)
+
+/// HDCP Revision Data Register
+#define TPI_HDCP_REVISION_DATA_REG			(0x30)
+
+#define HDCP_MAJOR_REVISION_MASK				(BIT_7 | BIT_6 | BIT_5 | BIT_4)
+#define HDCP_MAJOR_REVISION_VALUE				(0x10)
+
+#define HDCP_MINOR_REVISION_MASK				(BIT_3 | BIT_2 | BIT_1 | BIT_0)
+#define HDCP_MINOR_REVISION_VALUE				(0x02)
+
+/// HDCP KSV and V' Value Data Register
+#define TPI_V_PRIME_SELECTOR_REG				(0x31)
+
+/// V' Value Readback Registers
+#define TPI_V_PRIME_7_0_REG					(0x32)
+#define TPI_V_PRIME_15_9_REG					(0x33)
+#define TPI_V_PRIME_23_16_REG					(0x34)
+#define TPI_V_PRIME_31_24_REG					(0x35)
+
+/// HDCP AKSV Registers
+#define TPI_AKSV_1_REG							(0x36)
+#define TPI_AKSV_2_REG							(0x37)
+#define TPI_AKSV_3_REG							(0x38)
+#define TPI_AKSV_4_REG							(0x39)
+#define TPI_AKSV_5_REG							(0x3A)
+
+#define TPI_DEEP_COLOR_GCP						(0x40)
+
+//--------------------------------------------------------------------
+// Interrupt Service
+// TPI can be configured to generate an interrupt to the host to notify it of
+//   various events. The host can either poll for activity or use an interrupt
+//   handler routine. TPI generates on a single interrupt (INT) to the host.
+//--------------------------------------------------------------------
+
+/// Interrupt Enable Register
+#define TPI_INTERRUPT_ENABLE_REG				(0x3C)
+
+#define HDCP_AUTH_STATUS_CHANGE_EN_MASK	(BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_DISABLE		(0x00)
+#define HDCP_AUTH_STATUS_CHANGE_ENABLE		(0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EN_MASK		(BIT_6)
+#define HDCP_VPRIME_VALUE_READY_DISABLE		(0x00)
+#define HDCP_VPRIME_VALUE_READY_ENABLE		(0x40)
+
+#define HDCP_SECURITY_CHANGE_EN_MASK		(BIT_5)
+#define HDCP_SECURITY_CHANGE_DISABLE		    	(0x00)
+#define HDCP_SECURITY_CHANGE_ENABLE			(0x20)
+
+#define AUDIO_ERROR_EVENT_EN_MASK			(BIT_4)
+#define AUDIO_ERROR_EVENT_DISABLE				(0x00)
+#define AUDIO_ERROR_EVENT_ENABLE				(0x10)
+
+#define CPI_EVENT_NO_RX_SENSE_MASK			(BIT_3)
+#define CPI_EVENT_NO_RX_SENSE_DISABLE		(0x00)
+#define CPI_EVENT_NO_RX_SENSE_ENABLE			(0x08)
+
+#define RECEIVER_SENSE_EVENT_EN_MASK			(BIT_1)
+#define RECEIVER_SENSE_EVENT_DISABLE			(0x00)
+#define RECEIVER_SENSE_EVENT_ENABLE			(0x02)
+
+#define HOT_PLUG_EVENT_EN_MASK				(BIT_0)
+#define HOT_PLUG_EVENT_DISABLE				(0x00)
+#define HOT_PLUG_EVENT_ENABLE					(0x01)
+
+/// Interrupt Status Register
+#define TPI_INTERRUPT_STATUS_REG				(0x3D)
+
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_MASK	(BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_NO	(0x00)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_YES	(0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EVENT_MASK	(BIT_6)
+#define HDCP_VPRIME_VALUE_READY_EVENT_NO	(0x00)
+#define HDCP_VPRIME_VALUE_READY_EVENT_YES	(0x40)
+
+#define HDCP_SECURITY_CHANGE_EVENT_MASK		(BIT_5)
+#define HDCP_SECURITY_CHANGE_EVENT_NO		(0x00)
+#define HDCP_SECURITY_CHANGE_EVENT_YES		(0x20)
+
+#define AUDIO_ERROR_EVENT_MASK				(BIT_4)
+#define AUDIO_ERROR_EVENT_NO					(0x00)
+#define AUDIO_ERROR_EVENT_YES					(0x10)
+
+#define CPI_EVENT_MASK							(BIT_3)
+#define CPI_EVENT_NO							(0x00)
+#define CPI_EVENT_YES							(0x08)
+#define RX_SENSE_MASK							(BIT_3)		// This bit is dual purpose depending on the value of 0x3C[3]
+#define RX_SENSE_NOT_ATTACHED					(0x00)
+#define RX_SENSE_ATTACHED						(0x08)
+
+#define HOT_PLUG_PIN_STATE_MASK				(BIT_2)
+#define HOT_PLUG_PIN_STATE_LOW				(0x00)
+#define HOT_PLUG_PIN_STATE_HIGH				(0x04)
+
+#define RECEIVER_SENSE_EVENT_MASK				(BIT_1)
+#define RECEIVER_SENSE_EVENT_NO				(0x00)
+#define RECEIVER_SENSE_EVENT_YES				(0x02)
+
+#define HOT_PLUG_EVENT_MASK					(BIT_0)
+#define HOT_PLUG_EVENT_NO						(0x00)
+#define HOT_PLUG_EVENT_YES					(0x01)
+
+/// KSV FIFO First Status Register
+#define TPI_KSV_FIFO_READY_INT					(0x3E)
+
+#define KSV_FIFO_READY_MASK					(BIT_1)
+#define KSV_FIFO_READY_NO						(0x00)
+#define KSV_FIFO_READY_YES						(0x02)
+
+#define TPI_KSV_FIFO_READY_INT_EN				(0x3F)
+
+#define KSV_FIFO_READY_EN_MASK				(BIT_1)
+#define KSV_FIFO_READY_DISABLE				(0x00)
+#define KSV_FIFO_READY_ENABLE					(0x02)
+
+/// KSV FIFO Last Status Register
+#define TPI_KSV_FIFO_STATUS_REG				(0x41)
+#define TPI_KSV_FIFO_VALUE_REG					(0x42)
+
+#define KSV_FIFO_LAST_MASK						(BIT_7)
+#define KSV_FIFO_LAST_NO						(0x00)
+#define KSV_FIFO_LAST_YES						(0x80)
+
+#define KSV_FIFO_COUNT_MASK					(BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)
+
+// Sync Register Configuration and Sync Monitoring Registers
+#define TPI_SYNC_GEN_CTRL						(0x60)
+#define TPI_SYNC_POLAR_DETECT					(0x61)
+
+// Explicit Sync DE Generator Registers (TPI 0x60[7]=0)
+#define TPI_DE_DLY								(0x62)
+#define TPI_DE_CTRL								(0x63)
+#define TPI_DE_TOP								(0x64)
+
+#define TPI_RESERVED4							(0x65)
+
+#define TPI_DE_CNT_7_0							(0x66)
+#define TPI_DE_CNT_11_8						(0x67)
+
+#define TPI_DE_LIN_7_0							(0x68)
+#define TPI_DE_LIN_10_8							(0x69)
+
+#define TPI_DE_H_RES_7_0						(0x6A)
+#define TPI_DE_H_RES_10_8						(0x6B)
+
+#define TPI_DE_V_RES_7_0						(0x6C)
+#define TPI_DE_V_RES_10_8						(0x6D)
+
+// Embedded Sync Register Set (TPI 0x60[7]=1)
+#define TPI_HBIT_TO_HSYNC_7_0					(0x62)
+#define TPI_HBIT_TO_HSYNC_9_8					(0x63)
+#define TPI_FIELD_2_OFFSET_7_0					(0x64)
+#define TPI_FIELD_2_OFFSET_11_8				(0x65)
+#define TPI_HWIDTH_7_0							(0x66)
+#define TPI_HWIDTH_8_9							(0x67)
+#define TPI_VBIT_TO_VSYNC						(0x68)
+#define TPI_VWIDTH								(0x69)
+
+// H/W Optimization Control Registers
+#define TPI_HW_OPT_CTRL_1						(0xB9)
+#define TPI_HW_OPT_CTRL_2						(0xBA)
+#define TPI_HW_OPT_CTRL_3						(0xBB)
+
+// H/W Optimization Control Register #3 Set 
+#define DDC_DELAY_BIT9_MASK					(BIT_7)
+#define DDC_DELAY_BIT9_NO						(0x00)
+#define DDC_DELAY_BIT9_YES						(0x80)
+#define RI_CHECK_SKIP_MASK						(BIT_3)
+#define RI_CHECK_SKIP_NO						(0x00)
+#define RI_CHECK_SKIP_YES						(0x08)
+
+// TPI Enable Register
+#define TPI_ENABLE								(0xC7)
+
+// Misc InfoFrames
+#define MISC_INFO_FRAMES_CTRL					(0xBF)
+#define MISC_INFO_FRAMES_TYPE					(0xC0)
+#define MISC_INFO_FRAMES_VER					(0xC1)
+#define MISC_INFO_FRAMES_LEN					(0xC2)
+#define MISC_INFO_FRAMES_CHKSUM				(0xC3)
+//--------------------------------------------------------------------
+void DelayMS (word MS);
+
+byte I2CReadBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data );
+byte I2CWriteBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data );
+byte siiReadSegmentBlockEDID(struct i2c_client *client, byte Segment, byte Offset, byte *Buffer, byte Length);
+
+void WriteByteTPI (byte RegOffset, byte Data);
+byte ReadByteTPI (byte RegOffset);
+
+
+void siHdmiTx_PowerStateD2 (void);
+void siHdmiTx_PowerStateD0fromD2 (void);
+
+void siHdmiTx_Init (void);
+
+byte DoEdidRead (void);
+byte GetDDC_Access (byte* SysCtrlRegVal);
+byte ReleaseDDC (byte SysCtrlRegVal);
+
+
+
+
+byte siHdmiTx_VideoSet (void);
+byte siHdmiTx_AudioSet (void);
+byte siHdmiTx_TPI_Init (void);
+void siHdmiTx_TPI_Poll (void);
+void siHdmiTx_VideoSel (byte vmode);
+void siHdmiTx_AudioSel (byte Afs);
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk750/vdif.h b/drivers/gpu/drm/smifb2/ddk750/vdif.h
new file mode 100644
index 000000000000..36d11d6daa54
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk750/vdif.h
@@ -0,0 +1,63 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  vdif.h --- SMI DDK 
+*  This file contains the video display information format structure
+* 
+*******************************************************************/
+#ifndef _VDIF_H_
+#define _VDIF_H_
+
+/* Sync polarity */
+typedef enum _vdif_sync_polarity_t
+{
+    VDIF_SYNC_NEGATIVE = 0,
+    VDIF_SYNC_POSITIVE
+} vdif_sync_polarity_t; 
+
+/* Scan type */
+typedef enum _vdif_scan_type_t
+{
+    VDIF_NONINTERLACED = 0,
+    VDIF_INTERLACED
+} vdif_scan_type_t;
+
+/* Monitor Timing Information */
+typedef struct _video_display_information_format_t
+{
+    unsigned long pixelClock;
+    unsigned long characterWidth;
+    vdif_scan_type_t scanType; 
+    
+    unsigned long horizontalFrequency;
+    vdif_sync_polarity_t horizontalSyncPolarity;
+    unsigned long horizontalTotal;
+    unsigned long horizontalActive;
+    unsigned long horizontalBlankStart;
+    unsigned long horizontalBlankTime;
+    unsigned long horizontalSyncStart;
+    unsigned long horizontalRightBorder;
+    unsigned long horizontalFrontPorch;
+    unsigned long horizontalSyncWidth;
+    unsigned long horizontalBackPorch;
+    unsigned long horizontalLeftBorder;
+    
+    unsigned long verticalFrequency;
+    vdif_sync_polarity_t verticalSyncPolarity; 
+    unsigned long verticalTotal;
+    unsigned long verticalActive;
+    unsigned long verticalBlankStart;
+    unsigned long verticalBlankTime;
+    unsigned long verticalSyncStart;
+    unsigned long verticalBottomBorder;
+    unsigned long verticalFrontPorch;
+    unsigned long verticalSyncHeight;
+    unsigned long verticalBackPorch;
+    unsigned long verticalTopBorder;
+} vdif_t;
+
+#endif  /* _VDIF_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768.h b/drivers/gpu/drm/smifb2/ddk768/ddk768.h
new file mode 100644
index 000000000000..8285c868494b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768.h
@@ -0,0 +1,23 @@
+#ifndef DDK768_H__
+#define DDK768_H__
+/*******************************************************************
+*
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+*
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+*
+*  RegSC.h --- SM718 SDK
+*  This file contains the definitions for the System Configuration registers.
+*
+*******************************************************************/
+#include "ddk768_reg.h"
+#include "ddk768_help.h"
+
+
+#include "ddk768_mode.h"
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_display.h"
+#include "ddk768_2d.h"
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.c
new file mode 100644
index 000000000000..8ccbc20bd3bb
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.c
@@ -0,0 +1,1209 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  2d.C --- SM750/SM718 DDK 
+*  This file contains the definitions for the 2D functions.
+* 
+*******************************************************************/
+#include "linux/string.h"
+#include "ddk768_reg.h"
+
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_2d.h"
+#include "ddk768_help.h"
+
+/* Blt Direction definitions */
+#define TOP_TO_BOTTOM 0
+#define LEFT_TO_RIGHT 0
+#define BOTTOM_TO_TOP 1
+#define RIGHT_TO_LEFT 1
+
+#if 0 /* Cheok: Block it out to test if it is problem in new chip */
+
+/* Flag to enable the 192 bytes patch to workaround the 2D errata, where the engine
+   will draws incorrectly for BITBLT function that involves READ from memory. 
+   Currently, this definition flag is only used for testing. */
+#define ENABLE_192_BYTES_PATCH
+#endif
+
+/* Static macro */
+#define BYTE_PER_PIXEL(bpp)         (bpp / 8)
+
+/*
+ * 2D Engine Initialization.
+ * This function must be called before other 2D functions.
+ * Assumption: A specific video mode has been properly set up.
+ */
+void ddk768_deInit()
+{
+    ddk768_enable2DEngine(1);
+
+    ddk768_deReset(); /* Just be sure no left-over operations from other applications */
+
+    /* Set up 2D registers that won't change for a specific mode. */
+
+    /* Drawing engine bus and pixel mask, always want to enable. */
+    POKE_32(DE_MASKS, 0xFFFFFFFF);
+
+    /* Pixel format, which can be 8, 16 or 32.
+       Assuming setmode is call before 2D init, then pixel format
+       is available in reg 0x80000 (Panel Display Control)
+    */
+    POKE_32(DE_STRETCH_FORMAT,
+        FIELD_SET  (0, DE_STRETCH_FORMAT, PATTERN_XY,   NORMAL)  |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y,    0)       |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,    0)       |
+        FIELD_SET  (0, DE_STRETCH_FORMAT, ADDRESSING,   XY)      |
+        FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT,3));
+
+    /* Clipping and transparent are disable after INIT */
+    ddk768_deSetClipping(0, 0, 0, 0, 0);
+    ddk768_deSetTransparency(0, 0, 0, 0);
+}
+
+/*
+ * Reset 2D engine by 
+ * 1) Aborting the current 2D operation.
+ * 2) Re-enable 2D engine to normal state.
+ */
+void ddk768_deReset()
+{
+#if 0 /* Cheok(2/11/2014): Not sure which registers are used for Falcon */
+    unsigned long sysCtrl;
+	logical_chip_type_t chipType = ddk768_getChipType();
+
+	if (chipType == SM750 || chipType == SM718)
+	{
+    	/* Abort current 2D operation */
+    	sysCtrl = PEEK_32(SYSTEM_CTRL);
+    	sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, ON);
+    	POKE_32(SYSTEM_CTRL, sysCtrl);
+
+    	/* Re-enable 2D engine to normal state */
+    	sysCtrl = PEEK_32(SYSTEM_CTRL);
+    	sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, OFF);
+    	POKE_32(SYSTEM_CTRL, sysCtrl);
+	}
+	else /* For SM750LE and SM750HS series */
+	{
+	    /* Abort current 2D operation */
+		sysCtrl = PEEK_32(DE_STATE1);
+		sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, ON);
+		POKE_32(DE_STATE1, sysCtrl);
+
+		/* Re-enable 2D engine to normal state */
+        sysCtrl = PEEK_32(DE_STATE1);
+		sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, OFF);
+		POKE_32(DE_STATE1, sysCtrl);
+	}
+#endif
+}
+ 
+/*
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long ddk768_deWaitForNotBusy(void)
+{
+	unsigned long dwVal;
+    unsigned long i = 0x100000;
+
+    while (i--)
+    {
+        dwVal = PEEK_32(DE_STATE2);
+        if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS)      == DE_STATE2_DE_STATUS_IDLE) &&
+            (FIELD_GET(dwVal, DE_STATE2, DE_FIFO)        == DE_STATE2_DE_FIFO_EMPTY) &&
+            (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO)    == DE_STATE2_DE_MEM_FIFO_EMPTY))
+        {
+            return 0; /* Return because engine idle */
+        }
+    }
+    return -1; /* Return because of timeout */
+}
+
+/*
+ * This function enable/disable clipping area for the 2d engine.
+ * Note that the clipping area is always rectangular.
+ * 
+ */
+long ddk768_deSetClipping(
+unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */
+unsigned long x1,     /* x1, y1 is the upper left corner of the clipping area */
+unsigned long y1,     /* Note that the region includes x1 and y1 */
+unsigned long x2,     /* x2, y2 is the lower right corner of the clippiing area */
+unsigned long y2)     /* Note that the region will not include x2 and y2 */
+{
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    /* Upper left corner and enable/disable bit
+       Note: This module defautls to clip outside region.
+       "Clip inside" is not a useful feature since nothing gets drawn.
+     */
+    POKE_32(DE_CLIP_TL,
+        FIELD_VALUE(0, DE_CLIP_TL, TOP, y1) |
+        ((enable)?
+          FIELD_SET(0, DE_CLIP_TL, STATUS, ENABLE)
+        : FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE))|
+        FIELD_SET  (0, DE_CLIP_TL, INHIBIT,OUTSIDE) |
+        FIELD_VALUE(0, DE_CLIP_TL, LEFT, x1));
+
+    /* Lower right corner */
+    POKE_32(DE_CLIP_BR,
+        FIELD_VALUE(0, DE_CLIP_BR, BOTTOM,y2) |
+        FIELD_VALUE(0, DE_CLIP_BR, RIGHT, x2));
+
+    return 0;
+}
+
+/* 
+ * Function description:
+ * When transparency is enable, the blt engine compares each pixel value 
+ * (either source or destination) with DE_COLOR_COMPARE register.
+ * If match, the destination pixel will NOT be updated.
+ * If not match, the destination pixel will be updated.
+ */
+long ddk768_deSetTransparency(
+unsigned long enable,     /* 0 = disable, 1 = enable transparency feature */
+unsigned long tSelect,    /* 0 = compare source, 1 = compare destination */
+unsigned long tMatch,     /* 0 = Opaque mode, 1 = transparent mode */
+unsigned long ulColor)    /* Color to compare. */
+{
+    unsigned long de_ctrl;
+
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    /* Set mask */
+    if (enable)
+    {
+        POKE_32(DE_COLOR_COMPARE_MASK, 0x00ffffff);
+
+        /* Set compare color */
+        POKE_32(DE_COLOR_COMPARE, ulColor);
+    }
+    else
+    {
+        POKE_32(DE_COLOR_COMPARE_MASK, 0x0);
+        POKE_32(DE_COLOR_COMPARE, 0x0);
+    }
+
+    /* Set up transparency control, without affecting other bits
+       Note: There are two operatiing modes: Transparent and Opague.
+       We only use transparent mode because Opaque mode may have bug.
+    */
+    de_ctrl = PEEK_32(DE_CONTROL)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH)
+              & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT);
+
+    /* For DE_CONTROL_TRANSPARENCY_MATCH bit, always set it
+       to TRANSPARENT mode, OPAQUE mode don't seem working.
+    */
+    de_ctrl |=
+    ((enable)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY, ENABLE)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE))        |
+    ((tMatch)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, TRANSPARENT)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)) |
+    ((tSelect)?
+      FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, DESTINATION)
+    : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE));
+
+    POKE_32(DE_CONTROL, de_ctrl);
+
+    return 0;
+}
+
+/*
+ * This function gets the transparency status from DE_CONTROL register.
+ * It returns a double word with the transparent fields properly set,
+ * while other fields are 0.
+ */
+unsigned long ddk768_deGetTransparency(void)
+{
+    unsigned long de_ctrl;
+
+    de_ctrl = PEEK_32(DE_CONTROL);
+
+    de_ctrl &= 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| 
+        FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+    return de_ctrl;
+}
+
+/*
+ * This function sets the pixel format that will apply to the 2D Engine.
+ */
+void ddk768_deSetPixelFormat(
+    unsigned long bpp
+)
+{
+    unsigned long de_format;
+    
+    de_format = PEEK_32(DE_STRETCH_FORMAT);
+    
+    switch (bpp)
+    {
+        case 8:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
+            break;
+        default:
+        case 16:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
+            break;
+        case 32:
+            de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
+            break;
+    }
+    
+    POKE_32(DE_STRETCH_FORMAT, de_format);
+}
+
+/*
+ * This function uses 2D engine to fill a rectangular area with a specific color.
+ * The filled area includes the starting points.
+ */
+long ddk768_deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/
+unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,      /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long color,  /* Color to be filled */
+unsigned long rop2)   /* ROP value */
+{
+    unsigned long de_ctrl, bytePerPixel;
+
+    bytePerPixel = bpp/8;
+    
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    POKE_32(DE_FOREGROUND, color);
+
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+
+#ifdef ENABLE_192_BYTES_PATCH
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if (((rop2 != ROP2_COPY) || (rop2 != ROP2_Sn) || (rop2 != ROP2_Dn) || 
+         (rop2 != ROP2_D) || (rop2 != ROP2_BLACK) || (rop2 != ROP2_WHITE)) && 
+        ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            ddk768_deWaitForNotBusy();
+            
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    x)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+                
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+                FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+                //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+                FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+                FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+                FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+            POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+
+            if (xChunk == width) break;
+
+            x += xChunk;
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_SET  (0, DE_CONTROL,  STATUS,     START)          |
+            FIELD_SET  (0, DE_CONTROL,  DIRECTION,  LEFT_TO_RIGHT)  |
+            //FIELD_SET  (0, DE_CONTROL,LAST_PIXEL, OFF)            |
+            FIELD_SET  (0, DE_CONTROL,  COMMAND,    RECTANGLE_FILL) |
+            FIELD_SET  (0, DE_CONTROL,  ROP_SELECT, ROP2)           |
+            FIELD_VALUE(0, DE_CONTROL,  ROP,        rop2);
+
+        POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+    }
+    
+    return 0;
+}
+
+/*
+ * This function uses 2D engine to draw a trapezoid with a specific color.
+ * The filled area includes the starting points.
+ */
+long ddk768_deStartTrapezoidFill(
+    unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,
+    unsigned long y,      /* Starting (X, Y) coordinate inside the polygon to be filled */
+    unsigned long length, /* Length of the line */
+    unsigned long color,  /* Color to be filled */
+    unsigned long rop2    /* ROP value */
+)
+{
+    unsigned long de_ctrl =
+        FIELD_SET  (0, DE_CONTROL, STATUS,      START)           |
+        FIELD_SET  (0, DE_CONTROL, QUICK_START, ENABLE)          |
+        FIELD_SET  (0, DE_CONTROL, LAST_PIXEL,  OFF)             |
+        FIELD_SET  (0, DE_CONTROL, DIRECTION,   LEFT_TO_RIGHT)   |
+        FIELD_SET  (0, DE_CONTROL, COMMAND,     TRAPEZOID_FILL)  |
+        FIELD_SET  (0, DE_CONTROL, ROP_SELECT,  ROP2)            |
+        FIELD_VALUE(0, DE_CONTROL, ROP,         rop2);
+
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+    
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      dPitch / BYTE_PER_PIXEL(bpp)));
+
+    /* Set the Line Color */
+    POKE_32(DE_FOREGROUND, color);
+    
+    /* Set the destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    x)       |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    y));
+    
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+    
+    /* Set the line length and width */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    length) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, 0));
+
+    /* Enable the 2D Engine. */
+    POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+    
+    return 0;
+}
+
+/* 
+ * Function to continue drawing a line using Trapezoid Fill method.
+ */
+long ddk768_deNextTrapezoidFill(
+    unsigned long x,            /* Starting X location. */
+    unsigned long length        /* Line length */
+)
+{
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+    
+    /* Set the X destination coordinate */
+    POKE_32(DE_DESTINATION,
+        FIELD_VALUE(PEEK_32(DE_DESTINATION), DE_DESTINATION, X,    x));
+        
+    /* Set the line length */
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(PEEK_32(DE_DIMENSION), DE_DIMENSION, X,    length));
+        
+    return 0;
+}
+
+/* 
+ * Function to stop the Trapezoid Fill drawing.
+ * This function has to be called to end the Trapezoid Fill drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long ddk768_deStopTrapezoidFill()
+{
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+    
+    POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE));
+    
+    return 0;
+}
+
+/*
+ * Video Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk768_deVideoMem2VideoMemBlt(
+unsigned long sBase,  /* Address of source: offset in frame buffer */
+unsigned long sPitch, /* Pitch value of source surface in BYTE */
+unsigned long sx,
+unsigned long sy,     /* Starting coordinate of source surface */
+unsigned long dBase,  /* Address of destination: offset in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height, /* width and height of rectangle in pixel value */
+unsigned long rop2)   /* ROP value */
+{
+    unsigned long nDirection, de_ctrl, bytePerPixel;
+    long opSign;
+
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    nDirection = LEFT_TO_RIGHT;
+    opSign = 1;    /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
+    bytePerPixel = bpp/8;
+    de_ctrl = 0;
+
+    /* If source and destination are the same surface, need to check for overlay cases */
+    if (sBase == dBase && sPitch == dPitch)
+    {
+        /* Determine direction of operation */
+        if (sy < dy)
+        {
+            /* +----------+
+               |S         |
+               |   +----------+
+               |   |      |   |
+               |   |      |   |
+               +---|------+   |
+                   |         D|
+                   +----------+ */
+    
+            nDirection = BOTTOM_TO_TOP;
+        }
+        else if (sy > dy)
+        {
+            /* +----------+
+               |D         |
+               |   +----------+
+               |   |      |   |
+               |   |      |   |
+               +---|------+   |
+                   |         S|
+                   +----------+ */
+    
+            nDirection = TOP_TO_BOTTOM;
+        }
+        else
+        {
+            /* sy == dy */
+    
+            if (sx <= dx)
+            {
+                /* +------+---+------+
+                   |S     |   |     D|
+                   |      |   |      |
+                   |      |   |      |
+                   |      |   |      |
+                   +------+---+------+ */
+    
+                nDirection = RIGHT_TO_LEFT;
+            }
+            else
+            {
+                /* sx > dx */
+    
+                /* +------+---+------+
+                   |D     |   |     S|
+                   |      |   |      |
+                   |      |   |      |
+                   |      |   |      |
+                   +------+---+------+ */
+    
+                nDirection = LEFT_TO_RIGHT;
+            }
+        }
+    }
+
+    if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT))
+    {
+        sx += width - 1;
+        sy += height - 1;
+        dx += width - 1;
+        dy += height - 1;
+        opSign = (-1);
+    }
+
+    /* Note:
+       DE_FOREGROUND are DE_BACKGROUND are don't care.
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set ddk768_deSetTransparency().
+    */
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, sBase);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+    
+#ifdef ENABLE_192_BYTES_PATCH
+    /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. 
+       The Version AA also have this problem on higher clock with 32-bit memory data bus, 
+       therefore, it needs to be enabled here. 
+       In version AA, the problem happens on the following configurations:
+        1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp
+        2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp.
+       Somehow, the problem does not appears in 64-bit memory setting.
+     */
+
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            ddk768_deWaitForNotBusy();
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+                FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+                ((nDirection == RIGHT_TO_LEFT) ? 
+                FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
+                : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
+                FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+            POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+
+            if (xChunk == width) break;
+
+            sx += (opSign * xChunk);
+            dx += (opSign * xChunk);
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        ddk768_deWaitForNotBusy();
+
+        POKE_32(DE_SOURCE,
+            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+            FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+            FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+            ((nDirection == RIGHT_TO_LEFT) ? 
+            FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
+            : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
+            FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+        POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+    }
+
+    return 0;
+}
+#if 0
+
+/*
+ * System Memory to Video Memory data transfer.
+ * Only works in D, S, ~D, and ~S ROP.
+ */
+long ddk768_deSystemMem2VideoMemBusMasterBlt(
+    unsigned char *pSBase,  /* Address of source in the system memory.
+                               The memory must be a continuous physical address. */
+    unsigned long sPitch,   /* Pitch value of source surface in BYTE */
+    unsigned long sx,
+    unsigned long sy,       /* Starting coordinate of source surface */
+    unsigned long dBase,    /* Address of destination in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectangle in pixel value */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long de_ctrl, bytePerPixel;
+    unsigned long value, pciMasterBaseAddress;
+    long opSign;
+
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    bytePerPixel = bpp/8;
+    de_ctrl = 0;
+
+    /* Note:
+       DE_FOREGROUND are DE_BACKGROUND are don't care.
+       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set ddk768_deSetTransparency().
+    */
+
+    /* 2D Source Base.
+       It is an address offset (128 bit aligned) from the given PCI Master base address
+    */
+    /* Set 2D Source Base Address */
+    value = FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, (unsigned long)pSBase);        
+    pciMasterBaseAddress = ((unsigned long)pSBase & 0xFC000000) >> 24;
+    POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress));
+    POKE_32(DE_WINDOW_SOURCE_BASE, value);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/bytePerPixel)));
+
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+    
+#ifdef ENABLE_192_BYTES_PATCH
+    /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. 
+       The Version AA also have this problem on higher clock with 32-bit memory data bus, 
+       therefore, it needs to be enabled here. 
+       In version AA, the problem happens on the following configurations:
+        1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp
+        2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp.
+       Somehow, the problem does not appears in 64-bit memory setting.
+     */
+
+    /* Workaround for 192 byte requirement when ROP is not COPY */
+    if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192))
+    {
+        /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */
+        unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */
+        
+        //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel));
+
+        while (1)
+        {
+            ddk768_deWaitForNotBusy();
+            POKE_32(DE_SOURCE,
+                FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+                FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+                
+            POKE_32(DE_DESTINATION,
+                FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+                FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+                FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+                
+            POKE_32(DE_DIMENSION,
+                FIELD_VALUE(0, DE_DIMENSION, X,    xChunk) |
+                FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+            de_ctrl = 
+                FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+                FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+                FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+                FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+                FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+            POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+
+            if (xChunk == width) break;
+
+            sx += xChunk;
+            dx += xChunk;
+            width -= xChunk;
+
+            if (xChunk > width)
+            {
+                /* This is the last chunk. */
+                xChunk = width;
+            }
+        }
+    }
+    else
+#endif
+    {
+        ddk768_deWaitForNotBusy();
+
+        POKE_32(DE_SOURCE,
+            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
+            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));
+        POKE_32(DE_DESTINATION,
+            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
+            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+        POKE_32(DE_DIMENSION,
+            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+        de_ctrl = 
+            FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+            FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+            FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+            FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+            FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+        POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+    }
+
+    return 0;
+}
+#endif
+/* 
+ * System memory to Video memory data transfer
+ * Note: 
+ *         We also call it HOST Blt.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk768_deSystemMem2VideoMemBlt(
+    unsigned char *pSrcbuf, /* pointer to source data in system memory */
+    long srcDelta,          /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */
+    unsigned long dBase,    /* Address of destination: offset in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectange in pixel value */
+    unsigned long rop2      /* ROP value */
+)
+{
+    unsigned long bytePerPixel;
+    unsigned long ulBytesPerScan;
+    unsigned long ul8BytesPerScan;
+    unsigned long ulBytesRemain;
+    unsigned long de_ctrl = 0;
+    unsigned char ajRemain[8];
+    long i, j;
+
+    bytePerPixel = bpp/8;
+
+    /* HOST blt data port must take multiple of 8 bytes as input.
+       If the source width does not match that requirement,
+       we need to split it into two portions. The first portion
+       is 8 byte multiple. The 2nd portion is the remaining bytes.
+       The remaining bytes will be buffered to an 8 byte array and
+       and send it to the host blt data port.
+    */
+    //ulBytesPerScan = width * bpp / 8;
+    ulBytesPerScan = width  / 8;
+    ul8BytesPerScan = ulBytesPerScan & ~7;
+    ulBytesRemain = ulBytesPerScan & 7;
+
+    /* Program 2D Drawing Engine */
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    /* 2D Source Base.
+       Use 0 for HOST Blt.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, 0);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Note: For 2D Source in Host Write, only X_K1 field is needed, and Y_K2 field is not used.
+             For 1 to 1 bitmap transfer, use 0 for X_K1 means source alignment from byte 0. */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_SOURCE, X_K1, 0)       |
+        FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+        
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+
+    de_ctrl = 
+        FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
+        FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
+        FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+        FIELD_SET(0, DE_CONTROL, HOST, COLOR)         |
+        FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+
+    /* Write bitmap/image data (line by line) to 2D Engine data port */
+    for (i = 0; i < height; i++)
+    {
+        /* For each line, send the data in chunks of 4 bytes. */
+        for (j=0; j < (ul8BytesPerScan/4);  j++)
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4)));
+
+        if (ulBytesRemain)
+        {
+            memcpy(ajRemain, pSrcbuf+ul8BytesPerScan, ulBytesRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(ajRemain+4));
+        }
+
+        pSrcbuf += srcDelta;
+    }
+
+    return 0;
+}
+
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is monochrome image in system memory.
+ * This function expands the monochrome data to color image in video memory.
+ */
+long ddk768_deSystemMem2VideoMemMonoBlt(
+unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
+long srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
+unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2)     /* ROP value */
+{
+    unsigned long bytePerPixel;
+    unsigned long ulBytesPerScan;
+    unsigned long ul4BytesPerScan;
+    unsigned long ulBytesRemain;
+    unsigned long de_ctrl = 0;
+    unsigned char ajRemain[4];
+    long i, j;
+
+    bytePerPixel = bpp/8;
+
+    startBit &= 7; /* Just make sure the start bit is within legal range */
+    ulBytesPerScan = (width + startBit + 7) / 8;
+    ul4BytesPerScan = ulBytesPerScan & ~3;
+    ulBytesRemain = ulBytesPerScan & 3;
+
+    if (ddk768_deWaitForNotBusy() != 0)
+    {
+        /* The 2D engine is always busy for some unknown reason.
+           Application can choose to return ERROR, or reset it and
+           continue the operation.
+        */
+
+        return -1;
+
+        /* or */
+        /* ddk768_deReset(); */
+    }
+
+    /* 2D Source Base.
+       Use 0 for HOST Blt.
+    */
+    POKE_32(DE_WINDOW_SOURCE_BASE, 0);
+
+    /* 2D Destination Base.
+       It is an address offset (128 bit aligned) from the beginning of frame buffer.
+    */
+    POKE_32(DE_WINDOW_DESTINATION_BASE, dBase);
+
+    /* Program pitch (distance between the 1st points of two adjacent lines).
+       Note that input pitch is BYTE value, but the 2D Pitch register uses
+       pixel values. Need Byte to pixel convertion.
+    */
+    POKE_32(DE_PITCH,
+        FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
+        FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel));
+
+    /* Screen Window width in Pixels.
+       2D engine uses this value to calculate the linear address in frame buffer for a given point.
+    */
+    POKE_32(DE_WINDOW_WIDTH,
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
+        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
+
+    /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
+             For mono bitmap, use startBit for X_K1. */
+    POKE_32(DE_SOURCE,
+        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE)       |
+        FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit));
+
+    POKE_32(DE_DESTINATION,
+        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
+        FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
+        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));
+
+    POKE_32(DE_DIMENSION,
+        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
+        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+    POKE_32(DE_FOREGROUND, fColor);
+    POKE_32(DE_BACKGROUND, bColor);
+    
+    /* Set the pixel format of the destination */
+    ddk768_deSetPixelFormat(bpp);
+
+    de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
+              FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
+              FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+              FIELD_SET(0, DE_CONTROL, HOST, MONO)          |
+              FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+    POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency());
+
+    /* Write MONO data (line by line) to 2D Engine data port */
+    for (i=0; i<height; i++)
+    {
+        /* For each line, send the data in chunks of 4 bytes */
+        for (j=0; j<(ul4BytesPerScan/4); j++)
+        {
+            POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4)));
+        }
+
+        if (ulBytesRemain)
+        {
+            memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
+            POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain);
+        }
+
+        pSrcbuf += srcDelta;
+    }
+
+    return 0;
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.h
new file mode 100644
index 000000000000..07241143508b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_2d.h
@@ -0,0 +1,503 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  2d.h --- SM750/SM718 DDK 
+*  This file contains the definitions for the 2D Engine interrupt.
+* 
+*******************************************************************/
+#ifndef _DDK768_2D_H_
+#define _DDK768_2D_H_
+
+#define POKE_8(address, value)          pokeRegisterByte(address, value)
+#define POKE_16(address, value)         pokeRegisterWord(address, value)
+#define POKE_32(address, value)         pokeRegisterDWord(address, value)
+#define PEEK_8(address)                 peekRegisterByte(address)
+#define PEEK_16(address)                peekRegisterWord(address)
+#define PEEK_32(address)                peekRegisterDWord(address)
+
+/* Rotation Direction */
+typedef enum _rotate_dir_t
+{
+    ROTATE_NORMAL = 0,
+    ROTATE_90_DEGREE,
+    ROTATE_180_DEGREE,
+    ROTATE_270_DEGREE
+}
+rotate_dir_t;
+
+/*
+ * 2D Engine Initialization.
+ * This function must be called before other 2D functions.
+ * Assumption: A specific vidoe mode has been properly set up.
+ */
+void ddk768_deInit(void);
+
+/*
+ * Reset 2D engine by 
+ * 1) Aborting the current 2D operation.
+ * 2) Re-enable 2D engine to normal state.
+ */
+void ddk768_deReset(void);
+ 
+/*
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long ddk768_deWaitForNotBusy(void);
+
+/* deWaitIdle() function.
+ *
+ * This function is same as ddk768_deWaitForNotBusy(), except application can
+ * input the maximum number of times that this function will check 
+ * the idle register.
+ *
+ * Its usage is mainly for debugging purpose.
+ *
+ * Wait until 2D engine is not busy.
+ * All 2D operations are recommand to check 2D engine idle before start.
+ *
+ * Return: 0 = return because engine is idle and normal.
+ *        -1 = return because time out (2D engine may have problem).
+ */
+long deWaitIdle(unsigned long i);
+
+/*
+ * This function enable/disable clipping area for the 2d engine.
+ * Note that the clipping area is always rectangular.
+ * 
+ */
+long ddk768_deSetClipping(
+unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */
+unsigned long x1,     /* x1, y1 is the upper left corner of the clipping area */
+unsigned long y1,     /* Note that the region includes x1 and y1 */
+unsigned long x2,     /* x2, y2 is the lower right corner of the clippiing area */
+unsigned long y2);    /* Note that the region will not include x2 and y2 */
+
+/* 
+ * Function description:
+ * When transparency is enable, the blt engine compares each pixel value 
+ * (either source or destination) with DE_COLOR_COMPARE register.
+ * If match, the destination pixel will NOT be updated.
+ * If not match, the destination pixel will be updated.
+ */
+long ddk768_deSetTransparency(
+unsigned long enable,     /* 0 = disable, 1 = enable transparency feature */
+unsigned long tSelect,    /* 0 = compare source, 1 = compare destination */
+unsigned long tMatch,     /* 0 = Opaque mode, 1 = transparent mode */
+unsigned long ulColor);   /* Color to compare. */
+
+/*
+ * This function uses 2D engine to fill a rectangular area with a specific color.
+ * The filled area includes the starting points.
+ */
+long ddk768_deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/
+unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+unsigned long x,
+unsigned long y,      /* Upper left corner (X, Y) of rectangle in pixel value */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long color,  /* Color to be filled */
+unsigned long rop2);  /* ROP value */
+
+/*
+ * Video Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk768_deVideoMem2VideoMemBlt(
+unsigned long sBase,  /* Address of source: offset in frame buffer */
+unsigned long sPitch, /* Pitch value of source surface in BYTE */
+unsigned long sx,
+unsigned long sy,     /* Starting coordinate of source surface */
+unsigned long dBase,  /* Address of destination: offset in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height, /* width and height of rectange in pixel value */
+unsigned long rop2);  /* ROP value */
+#if 0
+/*
+ * System Memory to Video Memory data transfer.
+ * Note: 
+ *        It works whether the Video Memroy is off-screeen or on-screen.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk768_deSystemMem2VideoMemBusMasterBlt(
+    unsigned char *pSBase,  /* Address of source: offset in frame buffer */
+    unsigned long sPitch,   /* Pitch value of source surface in BYTE */
+    unsigned long sx,
+    unsigned long sy,       /* Starting coordinate of source surface */
+    unsigned long dBase,    /* Address of destination: offset in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width, 
+    unsigned long height,   /* width and height of rectangle in pixel value */
+    unsigned long rop2      /* ROP value */
+);
+#endif
+/* 
+ * System memory to Video memory data transfer
+ * Note: 
+ *         We also call it HOST Blt.
+ *        This function is a one to one transfer without stretching or 
+ *        mono expansion.
+ */
+long ddk768_deSystemMem2VideoMemBlt(
+unsigned char *pSrcbuf, /* pointer to source data in system memory */
+long srcDelta,          /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long rop2);    /* ROP value */
+
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is monochrome image in system memory.
+ * This function expands the monochrome data to color image in video memory.
+ */
+long ddk768_deSystemMem2VideoMemMonoBlt(
+unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */
+long srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
+unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+unsigned long dBase,    /* Address of destination: offset in frame buffer */
+unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+unsigned long bpp,      /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,       /* Starting coordinate of destination surface */
+unsigned long width, 
+unsigned long height,   /* width and height of rectange in pixel value */
+unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);    /* ROP value */
+
+#if 0
+/*
+ * System memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in System memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deSystemMem2VideoMemMonoBusMasterBlt(
+    unsigned char *pSBase,  /* Address of mono-chrome source data in frame buffer */
+    unsigned long sPitch,   /* Pitch value (in bytes) of the source buffer. */
+    unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
+    unsigned long dBase,    /* Base address of destination in frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTE */
+    unsigned long bpp,      /* Color depth of destination surface */
+    unsigned long dx,
+    unsigned long dy,       /* Starting coordinate of destination surface */
+    unsigned long width,    /* width of mono-chrome picture in pixel value */
+    unsigned long height,   /* height of mono-chrome picture in pixel value */
+    unsigned long fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
+    unsigned long bColor,   /* Background color (corresponding to a 0 in the monochrome data */
+    unsigned long rop2      /* ROP value */
+);
+#endif
+
+/*
+ * This function cache font table into frame buffer.
+ *
+ * Inputs:
+ *      Pointer to font table in system memory.
+ *      Charcter size in byte: How many bytes are used to store the font for one characer.
+ *      As an example: For 8x8 mono font, the size is 8 bytes; 
+ *                     For 8x16 mono font, the size is 16 bytes.
+ *                     For 16x32 mono font, the size is 64 bytes.
+ *      Number of characters in the font table.
+ *      Pointer to location of frame buffer to store the font: This is an offset from the beginning of frame buffer.
+ *  
+ * Rules for storing fonts in off-screen.
+ *     1) Base address of font table must be 16 byte (or 128 bit) aligned.
+ *     2) Each font character must be stored in a 16 byte (128 bit) aligned
+ *        location.
+ *
+ */
+long deCacheFontToFrameBuffer(
+unsigned char *fontTable,   /* Pointer to font table in system memory */
+unsigned long sizeOfChar,   /* How many bytes for one monochrome character */
+unsigned long numberOfChar, /* Number of characters in the font table */
+unsigned long fbAddr);      /* Destination in Video memory to store the font */
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * Source is the starting location of monochrome image in Video memory.
+ * This function expands the monochrome data to color image.
+ *
+ * Note:
+ * This fnnction can be used to diaplay a mono-font charater to the screen.
+ * Input source points to the starting location of the font character.
+ */
+long deVideoMem2VideoMemMonoBlt(
+unsigned long sBase,  /* Address of mono-chrome source data in frame buffer */
+unsigned long dBase,  /* Base address of destination in frame buffer */
+unsigned long dPitch, /* Pitch value of destination surface in BYTE */
+unsigned long bpp,    /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,     /* Starting coordinate of destination surface */
+unsigned long width,  /* width of mono-chrome picture in pixel value */
+unsigned long height, /* height of mono-chrome picture in pixel value */
+unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);  /* ROP value */
+
+/*
+ * Video memory to Video memory monochrome expansion.
+ * 
+ * Difference between this function and deVideoMem2VideoMemMonoBlt():
+ * 1) Input is base address of the whole font table.
+ * 2) An extra input about which character in the font table to display.
+ * 3) This function demos how to use registers DE_SOURCE and
+ *    DE_WINDOW_WIDTH, where they are set to 0 in deVideoMem2VideoMemMonoBlt().
+ */
+long deFontCacheTblMonoBlt(
+unsigned long fontTblBase,/* Base address of monochrome font table in frame buffer */
+unsigned long fontNumber, /* Which character in the font table, starting from 0 */
+unsigned long dBase,      /* Base address of destination in frame buffer */
+unsigned long dPitch,     /* Pitch value of destination surface in BYTE */
+unsigned long bpp,        /* Color depth of destination surface */
+unsigned long dx,
+unsigned long dy,         /* Starting coordinate of destination surface */
+unsigned long width,      /* width of each monochrome font in pixel value */
+unsigned long height,     /* height of each monochrome font in pixel value */
+unsigned long fColor,     /* Foreground color (corresponding to a 1 in the monochrome data */
+unsigned long bColor,     /* Background color (corresponding to a 0 in the monochrome data */
+unsigned long rop2);      /* ROP value */
+
+/*
+ * Stretch Blt.
+ * 
+ * The stretch blt is done by using the CSC engine.
+ */
+long deStretchBlt(
+    unsigned long sBase,    /* Source Base address */
+    unsigned long sPitch,   /* Source pitch value in bytes */
+    unsigned long sbpp,     /* Source bits per pixel */
+    unsigned long sx,       /* Source x coordinate */            
+    unsigned long sy,       /* Source y coordinate */
+    unsigned long sWidth,   /* Width of source in pixel */
+    unsigned long sHeight,  /* Height of source in lines */
+    unsigned long dBase,    /* Destination base address */
+    unsigned long dPitch,   /* Destination pitch value in bytes */
+    unsigned long dbpp,     /* Destination bits per pixel */
+    unsigned long dx,       /* Destination x coordinate */
+    unsigned long dy,       /* Destination y coordinate */
+    unsigned long dWidth,   /* Width of the destination display */
+    unsigned long dHeight   /* Height of the destination display */
+);
+
+/*
+ * Rotation Blt.
+ * 
+ * This function rotates an image to the screen based on the given rotation direction
+ * (0, 90, 180, or 270 degree).
+ * 
+ */
+long deVideoMem2VideoMemRotateBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long width,            /* Width  of un-rotated image in pixel value */
+    unsigned long height,           /* Height of un-rotated image in pixel value */
+    rotate_dir_t rotateDirection,   /* Direction of the rotation */
+    unsigned long repeatEnable,     /* Enable repeat rotation control where the
+                                       drawing engine is started again every vsync */
+    unsigned long rop2              /* ROP control */
+);
+
+/* 
+ * Function to draw a vertical line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deVerticalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/* 
+ * Function to draw a horizontal line.
+ *
+ * Note:
+ *      This function is using Short Stroke line
+ */
+long deHorizontalLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,        /* Starting X Coordinate */
+    unsigned long y,        /* Starting Y Coordinate */
+    unsigned long length,   /* Length of the line */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/* 
+ * Function to draw a line.
+ *
+ * Note:
+ *      This function is using Short Stroke Command for Vertical, Horizontal, and 
+ *      Diagonal line. Other line are drawn using the Line Draw Command.
+ */
+long deLine(
+    unsigned long dBase,    /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,   /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,      /* Color depth of destination surface: 8, 16 or 32 */
+    long x0,                /* Starting X Coordinate */
+    long y0,                /* Starting Y Coordinate */
+    long x1,                /* Ending X Coordinate */
+    long y1,                /* Ending Y Coordinate */
+    unsigned long color,    /* Color of the line */
+    unsigned long rop2      /* ROP value */
+);
+
+/*
+ * Alpha Blend Blt.
+ * 
+ * This function blends the source with the destination image.
+ */
+long deVideoMem2VideoMemAlphaBlendBlt(
+    unsigned long sBase,            /* Source Base Address */
+    unsigned long sPitch,           /* Source pitch */
+    unsigned long sx,               /* X Coordinate of the source */
+    unsigned long sy,               /* Y Coordinate of the source */
+    unsigned long sWidth,           /* Source Width */
+    unsigned long sHeight,          /* Source Height */
+    unsigned long dBase,            /* Destination Base Address */
+    unsigned long dPitch,           /* Destination pitch */
+    unsigned long bpp,              /* Color depth of destination surface */
+    unsigned long dx,               /* X Coordinate of the destination */ 
+    unsigned long dy,               /* Y Coordinate of the destination */
+    unsigned long dHeight,          /* Destination Height (only height stretch is supported) */
+    unsigned long alphaValue,       /* Alpha value for Alpha Blend*/
+    unsigned long rop2              /* ROP control */
+);
+
+#if 0   /* These RLE functions are not working. */
+/* 
+ * Function to draw a line using RLE line strip method.
+ */
+long deStartLineStrip(
+    unsigned long dBase,        /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch,       /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,          /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,            /* X Coordinate */
+    unsigned long y,            /* Y Coordinate */
+    unsigned long length,       /* Length of the line */
+    unsigned long lineCounter,  /* Line Counter */
+    unsigned long direction,    /* Direction:   0 - Left to Right
+                                                1 - Right to Left
+                                                2 - Top to Bottom
+                                                3 - Bottom to Top
+                                */
+    unsigned long color,        /* Color of the line */
+    unsigned long rop2          /* ROP value */
+);
+
+/* 
+ * Function to continue drawing a line using RLE line strip method.
+ */
+long deNextLineStrip(
+    unsigned long length,       /* Line strip length */
+    unsigned long lineCounter   /* Line Counter */
+);
+
+/* 
+ * Function to stop the RLE line strip drawing.
+ * This function has to be called to end the Line Strip drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long deStopLineStrip();
+#endif
+
+
+/*
+ * This function uses 2D engine to draw a trapezoid with a specific color.
+ * The filled area includes the starting points.
+ */
+long ddk768_deStartTrapezoidFill(
+    unsigned long dBase,  /* Base address of destination surface counted from beginning of video frame buffer */
+    unsigned long dPitch, /* Pitch value of destination surface in BYTES */
+    unsigned long bpp,    /* Color depth of destination surface: 8, 16 or 32 */
+    unsigned long x,
+    unsigned long y,      /* Starting (X, Y) coordinate inside the polygon to be filled */
+    unsigned long length, /* Length of the line */
+    unsigned long color,  /* Color to be filled */
+    unsigned long rop2);
+
+/* 
+ * Function to continue drawing a line using Trapezoid Fill method.
+ */
+long ddk768_deNextTrapezoidFill(
+    unsigned long x,            /* Starting X location. */
+    unsigned long length        /* Line length */
+);
+
+/* 
+ * Function to stop the Trapezoid Fill drawing.
+ * This function has to be called to end the Trapezoid Fill drawing.
+ * Otherwise, the next 2D function might still use this function.
+ */
+long ddk768_deStopTrapezoidFill(void);
+
+/*
+ * This function clears the RAW interrupt status of DE.
+ * 
+ * When Drawing Engine completes, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different sessions of countdown.
+ * 
+ */
+void deClearRawInt(void);
+
+/* 
+ * This function returns the INT mask for Drawing Engine.
+ *
+ */
+unsigned long deIntMask(void);
+
+/*
+ * This is a reference sample showing how to implement ISR for Drawing Engine.
+ * It provides information on how to use the interrupt registers.
+ * 
+ * Refer to Apps\2d\tst2d.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+void /*ISR_FUNC*/ deIsrTemplate(void);
+
+#endif /* _2D_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.c
new file mode 100644
index 000000000000..62e9ccb87952
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.c
@@ -0,0 +1,220 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CHIP.C --- SMI DDK 
+*  This file contains the source code for the mode table.
+* 
+*******************************************************************/
+#include "ddk768_reg.h"
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_clock.h"
+
+#include "ddk768_help.h"
+
+
+/* Size of SM768 MMIO and memory */
+#define SMI_MMIO_SIZE_SM768       (2<<20)    /* 2M of MMIO space */
+#define SMI_MEMORY_SIZE_SM768     (128<<20)  
+
+
+unsigned int ddk768_getCrystalType(void)
+{
+	unsigned int strapPin;
+		
+    /* If bit 12 of strap pin is 1, the crystal must be 24.576M */
+	strapPin = FIELD_GET(peekRegisterDWord(STRAP_PINS), STRAP_PINS, CRYSTAL_CONFIG);
+    
+    if(strapPin == STRAP_PINS_CRYSTAL_CONFIG_24576){
+		printk("Use 24.576MHZ Crystal\n");
+		return 1;
+    }else{
+		printk("Use 24MHZ Crystal\n");
+		return 0;
+	}
+}
+
+unsigned int ddk768_getPixelType(void)
+{
+	unsigned int strapPin;
+		
+    /* If bit 10 of strap pin is 1, the pixel clock will be half */
+	strapPin = FIELD_GET(peekRegisterDWord(STRAP_PINS), STRAP_PINS, PIXEL_CONFIG);
+    
+    if(strapPin == STRAP_PINS_PIXEL_CONFIG_HALF){
+		return 1;
+    }else{
+		return 0;
+	}
+}
+
+
+
+/*
+ * This function returns frame buffer memory size in Byte units.
+ */
+unsigned long ddk768_getFrameBufSize()
+{
+#if 1
+	return SMI_MEMORY_SIZE_SM768;
+#else
+    unsigned long strapPin, ddrController, rValue;
+
+    strapPin = FIELD_GET(peekRegisterDWord(STRAP_PINS), STRAP_PINS, MEM_SIZE);
+    ddrController = peekRegisterDWord(DDR_CONTROL);
+
+    switch(strapPin)
+    {
+        case STRAP_PINS_MEM_SIZE_512M:
+        pokeRegisterDWord(DDR_CONTROL, ddrController | FIELD_SET(0, DDR_CONTROL, SIZE, 512M));
+        rValue = MB(512);
+        break;
+
+        case STRAP_PINS_MEM_SIZE_1024M:
+        pokeRegisterDWord(DDR_CONTROL, ddrController | FIELD_SET(0, DDR_CONTROL, SIZE, 1024M));
+        rValue = MB(1024);
+        break;
+
+        default: /* default size of 256M. Don't need to do anything */
+        rValue = MB(256);
+        break;
+    }
+    return(rValue);
+#endif
+}
+
+/*
+ * This function returns the logical chip type defined in chip.h
+ * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or
+ * SM_UNKNOWN.
+ */
+logical_chip_type_t ddk768_getChipType()
+{
+
+    logical_chip_type_t chip;
+
+
+    chip = SM768;
+
+
+    return chip;
+}
+
+/*
+ * Return a char string name of the current chip.
+ * It's convenient for application need to display the chip name.
+ */
+char *ddk768_getChipTypeString()
+{
+    char * chipName;
+
+    switch(ddk768_getChipType())
+    {
+        case SM768:
+            chipName = "SM768";
+            break;
+        default:
+            chipName = "Unknown";
+            break;
+    }
+
+    return chipName;
+}
+
+/*
+ * Initialize a single chip and environment according to input parameters.
+ *
+ * Input: initchip_param_t structure.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ */
+long ddk768_initChipParamEx(initchip_param_t * pInitParam)
+{
+    unsigned long ulReg;
+
+    /* Check if we know this chip */
+    if (ddk768_getChipType() == SM_UNKNOWN)
+        return -1;
+
+    if (pInitParam->setAllEngOff == 1)
+    {
+        ulReg = peekRegisterDWord(VIDEO_DISPLAY_CTRL);
+        ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); 
+        pokeRegisterDWord(VIDEO_DISPLAY_CTRL, ulReg); /* Channel 0 */
+        pokeRegisterDWord(VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */
+
+        /* Disable alpha plane, if a former application left it on */
+        ulReg = peekRegisterDWord(ALPHA_DISPLAY_CTRL);
+        ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); 
+        pokeRegisterDWord(ALPHA_DISPLAY_CTRL, ulReg); /* Channel 0 */
+        pokeRegisterDWord(ALPHA_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */
+
+        /* Disable hardware cursor, if a former application left it on */
+        ulReg = peekRegisterDWord(HWC_CONTROL);
+        ulReg = FIELD_SET(ulReg, HWC_CONTROL, MODE, DISABLE); 
+        pokeRegisterDWord(HWC_CONTROL, ulReg); /* Channel 0 */
+        pokeRegisterDWord(HWC_CONTROL+CHANNEL_OFFSET, ulReg); /* Channel 1 */
+    }
+
+    /* We can add more initialization as needed. */
+
+        
+    return 0;
+}
+
+/*
+ * Initialize chip with default parameters.
+ *
+ * Input: none.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ */
+long ddk768_initChip()
+{
+    initchip_param_t initParam;
+    
+    /* Initialize the chip with some default parameters */
+
+    initParam.setAllEngOff = 1;
+    
+    
+    return(ddk768_initChipParamEx(&initParam));
+}
+
+#if 0
+#define PHY_STATUS(A, B)\
+    peekRegisterDWord(A) & B
+/*
+    Program DDR PHY register PIR to do DDR training.
+    Other parameters for training are assumed well set before calling here.
+*/
+void ddrTraining()
+{
+    unsigned long ulTmp;
+
+    ulTmp = peekRegisterDWord(CLOCK_ENABLE);
+
+    //Shut off all active components, espically ARM
+    pokeRegisterDWord(CLOCK_ENABLE, 0);
+
+    pokeRegisterDWord(PIR, 0);
+    pokeRegisterDWord(PIR, 0x1ff);
+
+    // May take few cycles for PGSR.IDONE = 0 after kick off DDR training.
+    while((PHY_STATUS(PGSR, 0x00000001))){}
+
+    // Wait until DDR training completed
+    while(!(PHY_STATUS(PGSR, 0x00000001))){}
+
+    //Restore clocks
+    pokeRegisterDWord(CLOCK_ENABLE, ulTmp);
+}
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.h
new file mode 100644
index 000000000000..3577e4f8fd60
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_chip.h
@@ -0,0 +1,90 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CHIP.H --- SMI DDK 
+*  This file contains the source code for the SM750/SM718 chip.
+* 
+*******************************************************************/
+#ifndef _DDK768_CHIP_H_
+#define _DDK768_CHIP_H_
+
+/* This is all the chips recognized by this library */
+typedef enum _logical_chip_type_t
+{
+    SM_UNKNOWN = 0,
+    SM768 = 1
+}
+logical_chip_type_t;
+
+/* input struct to initChipParam() function */
+typedef struct _initchip_param_t
+{
+
+    unsigned short setAllEngOff; /* 0 = leave all engine state untouched.
+                                    1 = make sure they are off: 2D, Overlay,
+                                    video alpha, alpha, hardware cursors
+                                 */
+
+    /* More initialization parameter can be added if needed */
+}
+initchip_param_t;
+
+
+
+unsigned int ddk768_getCrystalType(void);
+unsigned int ddk768_getPixelType(void);
+
+
+
+/*
+ * This function returns frame buffer memory size in Byte units.
+ */
+unsigned long ddk768_getFrameBufSize(void);
+
+
+
+/*
+ * This function returns the logical chip type defined in chip.h
+ * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or
+ * SM_UNKNOWN.
+ */
+logical_chip_type_t ddk768_getChipType(void);
+
+/*
+ * Return a char string name of the current chip.
+ * It's convenient for application need to display the chip name.
+ */
+char * ddk768_getChipTypeString(void);
+
+/*
+ * Initialize a single chip and environment according to input parameters.
+ *
+ * Input: initchip_param_t structure.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ *
+ */
+long ddk768_initChipParamEx(initchip_param_t * pInitParam);
+
+/*
+ * Initialize the chip with default parameters.
+ *
+ * Input: none.
+ *
+ * Return: 0 (or NO_ERROR) if successful.
+ *        -1 if fail.
+ */
+long ddk768_initChip(void);
+
+#define MB(x) (x<<20) /* Macro for Mega Bytes */
+
+
+
+
+#endif /* _CHIP_H_ */
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.c
new file mode 100644
index 000000000000..ba575abcd6e3
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.c
@@ -0,0 +1,182 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2016 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CLOCK.C --- Falcon  DDK 
+*  This file contains source code for the Falcon  PLL's
+* 
+*******************************************************************/
+#include "ddk768_reg.h"
+
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_clock.h"
+#include "ddk768_mode.h"
+
+
+#include "ddk768_help.h"
+#include "ddk768_helper.h"
+
+/*
+ * A local function to calculate the output frequency of a given PLL structure.
+ *
+ */
+unsigned long ddk768_calcPLL(pll_value_t *pPLL)
+{
+    unsigned long pllClk, vcoPower;
+    unsigned long fifteenPower = ddk768_twoToPowerOfx(15); /* 2^15 */
+
+    /* Convert everything in Khz range in order to avoid calculation overflow */
+    pPLL->inputFreq /= 1000;
+    
+    /* Work out 2 to the power of (VCO + 1) */
+    vcoPower = ddk768_twoToPowerOfx(pPLL->VCO + 1);
+    
+    pllClk = (pPLL->inputFreq * pPLL->INT + pPLL->inputFreq * pPLL->FRAC / fifteenPower) / vcoPower;
+    
+    /* Restore input frequency from Khz to hz unit */
+    pPLL->inputFreq *= 1000;
+    pllClk *= 1000;
+
+    return pllClk;
+}
+
+/*
+ * Given a requested clock frequency, this function calculates the 
+ * best INT, FRAC, VCO and BS values for the PLL.
+ * 
+ * Input: Requested pixel clock in Hz unit.
+ *        The followiing fields of PLL has to be set up properly:
+ *        pPLL->inputFreq.
+ *
+ * Output: Update the PLL structure with the proper values
+ * Return: The actual clock in Hz that the PLL is able to set up.
+ *
+ */
+unsigned long ddk768_calcPllValue(
+unsigned long ulRequestClk, /* Required pixel clock in Hz unit */
+pll_value_t *pPLL           /* Structure to hold the value to be set in PLL */
+)
+{
+
+		unsigned long INTEGER, FRAC, VCO,  diff, pllClk, vcoPower, tempRequestClk;
+		unsigned long bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */
+		unsigned long fifteenPower = ddk768_twoToPowerOfx(15); /* 2^15 */
+	
+		/* Init PLL structure to known states */
+		pPLL->INT = 0;
+		pPLL->FRAC = 0;
+		pPLL->VCO = 0;
+		pPLL->BS = 0;
+	
+		/* Convert everything in Khz range in order to avoid calculation overflow */
+		pPLL->inputFreq /= 1000;
+		tempRequestClk = ulRequestClk / 1000;
+	
+		/* If the requested clock is higher than 1 GHz, then set it to the maximum, which is
+		   1 GHz. */
+		if (tempRequestClk > MHz(1))
+			tempRequestClk = MHz(1);
+	
+		/* The maximum of VCO is 5. */
+		for (VCO=0; VCO<=5; VCO++)
+		{
+			/* Work out 2 to the power of (VCO + 1) */
+			vcoPower = ddk768_twoToPowerOfx(VCO + 1);
+	
+			INTEGER = tempRequestClk * vcoPower / pPLL->inputFreq;
+	
+			/* 28 <= INT <= 56 */
+			if ((INTEGER >= 28) && (INTEGER <=56))
+			{
+				/* FRAC = (requestClk * vcoPower / inputFreq - INT ) * (2^15)
+				  Use formula as following to avoid decimal calculation:
+				  FRAC = (requestClk * vcoPower - INT * inputFreq) * (2^15) / inputFreq
+				*/
+				FRAC = ((tempRequestClk * vcoPower) - (INTEGER * pPLL->inputFreq)) * fifteenPower / pPLL->inputFreq;
+	
+				/* FRAC field has 15 bits, reject value bigger than 15 bits */
+				if (FRAC < FRAC_MAX)
+				{
+					/* Calculate the actual clock for a given INT & FRAC */
+					pllClk = (pPLL->inputFreq * INTEGER + pPLL->inputFreq * FRAC / fifteenPower) / vcoPower;
+					
+					/* How much are we different from the requirement */
+					diff = ddk768_absDiff(pllClk, tempRequestClk);
+	
+					if (diff < bestDiff)
+					{
+						bestDiff = diff;
+	
+						/* Store INT and FRAC values */
+						pPLL->INT  = INTEGER;
+						pPLL->FRAC = FRAC;
+						pPLL->VCO = VCO;
+					}
+				}
+			}
+		}
+	
+		/* Calculate BS value */
+		if ((pPLL->INT >= 28) && (pPLL->INT < 35))
+		{
+			pPLL->BS = 0;
+		}
+		else if ((pPLL->INT >=35) && (pPLL->INT < 42))
+		{
+			pPLL->BS = 1;
+		}
+		else if ((pPLL->INT >= 42) && (pPLL->INT < 49))
+		{
+			pPLL->BS = 2;
+		}
+		else if ((pPLL->INT >= 49) && (pPLL->INT <= 56))
+		{
+			pPLL->BS = 3;
+		}
+		
+		/* Restore input frequency from Khz to hz unit */
+		pPLL->inputFreq *= 1000;
+#if 0	
+		/* Output debug information */
+		DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk));
+		DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, INT=%d, FRAC=%d, VCO=%d, BS=%d\n", 
+							pPLL->inputFreq, pPLL->INT, pPLL->FRAC, pPLL->VCO, pPLL->BS));
+#endif	
+		/* Return actual frequency that the PLL can set */
+		return ddk768_calcPLL(pPLL);
+
+    
+}
+
+/*
+ * Set up the corresponding bit field of the programmable PLL register.
+ *
+ * Input: Pointer to PLL structure with all values set up properly.
+ *
+ */
+unsigned long ddk768_formatPllReg(pll_value_t *pPLL)
+{
+
+     unsigned long ulPllReg = 0;
+
+    /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter
+       to work out the bit fields in the register.
+       On returning a 32 bit number, the value can be applied to any PLL in the calling function.
+    */
+    ulPllReg =
+        FIELD_SET(0, VCLK_PLL, FN, FRAC_MODE)
+      | FIELD_VALUE(0, VCLK_PLL, BS, pPLL->BS)      
+      | FIELD_VALUE(0, VCLK_PLL, VCO, pPLL->VCO)
+      | FIELD_VALUE(0, VCLK_PLL, INT, pPLL->INT)
+      | FIELD_VALUE(0, VCLK_PLL, FRAC, pPLL->FRAC);
+
+    return(ulPllReg);
+
+}
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.h
new file mode 100644
index 000000000000..a8e59634fdab
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_clock.h
@@ -0,0 +1,66 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2016 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CLOCK.H --- Falcon DDK 
+* 
+*******************************************************************/
+#ifndef _DDK768_CLOCK_H_
+#define _DDK768_CLOCK_H_
+
+#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */
+
+
+#define GHz(x) (x*1000000000)   //1000000000HZ  = 1(Ghz)
+#define FRAC_MAX    32768
+
+typedef struct pll_value_t
+{
+    unsigned long inputFreq; /* Input clock frequency to the PLL */
+    unsigned long INT;
+    unsigned long FRAC;
+    unsigned long VCO;
+    unsigned long BS;
+}
+pll_value_t;
+
+/*
+ * Given a requested clock frequency, this function calculates the 
+ * best INT, FRAC, VCO and BS values for the PLL.
+ * 
+ * Input: Requested pixel clock in Hz unit.
+ *        The followiing fields of PLL has to be set up properly:
+ *        pPLL->inputFreq.
+ *
+ * Output: Update the PLL structure with the proper values
+ * Return: The actual clock in Hz that the PLL is able to set up.
+ *
+ */
+unsigned long ddk768_calcPllValue(
+unsigned long ulRequestClk, /* Required pixel clock in Hz unit */
+pll_value_t *pPLL           /* Structure to hold the value to be set in PLL */
+);
+
+/*
+ * Set up the corresponding bit field of the programmable PLL register.
+ *
+ * Input: Pointer to PLL structure with all values set up properly.
+ *
+ */
+unsigned long ddk768_formatPllReg(pll_value_t *pPLL);
+
+/*
+    This funtion sets up pixel clock for Falcon FPGA.
+    Final product will have another PLL clock.
+*/
+
+long ddk768_setVclock(unsigned dispCtrl, unsigned long pixelClock);
+
+
+
+
+
+#endif /*_CLOCK_H_*/
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.c
new file mode 100644
index 000000000000..30a08028e1e7
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.c
@@ -0,0 +1,100 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  CURSOR.C --- Voyager GX SDK 
+*  This file contains the definitions for the Panel cursor functions.
+* 
+*******************************************************************/
+#include "ddk768.h"
+
+#include "ddk768_cursor.h"
+
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk768_initCursor(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+)
+{
+    /*
+     * 1. Set the cursor source address 
+     */
+    pokeRegisterDWord(
+        (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_ADDRESS : CHANNEL1_HWC_ADDRESS,
+        FIELD_VALUE(0, CHANNEL0_HWC_ADDRESS, ADDRESS, base));
+        
+    /*
+     * 2. Set the cursor color composition 
+     */
+    pokeRegisterDWord(
+        (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_COLOR_0 : CHANNEL1_HWC_COLOR_0, 
+        FIELD_VALUE(0, CHANNEL0_HWC_COLOR_0, RGB888, color1));
+
+    pokeRegisterDWord(
+        (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_COLOR_1 : CHANNEL1_HWC_COLOR_1, 
+        FIELD_VALUE(0, CHANNEL0_HWC_COLOR_1, RGB888, color2));
+
+}
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk768_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+)
+{  
+    unsigned long value;
+
+    /* Set the XY coordinate */
+    value = FIELD_VALUE(0, HWC_LOCATION, X, dx) |
+            FIELD_VALUE(0, HWC_LOCATION, Y, dy);
+    
+    /* Set the top boundary select either partially outside the top boundary
+       screen or inside */
+    if (topOutside)
+        value = FIELD_SET(value, HWC_LOCATION, TOP, OUTSIDE);
+    else         
+        value = FIELD_SET(value, HWC_LOCATION, TOP, INSIDE);
+
+    /* Set the left boundary select either partially outside the left boundary
+       screen or inside */
+    if (leftOutside)
+        value = FIELD_SET(value, HWC_LOCATION, LEFT, OUTSIDE);
+    else        
+        value = FIELD_SET(value, HWC_LOCATION, LEFT, INSIDE);
+
+    /* Set the register accordingly, either Panel cursor or CRT cursor */
+    pokeRegisterDWord((dispControl == CHANNEL0_CTRL) ? HWC_LOCATION : (HWC_LOCATION+CHANNEL_OFFSET), value);
+}
+
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk768_enableCursor(
+    disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long mode			/* Cursor type - 00 disable, 0x01 mask cursor, 0x02 mono, 0x03 alpha cursor */
+)
+{
+    unsigned long cursorRegister, value;
+
+    cursorRegister = (dispControl == CHANNEL0_CTRL) ? HWC_CONTROL : (HWC_CONTROL+CHANNEL_OFFSET);
+    
+	value = peekRegisterDWord(cursorRegister);
+    value = FIELD_VALUE(value, HWC_CONTROL, MODE, mode);
+    
+    pokeRegisterDWord(cursorRegister, value);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.h
new file mode 100644
index 000000000000..59afd2990675
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_cursor.h
@@ -0,0 +1,54 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  cursor.h --- SMI DDK 
+*  This file contains the definitions for the cursor functions.
+* 
+*******************************************************************/
+#ifndef _DDK768_CURSOR_H_
+#define _DDK768_CURSOR_H_
+
+#include "ddk768_mode.h"
+
+#define CURSOR_DISABLE	0x00
+#define CURSOR_ALPHA	0x01
+#define CURSOR_MONO		0x02
+#define CURSOR_MASK		0x03
+
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk768_initCursor(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+);
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk768_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+);
+
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk768_enableCursor(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long enable
+);
+
+#endif /* _CURSOR_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_display.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_display.c
new file mode 100644
index 000000000000..3757ac1f3225
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_display.c
@@ -0,0 +1,784 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  DISPLAY.C --- Voyager GX SDK 
+*  This file contains the source code for the panel and CRT functions.
+* 
+*******************************************************************/
+#include "ddk768_reg.h"
+
+
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_display.h"
+#include "ddk768_timer.h"
+
+#include "ddk768_help.h"
+
+
+
+/* Monitor Detection RGB Default Threshold values */
+#define DEFAULT_MON_DETECTION_THRESHOLD         0x64
+
+/*
+ * This function initializes the display.
+ *
+ * Output:
+ *      0   - Success
+ *      1   - Fail 
+ */
+long initDisplay()
+{
+
+    /* set 80024[30:28] and 88024[30:28] to 0x3 in order for the DAC to output stronger signal. */
+    unsigned long value;
+    value = peekRegisterDWord(CRT_DETECT);
+    value &= 0xCFFFFFFF;
+    value |= 0x30000000;
+    pokeRegisterDWord(CRT_DETECT, value);
+    value = peekRegisterDWord(CRT_DETECT + CHANNEL_OFFSET);
+    value &= 0xCFFFFFFF;
+    value |= 0x30000000;
+    pokeRegisterDWord(CRT_DETECT + CHANNEL_OFFSET, value);
+
+    return 0;
+
+}
+
+/* New for Falcon: DPMS control is moved to display controller.
+ * This function sets the display DPMS state 
+ * It is used to set CRT monitor to On, off, or suspend states, 
+ * while display channel are still active.
+ */
+void setDisplayDPMS(
+   disp_control_t dispControl, /* Channel 0 or Channel 1) */
+   DISP_DPMS_t state /* DPMS state */
+   )
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+	/* Get the control register for channel 0 or 1. */
+    ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+    switch (state)
+    {
+       case DISP_DPMS_ON:
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHP);
+        break;
+
+       case DISP_DPMS_STANDBY:
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHN);
+        break;
+
+       case DISP_DPMS_SUSPEND:
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHP);
+        break;
+
+       case DISP_DPMS_OFF:
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHN);
+        break;
+    }
+
+    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+}
+
+/* 
+ * New for Falcon.
+ * This funciton configures:
+ * 1. Output from channel 0 or channel 1 is 24 single or 48 double pixel.
+ * 2. Output data comes from data path of channel 0 or channel 1.
+ *
+ * Input: See the commnet in the input parameter below.
+ *
+ * Return: 0 is OK, -1 is error.
+ */
+long setDisplayFormat(
+   disp_control_t outputInterface, /* Use the output of channel 0 or 1 */
+   disp_control_t dataPath,        /* Use the data path from channel 0 or 1 */
+   disp_format_t dispFormat         /* 24 bit single or 48 bit double pixel */
+   )
+{
+   unsigned long ulDispCtrlAddr, ulDispCtrlReg;
+
+   ulDispCtrlAddr = (outputInterface == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+   ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+   if (dispFormat == DOUBLE_PIXEL_48BIT)
+   {
+      if (dataPath == CHANNEL0_CTRL)
+           ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL0_48BIT);
+      else
+           ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL1_48BIT);
+
+        // When in 48 bit mode, enable double pixel clock
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+   }
+   else
+   {
+      if (dataPath == CHANNEL0_CTRL)
+           ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL0_24BIT);
+      else
+           ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL1_24BIT);
+
+        // When in 24 bit mode, disable double pixel.
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE);
+   }
+
+   pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+
+   return 0;
+}
+
+/*
+ * Wait number of Vertical Vsync
+ *
+ * Input:
+ *          dispControl - Display Control (either channel 0 or 1)
+ *          vSyncCount  - Number of vertical sync to wait.
+ *
+ * Note:
+ *      This function is waiting for the next vertical sync.         
+ */
+void waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long status;
+    unsigned long ulLoopCount = 0;
+    static unsigned long ulDeadLoopCount = 10;
+    
+    if (dispControl == CHANNEL0_CTRL)
+    {
+        // There is no Vsync when PLL is off
+        if ((FIELD_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC0) == CLOCK_ENABLE_DC0_OFF))
+            return;
+
+        ulDispCtrlAddr = DISPLAY_CTRL;
+    }
+    else
+    {
+        // There is no Vsync when PLL is off
+        if ((FIELD_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC1) == CLOCK_ENABLE_DC1_OFF))
+            return;
+
+        ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET;
+    }
+
+    //There is no Vsync when display timing is off. 
+    if ((FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, TIMING) ==
+         DISPLAY_CTRL_TIMING_DISABLE))
+    {
+            return;
+    }
+
+    /* Count number of Vsync. */
+    while (vSyncCount-- > 0)
+    {
+        /* If VSync is active when entering this function. Ignore it and
+           wait for the next.
+        */
+        ulLoopCount = 0;
+        do
+        {
+            status = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, VSYNC);
+            //Insert delay to reduce number of Vsync checks
+            timerWaitTicks(3, 0xffff);
+            if(ulLoopCount++ > ulDeadLoopCount) break;
+        }
+        while (status == DISPLAY_CTRL_VSYNC_ACTIVE);
+
+        /* Wait for end of vsync or timeout */
+        ulLoopCount = 0;
+        do
+        {
+            status = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, VSYNC);
+            timerWaitTicks(3, 0xffff);
+            if(ulLoopCount++ > ulDeadLoopCount) break;
+        }
+        while (status == DISPLAY_CTRL_VSYNC_INACTIVE);
+    }
+}
+
+/*
+ * Use panel vertical sync line as time delay function.
+ * This function does not wait for the next VSync. Instead, it will wait
+ * until the current line reaches the Vertical Sync line.
+ * This function is really useful when flipping display to prevent tearing.
+ *
+ * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL)
+ */
+void ddk768_waitVSyncLine(disp_control_t dispControl)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long value;
+    mode_parameter_t modeParam;
+    
+    ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? CURRENT_LINE : (CURRENT_LINE+CHANNEL_OFFSET);
+
+    /* Get the current mode parameter of the specific display control */
+    modeParam = ddk768_getCurrentModeParam(dispControl);
+    
+    do
+    {
+    	value = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), CURRENT_LINE, LINE);
+    }
+    while (value < modeParam.vertical_sync_start);
+}
+
+/*
+ * Get current display line number
+ */
+unsigned long getDisplayLine(disp_control_t dispControl)
+{
+    unsigned long ulRegAddr;
+    unsigned long ulRegValue;
+    
+    ulRegAddr = (dispControl == CHANNEL0_CTRL)? CURRENT_LINE : (CURRENT_LINE+DC_OFFSET);
+    ulRegValue = FIELD_GET(peekRegisterDWord(ulRegAddr), CURRENT_LINE, LINE);
+
+    return(ulRegValue);
+}
+
+/*
+ * This functions uses software sequence to turn on/off the panel of the digital interface.
+ */
+void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+
+    ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+    if (dispState == DISP_ON)
+    {
+        //If bit 27:24 are already ON. Don't need to set them again 
+        //because setting panel seq is time consuming.
+        if ((ulDispCtrlReg & 0x0f000000) == 0x0f000000) return;
+
+        /* Turn on FPVDDEN. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, HIGH);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+        /* Turn on FPDATA. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, ENABLE);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+        /* Turn on FPVBIAS. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, HIGH);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+        /* Turn on FPEN. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, HIGH);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+    }
+    else
+    {
+        //If bit 27:24 are already OFF. Don't need to clear them again.
+        if ((ulDispCtrlReg & 0x0f000000) == 0x00000000) return;
+
+        /* Turn off FPEN. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, LOW);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+
+        /* Turn off FPVBIASEN. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, LOW);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+        /* Turn off FPDATA. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, DISABLE);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+		waitDispVerticalSync(dispControl, vSyncDelay);
+
+        /* Turn off FPVDDEN. */
+        ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, LOW);
+        pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+    }
+
+}
+
+/* 
+ * This function turns on/off the DAC for CRT display control.
+ * Input: On or off
+ */
+void ddk768_setDAC(disp_state_t state)
+{
+
+#if 1
+	/* Cheok(10/16/2013): For Falcon, DAC definition not exist yet.*/
+
+#else
+    if (state == DISP_ON)
+    {
+        pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL),
+                                               MISC_CTRL,
+                                               DAC_POWER,
+                                               ON));
+    }
+    else
+    {
+        pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL),
+                                               MISC_CTRL,
+                                               DAC_POWER,
+                                               OFF));
+    }
+#endif
+}
+
+/*
+ * This function turns on/off the display control of Channel 0 or channel 1.
+ *
+ * Note:
+ *      Turning on/off the timing and the plane requires programming sequence.
+ *      The plane can not be changed without turning on the timing. However,
+ *      changing the plane has no effect when the timing (clock) is off. Below,
+ *      is the description of the timing and plane combination setting.
+ */
+//Cheok(10/18/2013): New function similar to setDisplayControl()
+void ddk768_setDisplayEnable(
+   disp_control_t dispControl, /* Channel 0 or Channel 1) */
+   disp_state_t dispState      /* ON or OFF */
+)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+    ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+
+
+    /* Turn on/off the Panel display control */
+    if (dispState == DISP_ON)
+    {
+         /* Timing should be enabled first before enabling the plane because changing at the
+            same time does not guarantee that the plane will also enabled or disabled. 
+          */
+         ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, ENABLE);
+         ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DIRECTION, INPUT); 
+         pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+
+		 ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, ENABLE)|        
+                            FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED); 
+		
+		 pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+    }
+    else
+    {
+         /* When turning off, there is no rule on the programming sequence since whenever the
+            clock is off, then it does not matter whether the plane is enabled or disabled.
+            Note: Modifying the plane bit will take effect on the next vertical sync. Need to
+                  find out if it is necessary to wait for 1 vsync before modifying the timing
+                  enable bit. 
+          */
+         ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE);
+         pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+
+         ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, DISABLE);
+         pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+
+    }
+
+
+}
+
+
+/*
+ * This function set display channel data direction.
+ *
+ */
+
+void setDataDirection(
+   disp_control_t dispControl, /* Channel 0 or Channel 1) */
+   disp_state_t dispState      /* ON or OFF */
+)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+    if (dispState == DISP_ON)
+    {
+         ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+         ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+         /*set data direction */ 
+         ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DIRECTION, INPUT); 
+         pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+
+
+     }
+}
+
+
+
+
+/*
+ * This function detects if the CRT monitor is attached.
+ *
+ * Input:
+ *      redValue    - Threshold value to be detected on the red color.
+ *      greenValue  - Threshold value to be detected on the green color.
+ *      blueValue   - Threshold value to be detected on the blue color.
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long ddk768_detectCRTMonitor(
+    disp_control_t dispControl, 
+    unsigned char redValue,
+    unsigned char greenValue,
+    unsigned char blueValue
+)
+{
+    unsigned long ulMonitorDetectAddr;
+    unsigned long value = 0, red, green, blue;
+    long result = (-1);
+
+    ulMonitorDetectAddr = (dispControl == CHANNEL0_CTRL)? CRT_DETECT : (CRT_DETECT+DC_OFFSET);
+    
+    /* Use the given red, green, and blue threshold value to detect the monitor or
+       default. */
+    if (redValue != 0)
+        red = redValue;
+    else
+        red = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    if (greenValue != 0)
+        green = greenValue;
+    else
+        green = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    if (blueValue != 0)
+        blue = blueValue;
+    else
+        blue = DEFAULT_MON_DETECTION_THRESHOLD;
+        
+    /* Set the RGB Threshold value and enable the monitor detection. */
+    value = FIELD_VALUE(0, CRT_DETECT, DATA_RED, red) |
+            FIELD_VALUE(0, CRT_DETECT, DATA_GREEN, green) |
+            FIELD_VALUE(0, CRT_DETECT, DATA_BLUE, blue) |
+            FIELD_SET(value, CRT_DETECT, ENABLE, ENABLE);
+    pokeRegisterDWord(ulMonitorDetectAddr, value);
+    
+    /* Add some delay here. Otherwise, the detection is not stable.
+       SM768 has internal timer. It's better than SW countdown loop.
+    */
+    timerWaitTicks(3, 0x7ffff);
+    
+    /* Check if the monitor is detected. */
+    if (FIELD_GET(peekRegisterDWord(ulMonitorDetectAddr), CRT_DETECT, CRT) ==
+        CRT_DETECT_CRT_PRESENT)
+    {
+        result = 0;
+    }
+    
+    /* Disable the Monitor Detect Enable bit. Somehow, enabling this bit will 
+       cause the CRT to lose display. */
+    value = peekRegisterDWord(ulMonitorDetectAddr);
+    value = FIELD_SET(value, CRT_DETECT, ENABLE, DISABLE);
+    pokeRegisterDWord(ulMonitorDetectAddr, value);
+
+    return result;
+}
+
+
+/*
+ * This function controls monitor on/off and data path.
+ * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc.
+ * However, it needs too many input parameter.
+ * There are other set view functions with less parameters, but not as flexible as this one.
+ *
+ */
+long setDisplayView(
+	disp_control_t dispOutput, 		/* Monitor 0 or 1 */
+	disp_state_t dispState,				/* On or off */
+	disp_control_t dataPath,			/* Use the data path of channel 0 or channel 1 (optional when OFF) */
+	disp_format_t dispFormat)			/* 24 or 48 bit digital interface (optional when OFF */
+{
+
+	ddk768_setDisplayEnable(dispOutput, dispState);         /* Enable or disable Channel output timing */
+	ddk768_swPanelPowerSequence(dispOutput, dispState, 4);  /* Turn on or off output power */
+	setDisplayFormat(dispOutput, dataPath, dispFormat); /* Set dataPath and output pixel format */
+
+#if 0
+	if (dispState == DISP_ON)
+    	setDisplayDPMS(dispOutput, DISP_DPMS_ON);          /* DPMS on */
+#endif
+	return 0;
+}
+
+/*
+ * Convenient function to trun on single view 
+ */
+long setSingleViewOn(disp_control_t dispOutput)
+{
+	setDisplayView(
+		dispOutput, 			/* Output monitor */
+		DISP_ON, 				/* Turn On */
+		dispOutput,				/* Assume monitor 0 is using data path 0, and monitor 1 is using data path 1 */
+		SINGLE_PIXEL_24BIT);	/* Default to 24 bit single pixel, the most used case */
+
+	return 0;
+}
+
+/*
+ * Convenient function to trun off single view 
+ */
+long setSingleViewOff(disp_control_t dispOutput)
+{
+	setDisplayView(
+		dispOutput, 	      /* Output monitor */
+		DISP_OFF, 		      /* Turn Off */
+		dispOutput,				/* Assume monitor 0 is using data path 0, and monitor 1 is using data path 1 */
+		SINGLE_PIXEL_24BIT);	/* Default to 24 bit single pixel, the most used case */
+
+	return 0;
+}
+
+/*
+ * Convenient function to trun on clone view 
+ */
+long setCloneViewOn(disp_control_t dataPath)
+{
+	setDisplayView(
+		CHANNEL0_CTRL,			/* For Clone view, monitor 0 has to be ON */
+		DISP_ON, 
+		dataPath,				/* Use this data path for monitor 0 */
+		SINGLE_PIXEL_24BIT);	/* Default to 24 bit single pixel, the most used case */
+
+	setDisplayView(
+		CHANNEL1_CTRL,			/* For Clone view, monitor 1 has to be ON */
+		DISP_ON, 
+		dataPath,				/* Use this data path for monitor 1 */
+		SINGLE_PIXEL_24BIT);	/* Default to 24 bit single pixel, the most used case */
+
+	return 0;
+}
+
+/*
+ * Convenient function to trun on dual view 
+ */
+long setDualViewOn()
+{
+	setSingleViewOn(CHANNEL0_CTRL);
+	setSingleViewOn(CHANNEL1_CTRL);
+
+	return 0;
+}
+
+/*
+ * Convenient function to trun off all views
+ */
+long setAllViewOff()
+{
+	setSingleViewOff(CHANNEL0_CTRL);	/* Turn Off monitor 0 */
+	setSingleViewOff(CHANNEL1_CTRL);	/* Turn Off monitor 1 */
+
+	return 0;
+}
+
+/*
+ * Disable double pixel clock. 
+ * This is a temporary function, used to patch for the random fuzzy font problem. 
+ */
+void DisableDoublePixel(disp_control_t dispControl)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+	if(dispControl == CHANNEL0_CTRL) {
+	    ulDispCtrlAddr = DISPLAY_CTRL;
+	    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+	    ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE);
+	    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+	}else{
+	    ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET;
+	    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+	    ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE);
+	    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+	}
+}
+
+
+
+
+void EnableDoublePixel(disp_control_t dispControl)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+	if(dispControl == CHANNEL0_CTRL) {
+	    ulDispCtrlAddr = DISPLAY_CTRL;
+	    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+	    ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+	    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+	}else{
+	    ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET;
+	    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+	    ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+	    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+	}
+}
+
+void enableLVDS(
+	unsigned short lvds, //LVDS 1 or 2
+	unsigned short on    //On =1, and off = 0
+)
+{
+	unsigned long ulTmpValue;
+
+	ulTmpValue = peekRegisterDWord(LVDS_CTRL2);
+
+	if (lvds == 1)
+	{
+		ulTmpValue &= FIELD_CLEAR(LVDS_CTRL2, PD_PLL1);
+		if (!on)
+			ulTmpValue |= FIELD_SET(0, LVDS_CTRL2, PD_PLL1, DOWN);
+	}
+	else
+	{
+		ulTmpValue &= FIELD_CLEAR(LVDS_CTRL2, PD_PLL2);
+		if (!on)
+			ulTmpValue |= FIELD_SET(0, LVDS_CTRL2, PD_PLL2, DOWN);
+	}
+
+	pokeRegisterDWord(LVDS_CTRL2, ulTmpValue);
+}
+
+
+
+void setupLVDS(unsigned short lvds)
+{
+    unsigned long ulTmpValue;
+
+    /* Set lvds control register 0x80020 */
+	// Program 0x80020
+	// bit 31:30 = 00 binary
+	//bit 29:23 = 0x63
+	//bit 22:16 = 0x63
+    ulTmpValue = 0;
+    ulTmpValue |=        
+        FIELD_SET(0, LVDS_CTRL1, CLKSEL_PLL2, RE)
+      | FIELD_SET(0, LVDS_CTRL1, CLKSEL_PLL1, RE)
+      | FIELD_SET(0, LVDS_CTRL1, DCLK2, DEFAULT)
+      | FIELD_SET(0, LVDS_CTRL1, DCLK1, DEFAULT);
+
+    pokeRegisterDWord(LVDS_CTRL1, ulTmpValue);
+
+    /* Set lvds control register 0x8002c */
+	//Program 0x8002c
+	// bit 31 to 0 = 0x750fed0e
+	ulTmpValue = 0;
+    ulTmpValue |=        
+        FIELD_SET(0, LVDS_CTRL2, SHTDNB2, NORMAL)
+      | FIELD_SET(0, LVDS_CTRL2, SHTDNB1, NORMAL)
+      | FIELD_SET(0, LVDS_CTRL2, CLK2_DS, 5MA)
+      | FIELD_SET(0, LVDS_CTRL2, CLK1_DS, 5MA)
+      | FIELD_SET(0, LVDS_CTRL2, DS, 5MA)
+      | FIELD_SET(0, LVDS_CTRL2, CLK2_TR, 0)
+      | FIELD_SET(0, LVDS_CTRL2, CLK1_TR, 0)
+      | FIELD_SET(0, LVDS_CTRL2, TR, 0)
+      | FIELD_SET(0, LVDS_CTRL2, CLK2_COMP, 3)
+      | FIELD_SET(0, LVDS_CTRL2, CLK1_COMP, 3)
+      | FIELD_SET(0, LVDS_CTRL2, PRE_COMP, 3)
+      | FIELD_SET(0, LVDS_CTRL2, VCOS_PLL2, 350M)
+      | FIELD_SET(0, LVDS_CTRL2, VCOS_PLL1, 350M)
+      | FIELD_SET(0, LVDS_CTRL2, SHORTS_PLL2, 2048)
+      | FIELD_SET(0, LVDS_CTRL2, SHORTS_PLL1, 2048)
+      | FIELD_SET(0, LVDS_CTRL2, PD_PLL2, DOWN)
+      | FIELD_SET(0, LVDS_CTRL2, PD_PLL1, DOWN)
+      | FIELD_SET(0, LVDS_CTRL2, MODESEL2, DC1)
+      | FIELD_SET(0, LVDS_CTRL2, MODESEL1, DC0);
+	
+    pokeRegisterDWord(LVDS_CTRL2, ulTmpValue);
+}
+
+/*
+ *  Set up 48 bit LVDS output with the input DC channel.
+ */
+long set48bitLVDS(disp_control_t dataPath)
+{
+    unsigned long ulTmpValue;
+    unsigned long offset;
+
+    offset = (dataPath==CHANNEL0_CTRL)? 0 : CHANNEL_OFFSET;
+
+	// Set Display Control for dual lvds 
+    ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+offset)
+               & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT)
+               & FIELD_CLEAR(DISPLAY_CTRL, PIXEL_CLOCK_SELECT)
+               & FIELD_CLEAR(DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK);
+
+	// Program 0x80000
+	// bit 17:16 = 10 binary
+	// bit 15 = 1
+	// bit 11 = 1
+	if (offset)
+    	ulTmpValue |= FIELD_SET(0, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_48BIT);
+	else
+    	ulTmpValue |= FIELD_SET(0, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT);
+
+	ulTmpValue |=
+        FIELD_SET(0, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, HALF)
+      | FIELD_SET(0, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+
+
+    pokeRegisterDWord(DISPLAY_CTRL+offset, ulTmpValue);
+
+	// For 48 bit output, the other channel has to set up properly as well.
+	if (offset) //If data path is DC1, set DC0
+	{
+    	ulTmpValue = peekRegisterDWord(DISPLAY_CTRL) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT);
+
+		// Program 0x80000
+		// bit 17:16 = 3
+    	ulTmpValue |=  FIELD_SET(0, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_48BIT);
+
+    	pokeRegisterDWord(DISPLAY_CTRL, ulTmpValue);
+	}
+	else // If data path is DC0, set DC1
+	{
+    	ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT);
+
+		// Program 0x88000
+		// bit 17:16 = 2
+    	ulTmpValue |=  FIELD_SET(0, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT);
+
+    	pokeRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET, ulTmpValue);
+	}
+
+	/* Set LVDS clock polarity */
+	// Program 0x80024
+	// bit 26 = 0
+    ulTmpValue = peekRegisterDWord(CRT_DETECT+offset)
+               & FIELD_CLEAR(CRT_DETECT, LVDS_CLK);
+
+	//printf( "0x80024 = %08x\n", ulTmpValue);
+    pokeRegisterDWord(CRT_DETECT+offset, ulTmpValue);
+
+	setupLVDS(3);
+
+	//Wait for LVDS PLL to settle before enable it.
+    waitDispVerticalSync(dataPath, 3);
+
+	// program 0x8002c again
+	//bit 31:0 = 0x750fed02
+	enableLVDS(1, 1);
+	enableLVDS(2, 1);
+
+	return 0;
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_display.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_display.h
new file mode 100644
index 000000000000..72382d841159
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_display.h
@@ -0,0 +1,247 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  display.h --- SM750/SM718 DDK
+*  This file contains the function prototypes for the display.
+* 
+*******************************************************************/
+#ifndef _DDK768_DISPLAY_H_
+#define _DDK768_DISPLAY_H_
+#include "ddk768_mode.h"
+typedef enum _disp_path_t
+{
+    CHANNEL0_PATH = 0,
+    CHANNEL1_PATH = 1,
+}
+disp_path_t;
+
+typedef enum _disp_state_t
+{
+    DISP_OFF = 0,
+    DISP_ON  = 1,
+}
+disp_state_t;
+
+//Cheok: obsolete for Falcon, delete after old code cleans up.
+typedef enum _disp_output_t
+{
+    NO_DISPLAY,             /* All display off. */
+    LCD1_ONLY,              /* LCD1 only */
+    LCD2_ONLY,              /* LCD2 only */
+    CRT2_ONLY,              /* CRT2 only */
+    LCD1_CRT2_SIMUL,        /* Both LCD1 and CRT2 displaying the same content. */
+    LCD1_LCD2_SIMUL,        /* Both LCD1 and LCD2 displaying the same content. */
+    CRT2_LCD2_SIMUL,        /* CRT2 and LCD2 displaying the same content. */
+    LCD1_LCD2_CRT2_SIMUL,   /* LCD1, LCD2, and CRT2 displaying the same content. */
+    LCD1_CRT2_DUAL,         /* LCD1 and CRT2 displaying different contents. */
+    LCD1_LCD2_DUAL,         /* LCD1 and LCD2 displaying different contents. */
+    LCD1_LCD2_CRT2_DUAL     /* LCD2 and CRT2 displaying the same content while
+                               the Panel displaying different content. */
+}
+disp_output_t;
+
+//Cheok(10/172013): New interface for Falcon.
+typedef enum _disp_interface_t
+{
+    DIGITAL_24BIT = 0,
+    DIGITAL_48BIT,
+    CRT,
+	LVDS,
+    HDMI
+}
+disp_interface_t;
+
+typedef enum _disp_format_t
+{
+    SINGLE_PIXEL_24BIT = 0,
+    DOUBLE_PIXEL_48BIT
+}
+disp_format_t;
+
+typedef enum _DISP_DPMS_t
+{
+    DISP_DPMS_ON,
+    DISP_DPMS_STANDBY,
+    DISP_DPMS_SUSPEND,
+    DISP_DPMS_OFF
+}
+DISP_DPMS_t;
+
+
+
+/*
+ * This function initializes the display.
+ *
+ * Output:
+ *      0   - Success
+ *      1   - Fail 
+ */
+long initDisplay(void);
+
+/*
+ * This function sets the display DPMS state 
+ * It is used to set CRT monitor to On, off, or suspend states, 
+ * while display channel are still active.
+ */
+void setDisplayDPMS(
+   disp_control_t dispControl, /* Channel 0 or Channel 1) */
+   DISP_DPMS_t state /* DPMS state */
+   );
+
+/*
+ * This funciton sets:
+ * 1. Output from channel 0 or channel 1 is 24 single or 48 double pixel.
+ * 2. Output data comes from path of channel 0 or 1.
+ *
+ * Input: See the commnet in the input parameter below.
+ *
+ * Return: 0 is OK, -1 is error.
+ */
+long setDisplayFormat(
+   disp_control_t outputInterface, /* Use the output of channel 0 or 1 */
+   disp_control_t dataPath,        /* Use the data path from channel 0 or 1 */
+   disp_format_t dispFormat         /* 24 bit single or 48 bit double pixel */
+   );
+
+/*
+ * This functions sets the CRT Path.
+ */
+void setCRTPath(disp_control_t dispControl);
+
+/*
+ * This functions uses software sequence to turn on/off the panel.
+ */
+void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vsync_delay);
+
+/*
+ * This functions uses software sequence to turn on/off the digital interface.
+ */
+void swDispPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay);
+
+/* 
+ * This function turns on/off the DAC for CRT display control.
+ * Input: On or off
+ */
+void ddk768_setDAC(disp_state_t state);
+
+/*
+ * Wait number of Vertical Vsync
+ *
+ * Input:
+ *          dispControl - Display Control (either channel 0 or 1)
+ *          vSyncCount  - Number of vertical sync to wait.
+ *
+ * Note:
+ *      This function is waiting for the next vertical sync.         
+ */
+void waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount);
+
+/*
+ * Use panel vertical sync line as time delay function.
+ * This function does not wait for the next VSync. Instead, it will wait
+ * until the current line reaches the Vertical Sync line.
+ * This function is really useful when flipping display to prevent tearing.
+ *
+ * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL)
+ */
+void ddk768_waitVSyncLine(disp_control_t dispControl);
+
+/*
+ * This function detects if the CRT monitor is attached.
+ *
+ * Input:
+ *      redValue    - Threshold value to be detected on the red color.
+ *      greenValue  - Threshold value to be detected on the green color.
+ *      blueValue   - Threshold value to be detected on the blue color.
+ *
+ * Output:
+ *      0   - Success
+ *     -1   - Fail 
+ */
+long ddk768_detectCRTMonitor(
+    disp_control_t dispControl, 
+    unsigned char redValue,
+    unsigned char greenValue,
+    unsigned char blueValue
+);
+
+
+
+/*
+ * This function turns on/off the display control of Channel 0 or channel 1.
+ *
+ * Note:
+ *      Turning on/off the timing and the plane requires programming sequence.
+ *      The plane can not be changed without turning on the timing. However,
+ *      changing the plane has no effect when the timing (clock) is off. Below,
+ *      is the description of the timing and plane combination setting.
+ */
+void ddk768_setDisplayEnable(
+disp_control_t dispControl, /* Channel 0 or Channel 1) */
+disp_state_t dispState /* ON or OFF */
+);
+
+/*
+ * This function controls monitor on/off and data path.
+ * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc.
+ * However, it needs too many input parameter.
+ * There are other set view functions with less parameters, but not as flexible as this one.
+ *
+ */
+long setDisplayView(
+	disp_control_t dispOutput, 			/* Monitor 0 or 1 */
+	disp_state_t dispState,				/* On or off */
+	disp_control_t dataPath,			/* Use the data path of channel 0 or channel 1 (optional when OFF) */
+	disp_format_t dispFormat);			/* 24 or 48 bit digital interface (optional when OFF */
+
+/*
+ * Convenient function to trun on single view 
+ */
+long setSingleViewOn(disp_control_t dispOutput);
+
+/*
+ * Convenient function to trun off single view 
+ */
+long setSingleViewOff(disp_control_t dispOutput);
+
+/*
+ * Convenient function to trun on clone view 
+ */
+long setCloneViewOn(disp_control_t dataPath);
+
+/*
+ * Convenient function to trun on dual view 
+ */
+long setDualViewOn(void);
+
+/*
+ * Convenient function to trun off all views
+ */
+long setAllViewOff(void);
+
+
+/*
+ * Disable double pixel clock. 
+ * This is a teporary function, used to patch for the random fuzzy font problem. 
+ */
+void DisableDoublePixel(disp_control_t dispControl);
+void EnableDoublePixel(disp_control_t dispControl);
+
+
+void enableLVDS(
+	unsigned short lvds, //LVDS 1 or 2
+	unsigned short on    //On =1, and off = 0
+);
+
+
+void setupLVDS(unsigned short lvds);
+
+
+long set48bitLVDS(disp_control_t dataPath);
+
+
+#endif /* _DISPLAY_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.c
new file mode 100644
index 000000000000..ffbc0399f672
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.c
@@ -0,0 +1,2140 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  edid.c --- SM750/SM718 DDK 
+*  This file contains functions to interpret the EDID structure.
+* 
+*******************************************************************/
+
+#include "ddk768_help.h"
+#include "ddk768_helper.h"
+#include "ddk768_hwi2c.h"
+#include "ddk768_swi2c.h"
+#include "ddk768_edid.h"
+
+#include "ddkdebug.h"
+
+
+/* Enable this one to print the VDIF timing when debug is enabled. */
+//#define ENABLE_DEBUG_PRINT_VDIF
+
+
+#define HEADER_EDID_REGISTERS               8
+
+typedef struct _est_timing_mode_t
+{
+    unsigned long x;        /* Mode Width */
+    unsigned long y;        /* Mode Height */
+    unsigned long hz;       /* Refresh Rate */
+    unsigned char source;   /* Source:  0 - VESA
+                                        1 - IBM
+                                        2 - Apple
+                             */
+}
+est_timing_mode_t;
+
+/* These values only applies to EDID Version 1 */
+static est_timing_mode_t establishTiming[3][8] =
+{
+    /* Established Timing 1 */
+    {   
+        { 800,  600, 60, 0},
+        { 800,  600, 56, 0},
+        { 640,  480, 75, 0},
+        { 640,  480, 72, 0},
+        { 640,  480, 67, 2},
+        { 640,  480, 60, 1},
+        { 720,  400, 88, 1},
+        { 720,  400, 70, 1},
+    },
+    {
+        {1280, 1024, 75, 0},
+        {1024,  768, 75, 0},
+        {1024,  768, 70, 0},
+        {1024,  768, 60, 0},
+        {1024,  768, 87, 1},
+        { 832,  624, 75, 0},
+        { 800,  600, 75, 0},
+        { 800,  600, 72, 0},
+    },
+    {
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {   0,    0,  0, 0},
+        {1152,  870, 75, 2},
+    }
+};
+
+static void printVdif(
+    vdif_t *pVDIF
+)
+{
+#ifdef DDKDEBUG
+
+#ifndef ENABLE_DEBUG_PRINT_VDIF
+    DDKDEBUGENABLE(0);
+#endif
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "pixelClock = %d\n", pVDIF->pixelClock));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "characterWidth = %d\n", pVDIF->characterWidth));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "scanType = %s\n", (pVDIF->scanType == VDIF_INTERLACED) ? "Interlaced" : "Progressive"));
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrequency = %d\n", pVDIF->horizontalFrequency));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalTotal = %d\n", pVDIF->horizontalTotal));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalActive = %d\n", pVDIF->horizontalActive));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankStart = %d\n", pVDIF->horizontalBlankStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankTime = %d\n", pVDIF->horizontalBlankTime));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncStart = %d\n", pVDIF->horizontalSyncStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalRightBorder = %d\n", pVDIF->horizontalRightBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrontPorch = %d\n", pVDIF->horizontalFrontPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncWidth = %d\n", pVDIF->horizontalSyncWidth));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBackPorch = %d\n", pVDIF->horizontalBackPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalLeftBorder = %d\n", pVDIF->horizontalLeftBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncPolarity = %s\n", 
+        (pVDIF->horizontalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive"));
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrequency = %d\n", pVDIF->verticalFrequency));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTotal = %d\n", pVDIF->verticalTotal));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalActive = %d\n", pVDIF->verticalActive));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankStart = %d\n", pVDIF->verticalBlankStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankTime = %d\n", pVDIF->verticalBlankTime));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncStart = %d\n", pVDIF->verticalSyncStart));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBottomBorder = %d\n", pVDIF->verticalBottomBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrontPorch = %d\n", pVDIF->verticalFrontPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncHeight = %d\n", pVDIF->verticalSyncHeight));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBackPorch = %d\n", pVDIF->verticalBackPorch));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTopBorder = %d\n", pVDIF->verticalTopBorder));
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncPolarity = %s\n", 
+        (pVDIF->verticalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive"));
+
+#ifndef ENABLE_DEBUG_PRINT_VDIF
+    DDKDEBUGENABLE(1);
+#endif
+#endif
+}
+
+/*
+ *  edidGetHeader
+ *      This function gets the EDID Header
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0 get header success; -1 fail.
+ */
+unsigned char edidGetHeader(
+    unsigned char *pEDIDBuffer
+)
+{
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Check the header */
+        if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) &&
+            (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) &&
+            (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00))
+        {
+            return 0;
+        }
+        else
+            return -1;
+    }
+
+   // DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID bufffer\n"));
+    return -1;
+}
+
+/*
+ *  edidGetVersion
+ *      This function gets the EDID version
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRevision   - Revision of the EDIE (if exist)
+ *
+ *  Output:
+ *      Revision number of the given EDID buffer.
+ */
+unsigned char ddk768_edidGetVersion(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pRevision
+)
+{
+    unsigned char version;
+    
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Check the header */
+        if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) &&
+            (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) &&
+            (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00))
+        {
+            /* 
+             * EDID Structure Version 1.
+             */
+        
+            /* Read the version field from the buffer. It should be 1 */
+            version  = pEDIDBuffer[18];
+        
+            if (version == 1)
+            {
+                /* Copy the revision first */
+                if (pRevision != (unsigned char *)0)
+                    *pRevision = pEDIDBuffer[19];
+                    
+                return version;
+            }
+        }
+        else
+        {
+            /* 
+             * EDID Structure Version 2 
+             */
+             
+            /* Read the version and revision field from the buffer. */
+            version = pEDIDBuffer[0];
+        
+            if ((version >> 4) == 2)
+            {
+                /* Copy the revision */
+                if (pRevision != (unsigned char *)0)
+                    *pRevision = version & 0x0F;
+                
+                return (version >> 4);
+            }
+        }
+    }
+    
+    DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID Structure\n"));    
+    return 0;    
+}
+
+/*
+ *  ddk768_edidGetProductInfo
+ *      This function gets the vendor and product information.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor [in]
+ *      pManufacturerName   - Pointer to a 3 byte length variable to store the manufacturer name [out]
+ *      pProductCode        - Pointer to a variable to store the product code [out]
+ *      pSerialNumber       - Pointer to a variable to store the serial number [out]
+ *      pWeekOfManufacture  - Pointer to a variable to store the week of manufacture [out]
+ *      pYearOfManufacture  - Pointer to a variable to store the year of manufacture 
+ *                            or model year (if WeekOfManufacture is 0xff) [out]
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetProductInfo(
+    unsigned char *pEDIDBuffer,
+    char *pManufacturerName,
+    unsigned short *pProductCode,
+    unsigned long *pSerialNumber,
+    unsigned char *pWeekOfManufacture,
+    unsigned short *pYearOfManufacture
+)
+{
+    unsigned char version, revision;
+    unsigned short manufactureID;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pManufacturerName != (char *)0)
+        {
+            /* Swap the byte */
+            manufactureID = (pEDIDStructure->manufacturerID >> 8) + (pEDIDStructure->manufacturerID << 8);
+            pManufacturerName[0] = ((manufactureID >> 10) & 0x001F) + 'A' - 1;
+            pManufacturerName[1] = ((manufactureID >> 5) & 0x001F) + 'A' - 1;
+            pManufacturerName[2] = (manufactureID & 0x001F) + 'A' - 1;
+            pManufacturerName[3] = '\0';
+        }
+        
+        if (pProductCode != (unsigned short *)0)
+            *pProductCode = pEDIDStructure->productCode;
+            
+        /* Only EDID structure version 1.1 and 1.2 supports this. EDID 1.3 uses
+           detail timing descriptor to store the serial number in ASCII. */
+        if (pSerialNumber != (unsigned long *)0)
+            *pSerialNumber = pEDIDStructure->serialNumber;
+        
+        /*
+         * Rev 1.3: - A value of 0 means that week of manufacture is not specified
+         *          - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture
+         *          - Any values greater than 54 is invalid.
+         *
+         * Rev 1.4: - A value of 0 means that week of manufacture is not specified
+         *          - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture
+         *          - A value of 0xFF means that Year of Manufacture contains the model year
+         *            instead of year of Manufacture.
+         *          - Other values means invalid
+         */
+        if (pWeekOfManufacture != (unsigned char *)0)
+            *pWeekOfManufacture = pEDIDStructure->weekOfManufacture;
+            
+        /* The value must be greater than 3 and less than or equal to the current
+           year minus 1990.
+           A value of 3 or less would indicated that the display was manufactured 
+           before the EDID standard was defined.
+           A value greater than (current year - 1990) would indicate that the display
+           has not yet been manufactured.
+         */
+        if (pYearOfManufacture != (unsigned short *)0)
+            *pYearOfManufacture = (unsigned short) pEDIDStructure->yearOfManufacture + 1990;
+        
+        return 0;
+    }
+
+    return (-1);
+}
+
+/*
+ *  ddk768_edidCheckMonitorInputSignal
+ *      This function checks whether the monitor is expected analog/digital 
+ *      input signal.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Analog
+ *      1   - Digital
+ */
+unsigned char ddk768_edidCheckMonitorInputSignal(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->videoInputDefinition.analogSignal.inputSignal;
+    
+    return 0;
+}
+
+/*
+ *  ddk768_edidGetAnalogSignalInfo
+ *      This function gets the analog video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pRefWhiteAboveBlank     - Pointer to a variable to store the reference white above blank
+ *                                value. The value is in milliVolt.
+ *      pSyncLevelBelowBlank    - Pointer to a variable to store the Sync tip level below blank
+ *                                The value is also in milliVolt
+ *      pBlank2BlackSetup       - Pointer to a variable to store the Blank to black setup or
+ *                                pedestal per appropriate Signal Level Standard flag. 
+ *                                1 means that the display expect the setup.
+ *      pSeparateSyncSupport    - Pointer to a variable to store the flag to indicate that the
+ *                                monitor supports separate sync.
+ *      pCompositeSyncSupport   - Pointer to a variable to store a flag to indicate that the
+ *                                monitor supports composite sync.
+ *      pSyncOnGreenSupport     - Pointer to a variable to store a flag to indicate that
+ *                                the monitor supports sync on green video.
+ *      pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration
+ *                                of the VSync pulse is required when composite sync or
+ *                                sync-on-green video is used.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetAnalogSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRefWhiteAboveBlank,
+    unsigned short *pSyncLevelBelowBlank,
+    unsigned char *pBlank2BlackSetup,
+    unsigned char *pSeparateSyncSupport,
+    unsigned char *pCompositeSyncSupport,
+    unsigned char *pSyncOnGreenSupport,
+    unsigned char *pVSyncSerrationRequired
+)
+{
+    unsigned char version, revision;
+    unsigned short whiteReference, syncLevel;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Check if the input signal is analog */
+        if (pEDIDStructure->videoInputDefinition.analogSignal.inputSignal != 0)
+            return (-1);
+        
+        switch (pEDIDStructure->videoInputDefinition.analogSignal.signalLevelStd)
+        {
+            case 0:
+                whiteReference = 700;
+                syncLevel = 300;
+                break;
+            case 1:
+                whiteReference = 714;
+                syncLevel = 286;
+                break;
+            case 2:
+                whiteReference = 1000;
+                syncLevel = 400;
+                break;
+            case 3:
+                whiteReference = 700;
+                syncLevel = 0;
+                break;
+        }
+        
+        if (pRefWhiteAboveBlank != (unsigned short *)0)
+            *pRefWhiteAboveBlank = whiteReference; 
+        
+        if (pSyncLevelBelowBlank != (unsigned short *)0)
+            *pSyncLevelBelowBlank = syncLevel;
+        
+        if (pBlank2BlackSetup != (unsigned char *)0)
+            *pBlank2BlackSetup = (unsigned char)
+                                  pEDIDStructure->videoInputDefinition.analogSignal.blank2Black;
+        
+        if (pSeparateSyncSupport != (unsigned char *)0)
+            *pSeparateSyncSupport = (unsigned char)
+                                     pEDIDStructure->videoInputDefinition.analogSignal.separateSyncSupport;
+        
+        if (pCompositeSyncSupport != (unsigned char *)0)
+            *pCompositeSyncSupport = (unsigned char)
+                                      pEDIDStructure->videoInputDefinition.analogSignal.compositeSyncSupport;
+        
+        if (pSyncOnGreenSupport != (unsigned char *)0)
+            *pSyncOnGreenSupport = (unsigned char)
+                                    pEDIDStructure->videoInputDefinition.analogSignal.syncOnGreenSupport;
+        
+        if (pVSyncSerrationRequired != (unsigned char *)0)
+            *pVSyncSerrationRequired = (unsigned char)
+                                        pEDIDStructure->videoInputDefinition.analogSignal.vsyncSerration;
+                                        
+        return 0;
+    }
+    else
+    {
+        /* EDID Structure 2 */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetDigitalSignalInfo
+ *      This function gets the digital video input signal information.
+ *      Only applies to EDID 1.3 and above.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pDFP1xSupport   - Pointer to a variable to store the flag to indicate that
+ *                        the mointor interface is signal compatible with VESA
+ *                        DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color
+ *                        MSB aligned, DE active high
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDigitalSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDFP1xSupport
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision == 3))
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Check if the input signal is digital */
+        if (pEDIDStructure->videoInputDefinition.digitalSignal.inputSignal != 1)
+            return (-1);
+            
+        if (pDFP1xSupport != (unsigned char *)0)
+            *pDFP1xSupport = pEDIDStructure->videoInputDefinition.digitalSignal.dfp1Support;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetDisplaySize
+ *      This function gets the display sizes in cm.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMaxHorzImageSize   - Pointer to a variable to store the maximum horizontal 
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *      pMaxVertImageSize   - Pointer to a variable to store the maximum vertical
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDisplaySize(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMaxHorzImageSize,
+    unsigned char *pMaxVertImageSize
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pMaxHorzImageSize != (unsigned char *)0)
+            *pMaxHorzImageSize = pEDIDStructure->maxHorzImageSize;
+        
+        if (pMaxVertImageSize != (unsigned char *)0)
+            *pMaxVertImageSize = pEDIDStructure->maxVertImageSize;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+#if 0   /* Use the ddk768_edidGetWhitePoint to get the Gamma */
+/*
+ *  edidGetGamma
+ *      This function gets the Display Transfer Characteristic (Gamma).
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Gamma value multiplied by 100. A value of 0xFFFF (-1) indicates that
+ *      the gamma value is not defined.
+ */
+unsigned short edidGetGamma(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned short)(((edid_version_1_t *)pEDIDBuffer)->displayTransferChar + 100);
+    
+    return (-1);
+}
+#endif
+
+/*
+ *  ddk768_edidGetPowerManagementSupport
+ *      This function gets the monitor's power management support.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStandBy        - Pointer to a variable to store the flag to indicate that
+ *                        standby power mode is supported.
+ *      pSuspend        - Pointer to a variable to store the flag to indicate that
+ *                        suspend power mode is supported.
+ *      pLowPower       - Pointer to a variable to store the flag to indicate that
+ *                        the display consumes low power when it receives a timing
+ *                        signal that is outside its declared active operating range.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetPowerManagementSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStandBy,
+    unsigned char *pSuspend,
+    unsigned char *pLowPower
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pStandBy != (unsigned char *)0)
+            *pStandBy = (unsigned char) pEDIDStructure->featureSupport.standbySupport;
+            
+        if (pSuspend != (unsigned char *)0)
+            *pSuspend = (unsigned char) pEDIDStructure->featureSupport.suspendSupport;
+            
+        if (pLowPower != (unsigned char *)0)
+            *pLowPower = (unsigned char) pEDIDStructure->featureSupport.lowPowerSupport;
+        
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetDisplayType
+ *      This function gets the display type.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Monochrome / grayscale display
+ *      1   - RGB Color Display
+ *      2   - Non-RGB multicolor display, e.g. R/G/Y
+ *      3   - Undefined
+ */
+unsigned char ddk768_edidGetDisplayType(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.displayType;
+    
+    return (3);
+}
+
+/*
+ *  ddk768_edidChecksRGBUsage
+ *      This function checks if the display is using the sRGB standard default
+ *      color space as its primary color space. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Does not use sRGB as its primary color space
+ *      1   - Use sRGB as its primary color space
+ */
+unsigned char ddk768_edidChecksRGBUsage(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.sRGBSupport;
+    
+    return (0);
+}
+
+/*
+ *  ddk768_edidIsPreferredTimingAvailable
+ *      This function checks whether the preffered timing mode is available.
+ *      Use of preferred timing mode is required by EDID structure version 1
+ *      Revision 3 and higher. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Preferred Timing is not available
+ *      1   - Preferred Timing is available
+ */
+unsigned char ddk768_edidIsPreferredTimingAvailable(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        /* Get EDID Version and revision */
+        version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+        if (version == 1)
+            return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.preferredTiming;
+    }
+        
+    return (0);
+}
+
+/*
+ *  ddk768_edidIsDefaultGTFSupported
+ *      This function checks whether the display supports timings based on the
+ *      GTF standard using default GTF parameter values. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Default GTF is not supported
+ *      1   - Default GTF is supported
+ */
+unsigned char ddk768_edidIsDefaultGTFSupported(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+        return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.defaultGTFSupport;
+    
+    return (0);
+}
+
+/*
+ *  edidCalculateChromaticValue
+ *      This function calculates the chromatic value. 
+ *
+ *  Input:
+ *      colorBinaryValue    - Color Characteristic Binary Representation Value 
+ *                            to be computed
+ *
+ *  Output:
+ *      The chromatic value times a 1000.
+ */
+static unsigned short edidCalculateChromaticValue(
+    unsigned short colorBinaryValue
+)
+{
+    unsigned long index;
+    unsigned long result;
+    
+    result = 0;
+    for (index = 10; index > 0; index--)
+    {
+        /* Times 1000000 to make it accurate to the micro value. */
+        result += ddk768_roundedDiv((colorBinaryValue & 0x0001) * 1000000, ddk768_twoToPowerOfx(index));
+        colorBinaryValue >>= 1;
+    }
+    
+    /* Make it accurate to 1000 place */
+    return ((unsigned short)ddk768_roundedDiv(result, 1000));
+}
+
+/*
+ *  ddk768_edidGetColorCharacteristic
+ *      This function gets the chromaticity and white point values expressed as
+ *      an integer value which represents the actual value times 1000.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRedX   - Pointer to a variable to store the Red X values
+ *      pRedY   - Pointer to a variable to store the Red Y values
+ *      pGreenX - Pointer to a variable to store the Green X values
+ *      pGreenY - Pointer to a variable to store the Green Y values
+ *      pBlueX  - Pointer to a variable to store the Blue X values
+ *      pBlueY  - Pointer to a variable to store the Blue Y values
+ *
+ *  Note:
+ *      To get the White color characteristic, use the ddk768_edidGetWhitePoint
+ */
+void ddk768_edidGetColorCharacteristic(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRedX,
+    unsigned short *pRedY,
+    unsigned short *pGreenX,
+    unsigned short *pGreenY,
+    unsigned short *pBlueX,
+    unsigned short *pBlueY
+)
+{
+    unsigned char version;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        if (pRedX != (unsigned short *)0)
+        {
+            *pRedX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redX << 2) + 
+                                                  (unsigned short)pEDIDStructure->redGreenLowBits.redXLowBits);
+        }
+            
+        if (pRedY != (unsigned short *)0)
+        {
+            *pRedY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redY << 2) + 
+                                                  (unsigned short)pEDIDStructure->redGreenLowBits.redYLowBits);
+        }
+            
+        if (pGreenX != (unsigned short *)0)
+        {
+            *pGreenX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenX << 2) + 
+                                                    (unsigned short)pEDIDStructure->redGreenLowBits.greenXLowBits);
+        }
+            
+        if (pGreenY != (unsigned short *)0)
+        {
+            *pGreenY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenY << 2) + 
+                                                    (unsigned short)pEDIDStructure->redGreenLowBits.greenYLowBits);
+        }
+            
+        if (pBlueX != (unsigned short *)0)
+        {
+            *pBlueX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueX << 2) +
+                                                   (unsigned short)pEDIDStructure->blueWhiteLowBits.blueXLowBits);
+        }
+            
+        if (pBlueY != (unsigned short *)0)
+        {
+            *pBlueY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueY << 2) +
+                                                   (unsigned short)pEDIDStructure->blueWhiteLowBits.blueYLowBits);
+        }
+    }
+}
+
+/*
+ *  ddk768_edidGetWhitePoint
+ *      This function gets the white point.
+ *      To get the default white point, set the index to 0. For multiple white point,
+ *      call this function multiple times to check if more than 1 white point is supported.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pWhitePointIndex    - Pointer to a variable that contains the white point index 
+ *                            to be retrieved.
+ *      pWhiteX             - Pointer to a variable to store the White X value
+ *      pWhiteY             - Pointer to a variable to store the White Y value
+ *      pWhiteGamma         - Pointer to a variable to store the White Gamma value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetWhitePoint(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pWhitePointIndex,
+    unsigned short *pWhiteX,
+    unsigned short *pWhiteY,
+    unsigned short *pWhiteGamma
+)
+{
+    unsigned char version, index, tableIndex;
+    
+    if (pWhitePointIndex == (unsigned char *)0)
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        /* Get the index to a temporary variable and increment the index for the
+           next loop. */
+        index = *pWhitePointIndex;
+        (*pWhitePointIndex)++;
+        
+        if (index == 0)
+        {
+            if (pWhiteX != (unsigned short *)0)
+            {
+                *pWhiteX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteX << 2) +
+                                                        (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteXLowBits);
+            }
+            
+            if (pWhiteY != (unsigned short *)0)
+            {
+                *pWhiteY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteY << 2) +
+                                                        (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteYLowBits);
+            }
+            
+            if (pWhiteGamma != (unsigned short *)0)
+                *pWhiteGamma = pEDIDStructure->displayTransferChar + 100;
+                
+            return 0;
+        }
+        else
+        {
+            for (tableIndex = 0; tableIndex < 4; tableIndex++)
+            {
+                pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+                if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                    (pMonitorDescriptor->dataTypeTag == 0xFB) && 
+                    (pMonitorDescriptor->descriptor.colorPoint.white[index-1].whitePointIndex != 0))
+                {
+                    if (pWhiteX != (unsigned short *)0)
+                    {
+                        *pWhiteX = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteX << 2) +
+                                                                (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteXLowBits);
+                    }
+                    
+                    if (pWhiteY != (unsigned short *)0)
+                    {
+                        *pWhiteY = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteY << 2) +
+                                                                (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteYLowBits);
+                    }
+                    
+                    if (pWhiteGamma != (unsigned short *)0)
+                        *pWhiteGamma = pMonitorDescriptor->descriptor.colorPoint.white[index-1].gamma + 100;
+                    
+                    return 0;
+                }
+            }
+        }
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidCalculateChecksum
+ *      This function adds all one-byte value of the EDID buffer. 
+ *      The total should be equal to 0x00
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total of one-byte values. It should equal to 0x00. A value other than
+ *      0x00 indicates the EDID buffer is not valid.
+ */
+__attribute__((unused)) static unsigned char edidCalculateChecksum(
+    unsigned char *pEDIDBuffer)
+{
+    unsigned char version, revision, checksum;
+    unsigned short index;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    checksum = 0;
+    if (version == 1)
+    {
+        for (index = 0; index < 128; index++)
+            checksum += pEDIDBuffer[index];
+    }
+    
+    return checksum;
+}
+
+/*
+ *  ddk768_edidGetExtension
+ *      This function gets the number of (optional) EDID extension blocks to follow
+ *      the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total number of EDID Extension to follow the given EDID buffer.
+ */
+unsigned char ddk768_edidGetExtension(
+    unsigned char *pEDIDBuffer
+)
+{
+    unsigned char version, revision;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+        return ((edid_version_1_t *)pEDIDBuffer)->extFlag;
+    
+    return 0;
+}
+
+#if 0
+#define EDID_TOTAL_RETRY_COUNTER            1
+/*
+ *  ddk768_edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Fail
+ *      edidSize   - Success and return the edid's size
+ */
+long ddk768_edidReadMonitorEx(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+)
+{
+    unsigned char retry, edidVersion, edidRevision;
+    unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256];
+    unsigned long offset;
+    long edidSize = TOTAL_EDID_REGISTERS_128;
+
+    /* Initialize the i2c bus */
+    ddk768_swI2CInit(sclGpio, sdaGpio);
+
+
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+       // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+
+#ifndef  READ_EDID_CONTINUOUS	            
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++)
+            edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+#else
+			if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0,TOTAL_EDID_REGISTERS_128,edidBuffer))
+ 		           memset(edidBuffer, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */
+#endif
+
+         	if(edidBuffer[EDID_EXTEND_BLOCK])
+       	 	{
+#ifndef READ_EDID_CONTINUOUS
+				for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++)
+                	edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+#else
+				if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, TOTAL_EDID_REGISTERS_128, TOTAL_EDID_REGISTERS_128, edidBuffer + TOTAL_EDID_REGISTERS_128))
+                	memset(edidBuffer + TOTAL_EDID_REGISTERS_128, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */
+#endif
+
+            	edidSize = TOTAL_EDID_REGISTERS_256;
+         	}	
+
+        /* Check if the EDID is valid. */
+        edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); 
+        if (edidVersion != 0)
+            break;
+        
+        ddk768_swI2CCleanBus(sclGpio, sdaGpio);
+    }
+    
+    /* 
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return 0;
+    }
+
+    /* Copy the data to the given buffer */
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        for (offset = 0; offset < edidSize; offset++)
+            pEDIDBuffer[offset] = edidBuffer[offset];
+    }
+
+    return edidSize;
+}
+
+/*
+ *  This function is same as editReadMonitorEx(), but using HW I2C.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      i2cNumber   - 0 = I2C0 and 1 = I2C1
+ *
+ *  Output:
+ *      0   - Fail
+ *     edidSize   - Success and return the edid's size.
+ */
+long ddk768_edidReadMonitorExHwI2C(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+)
+{
+    unsigned char  retry, edidVersion, edidRevision;
+    unsigned long value;
+    unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256];
+    unsigned long offset;
+    long edidSize = 0;
+    
+    /* Initialize the i2c bus */
+    ddk768_hwI2CInit(i2cNumber);
+#if 0
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+       // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+            
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++)
+            edidBuffer[offset] = ddk768_hwI2CReadReg(i2cNumber, EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+            
+        /* Check if the EDID is valid. */
+        edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+      //  DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); 
+        if (edidVersion != 0)
+            break;
+    }
+#else
+	
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        //DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+		edidSize = 0;
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++)
+        {
+            value = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+            if(0xFFFFFFFF == value)
+                break;
+            edidBuffer[offset] = (0xFF & value);
+        }
+        if(0xFFFFFFFF != value)
+        {
+          	edidSize = TOTAL_EDID_REGISTERS_128;
+            if(edidBuffer[EDID_EXTEND_BLOCK])
+            {
+                for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++)
+                {
+                    value = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+
+                    if(0xFFFFFFFF == value)
+                        break;
+                    edidBuffer[offset] = (0xFF & value);
+                }
+
+                if(0xFFFFFFFF != value)
+                	edidSize = TOTAL_EDID_REGISTERS_256;
+            }
+            if(0xFFFFFFFF != value)
+            {
+                /* Check if the EDID is valid. */
+                edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision);
+           //     DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision));
+                if (edidVersion != 0)
+                    break;
+            }
+        }
+    }
+#endif
+
+    /* Finish using HW I2C, we can close the device. */
+    ddk768_hwI2CClose(i2cNumber);
+    
+     /*
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return 0;
+    }
+
+    /* Copy the data to the given buffer */
+    if (pEDIDBuffer != (unsigned char *)0)
+    {
+        for (offset = 0; offset < edidSize; offset++)
+            pEDIDBuffer[offset] = edidBuffer[offset];
+    }
+
+    return edidSize;
+}
+
+
+
+/*
+ *  ddk768_edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      i2cNumber   - 0 = I2c0 and 1 = 12c1
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidReadMonitor(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+)
+{
+
+	unsigned char i2cSCL, i2cSDA;
+
+    if (i2cNumber == 0)
+    {
+        i2cSCL = DEFAULT_I2C0_SCL;
+        i2cSDA = DEFAULT_I2C0_SDA;
+    }
+    else
+    {
+        i2cSCL = DEFAULT_I2C1_SCL;
+        i2cSDA = DEFAULT_I2C1_SDA;
+    }
+
+    return ddk768_edidReadMonitorEx(pEDIDBuffer, bufferSize, edidExtNo, i2cSCL, i2cSDA);
+}
+
+
+/*
+ *  edidHeaderReadMonitor
+ *      This function reads the EDID header from the attached monitor
+ *
+ *  Input:
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidHeaderReadMonitorEx(
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+)
+{
+    unsigned char retry;//value,
+    unsigned char edidBuffer[10];
+#ifndef READ_EDID_CONTINUOUS
+    unsigned long offset;
+#endif    
+
+    /* Initialize the i2c bus */
+    ddk768_swI2CInit(sclGpio, sdaGpio);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+
+#ifndef READ_EDID_CONTINUOUS
+		/* Read the EDID from the monitor. */
+		for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++)
+			edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+
+#else
+		if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, HEADER_EDID_REGISTERS, edidBuffer))
+			memset(edidBuffer, 0xFF, HEADER_EDID_REGISTERS); /* read error */
+#endif
+
+        /* Check if the EDID header is valid. */
+        if (!edidGetHeader((unsigned char *)&edidBuffer))
+            break;
+        ddk768_swI2CCleanBus(sclGpio, sdaGpio);
+    }
+
+    /*
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+
+    return 0;
+}
+
+long ddk768_edidHeaderReadMonitorExHwI2C(
+    unsigned char i2cNumber
+)
+{
+    unsigned char retry;//value,
+    unsigned char edidBuffer[10];
+    unsigned long offset;
+
+    /* Initialize the i2c bus */
+    ddk768_hwI2CInit(i2cNumber);
+
+    for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++)
+    {
+        DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry));
+
+        /* Read the EDID from the monitor. */
+        for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++)
+            edidBuffer[offset] = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset);
+
+        /* Check if the EDID header is valid. */
+        if (!edidGetHeader((unsigned char *)&edidBuffer))
+            break;
+    }
+
+	/* Finish using HW I2C, we can close the device. */
+    ddk768_hwI2CClose(i2cNumber);
+
+    /*
+     *  The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol,
+     *  which uses the Vertical Sync to clock in the EDID data.
+     *  Currently this function return error. DDC1 protocol can be added later.
+     */
+    if (retry == EDID_TOTAL_RETRY_COUNTER)
+    {
+        /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is
+         * only an acknowledge flag, which could be high or low. However, SCL line
+         * is not used. Instead the data is clock-in using vertical sync.
+         */
+        return (-1);
+    }
+
+    return 0;
+}
+
+#endif
+
+/*
+ *  ddk768_edidGetEstablishedTiming
+ *      This function gets the established timing list from the given EDID buffer,
+ *      table, and timing index.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor (In)
+ *      pEstTableIndex  - Pointer to the Established Timing Table index  (In/Out)
+ *      pIndex          - Pointer to the Establihsed Timing Index (In/Out)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *      pSource         - Pointer to a variable to store the standard timing source:
+ *                          0 - VESA
+ *                          1 - IBM
+ *                          2 - Apple
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetEstablishedTiming(
+    unsigned char *pEDIDBuffer,
+    /*unsigned char *pEstTableIndex,*/
+    unsigned char *pIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate,
+    unsigned char *pSource
+)
+{
+    unsigned char version, revision;
+    unsigned char tableIndex, index;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            /* Get index */
+            index = *pIndex;
+            
+            if (index > 16)
+                break;
+            
+            /* Search Established Table index 0 when the index is less than 8 */
+            tableIndex = index / 8;
+            
+            /* Exit the function when it has reached the last table. */
+            if (tableIndex > 2)
+                break;
+            
+            /* Increment the index value and update the index accordingly */
+            (*pIndex)++;
+            index %= 8;
+            
+            /* Check */
+            if ((pEDIDStructure->estTiming[tableIndex] & (1 << index)) != 0)
+            {
+                if (pWidth != (unsigned long *)0)
+                    *pWidth = establishTiming[tableIndex][index].x;
+        
+                if (pHeight != (unsigned long *)0)
+                    *pHeight = establishTiming[tableIndex][index].y;
+    
+                if (pRefreshRate != (unsigned long *)0)
+                    *pRefreshRate = establishTiming[tableIndex][index].hz;
+    
+                if (pSource != (unsigned char *)0)
+                    *pSource = establishTiming[tableIndex][index].source;
+                    
+                /* Return success */
+                return 0;
+            }
+        }
+    }
+    else
+    {
+        /* EDID Structure Version 2.0. */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  edidCalculateStdTiming
+ *      This function calculates the width, height, and vertical frequency values
+ *      from the given Standard Timing structure. This function only applies to
+ *      EDID structure version 1. It will give the wrong result when used with
+ *      EDID version 2.
+ *
+ *  Input:
+ *      pStdTiming      - Pointer to a standard timing structure that contains the
+ *                        standard timing value to be calculated (In)
+ *      edid1Revision   - Revision of the EDID 1 (In)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+static long edidCalculateStdTiming(
+    standard_timing_t *pStdTiming,
+    unsigned char edid1Revision,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+)
+{
+    unsigned long x, y;
+     
+    /* Calculate the standard timing into x and y mode dimension */
+    if (pStdTiming->horzActive != 0x01)
+    {
+        /* Calculate the X and Y */
+        x = (pStdTiming->horzActive + 31) * 8;
+        switch (pStdTiming->stdTimingInfo.aspectRatio)
+        {
+            case 0:
+                if (edid1Revision != 3)
+                    y = x;                  /* 1:1 aspect ratio (prior revision 1.3) */
+                else
+                    y = x * 10 / 16;        /* 16:10 aspect ratio (revision 1.3) */
+                break;
+            case 1:
+                y = x * 3 / 4;              /* 4:3 aspect ratio */
+                break;
+            case 2:
+                y = x * 4 / 5;              /* 5:4 aspect ratio */
+                break;
+            case 3:
+                y = x * 9 / 16;             /* 16:9 aspect ratio */
+                break;
+        }
+
+        if (pWidth != (unsigned long *)0)
+            *pWidth = x;
+
+        if (pHeight != (unsigned long *)0)
+            *pHeight = y;
+
+        if (pRefreshRate != (unsigned long *)0)
+            *pRefreshRate = pStdTiming->stdTimingInfo.refreshRate + 60;
+    
+        return 0;
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetStandardTiming
+ *      This function gets the standard timing from the given EDID buffer and
+ *      calculates the width, height, and vertical frequency from that timing.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStdTimingIndex - Pointer to a standard timing index to be retrieved
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetStandardTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStdTimingIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+)
+{
+    unsigned char version, revision, timingIndex, tableIndex;
+  
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            /* There are only 8 standard timing entries */
+            if (*pStdTimingIndex > 7)
+                break;
+            
+            /* Get the table index first before incrementing the index. */
+            timingIndex = *pStdTimingIndex;
+            
+            /* Increment the standard timing index */
+            (*pStdTimingIndex)++;
+            
+            if (timingIndex < 8)
+            {
+                /*
+                 *  Search the first Standard Timing Identifier table
+                 */
+                 
+                /* Calculate the standard timing into x and y mode dimension */
+                if (edidCalculateStdTiming(&pEDIDStructure->stdTiming[timingIndex], 
+                                       revision, pWidth, pHeight, pRefreshRate) == 0)
+                {
+                    return 0;
+                }
+            }
+            else
+            {
+                /*
+                 *  Search Standard Timing Identifier Table in the detailed Timing block. 
+                 */
+                
+                /* 
+                 * Each Detailed Timing Identifier can contains 6 entries of Standard Timing
+                 * Identifier. Based on this value, we can get the Detailed Timing Table Index
+                 * that contains the requested standard timing.
+                 */
+                timingIndex = timingIndex - 8;
+                for (tableIndex = 0; tableIndex < 4; tableIndex++)
+                {
+                    /* Get detailed info */
+                    pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+                    if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                        (pMonitorDescriptor->dataTypeTag == 0xFA))
+                    {
+                        if (timingIndex >= 6)
+                        {
+                            timingIndex-=6;
+                            continue;
+                        }
+                        else
+                        {
+                            if (edidCalculateStdTiming(&pMonitorDescriptor->descriptor.stdTimingExt.stdTiming[timingIndex], 
+                                                   revision, pWidth, pHeight, pRefreshRate) == 0)
+                            {
+                                return 0;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        /* EDID Structure version 2 */
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetDetailedTiming
+ *      This function gets the detailed timing from the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pDetailedTimingIndex    - Pointer to a detailed timing index to be retrieved
+ *      pModeParameter          - Pointer to a mode_parameter_t structure that will be
+ *                                filled with the detailed timing.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDetailedTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDetailedTimingIndex,
+    vdif_t *pVDIF
+)
+{
+    unsigned char version, revision, tableIndex;
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        detailed_timing_t *pDetailedTiming;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        while (1)
+        {
+            if (*pDetailedTimingIndex > 3)
+                break;
+            
+            /* Get the Detail Timing entry index */
+            tableIndex = *pDetailedTimingIndex;
+            
+            /* Increment the index */
+            (*pDetailedTimingIndex)++;
+                
+            /* Get detailed info */
+            pDetailedTiming = &pEDIDStructure->miscInformation.detailTiming[tableIndex];
+            if ((pDetailedTiming->pixelClock != 0) && (pVDIF != (vdif_t *)0))
+            {
+                /* Translate the Detail timing to VDIF format. */
+                pVDIF->pixelClock = (unsigned long)pDetailedTiming->pixelClock * 10000;
+                pVDIF->characterWidth = 8;
+                pVDIF->scanType = (pDetailedTiming->flags.interlaced == 0) ? VDIF_NONINTERLACED : VDIF_INTERLACED;
+
+                pVDIF->horizontalActive = 
+                    ((unsigned long)pDetailedTiming->horzActiveBlanking.horzActiveMSB << 8) +
+                     (unsigned long)pDetailedTiming->horzActive;
+                pVDIF->horizontalBlankStart = pVDIF->horizontalActive;
+                pVDIF->horizontalBlankTime = 
+                    ((unsigned long)pDetailedTiming->horzActiveBlanking.horzBlankingMSB << 8) +
+                     (unsigned long)pDetailedTiming->horzBlanking;
+                pVDIF->horizontalTotal = pVDIF->horizontalActive + pVDIF->horizontalBlankTime;
+                pVDIF->horizontalFrontPorch = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncOffset << 8) + 
+                     (unsigned long)pDetailedTiming->horzSyncOffset;
+                pVDIF->horizontalSyncStart = pVDIF->horizontalBlankStart + pVDIF->horizontalFrontPorch;
+                pVDIF->horizontalSyncWidth = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncWidth << 8) +
+                     (unsigned long)pDetailedTiming->horzSyncPulseWidth;                     
+                pVDIF->horizontalBackPorch = 
+                    pVDIF->horizontalBlankTime - (pVDIF->horizontalFrontPorch + pVDIF->horizontalSyncWidth);
+                pVDIF->horizontalFrequency = ddk768_roundedDiv(pVDIF->pixelClock, pVDIF->horizontalTotal);
+                pVDIF->horizontalLeftBorder = 0;
+                pVDIF->horizontalRightBorder = 0;
+        
+                pVDIF->verticalActive = 
+                    ((unsigned long)pDetailedTiming->vertActiveBlanking.vertActiveMSB << 8) +
+                     (unsigned long)pDetailedTiming->vertActive;
+                pVDIF->verticalBlankStart = pVDIF->verticalActive;
+                pVDIF->verticalBlankTime =
+                    ((unsigned long)pDetailedTiming->vertActiveBlanking.vertBlankingMSB << 8) +
+                     (unsigned long)pDetailedTiming->vertBlanking;
+                pVDIF->verticalTotal = pVDIF->verticalActive + pVDIF->verticalBlankTime;
+                pVDIF->verticalFrontPorch = 
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncOffset << 8) +
+                     (unsigned long)pDetailedTiming->verticalSyncInfo.syncOffset;
+                pVDIF->verticalSyncStart = pVDIF->verticalBlankStart + pVDIF->verticalFrontPorch;
+                pVDIF->verticalSyncHeight =
+                    ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncWidth  << 8) +
+                     (unsigned long)pDetailedTiming->verticalSyncInfo.syncWidth;
+                pVDIF->verticalBackPorch =
+                    pVDIF->verticalBlankTime - (pVDIF->verticalFrontPorch + pVDIF->verticalSyncHeight);
+                pVDIF->verticalFrequency =
+                    ddk768_roundedDiv(pVDIF->pixelClock, (pVDIF->horizontalTotal * pVDIF->verticalTotal));
+                pVDIF->verticalTopBorder = 0;
+                pVDIF->verticalBottomBorder = 0;
+                
+                if (pDetailedTiming->flags.connectionType == 3)
+                {
+                    pVDIF->verticalSyncPolarity = 
+                        (pDetailedTiming->flags.vertSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE;
+                    pVDIF->horizontalSyncPolarity = 
+                        (pDetailedTiming->flags.horzSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE;
+                }
+                else
+                {
+                    pVDIF->verticalSyncPolarity = VDIF_SYNC_NEGATIVE;
+                    pVDIF->horizontalSyncPolarity = VDIF_SYNC_NEGATIVE;
+                }
+                
+                /* For debugging purpose. */
+                printVdif(pVDIF);
+                
+                return 0;
+            }
+        }
+    }
+    
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetMonitorSerialNumber
+ *      This function gets the monitor serial number from the EDID structure.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the serial number 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the serial number.
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorSerialNumber(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorSerialNumber,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pMonitorSerialNumber == (char *)0) || (bufferSize == 0))
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFF))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.serialNo[charIndex] == 0x0A)
+                    {
+                        pMonitorSerialNumber[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pMonitorSerialNumber[charIndex] = pMonitorDescriptor->descriptor.serialNo[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Serial Number is not found. */
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetDataString
+ *      This function gets the data string from the EDID 
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the data string 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the data string
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDataString(
+    unsigned char *pEDIDBuffer,
+    char *pDataString,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pDataString == (char *)0) || (bufferSize == 0))
+        return (-1);
+    
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFE))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.dataString[charIndex] == 0x0A)
+                    {
+                        pDataString[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pDataString[charIndex] = pMonitorDescriptor->descriptor.dataString[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetMonitorRangeLimit
+ *      This function gets the monitor range limits from the EDID structure.
+ *      Only EDID version 1 revision 1 or above supports this feature.
+ *      This is a required field in EDID Version 1.3
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMinVerticalRate    - Pointer to a variable to store the Minimum Vertical Rate (Hz)
+ *      pMaxVerticalRate    - Pointer to a variable to store the Maximum Vertical Rate (Hz)
+ *      pMinHorzFreq        - Pointer to a variable to store the Minimum Horz. Freq (kHz)
+ *      pMaxHorzFreq        - Pointer to a variable to store the Maximum Horz. Freq (kHz)
+ *      pMaxPixelClock      - Pointer to a variable to store the Maximum Pixel Clock (Hz)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorRangeLimit(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMinVerticalRate,
+    unsigned char *pMaxVerticalRate,
+    unsigned char *pMinHorzFreq,
+    unsigned char *pMaxHorzFreq,
+    unsigned long *pMaxPixelClock
+)
+{
+    unsigned char version, revision, tableIndex;
+    
+    if (pEDIDBuffer == (unsigned char *)0)
+        return (-1);
+            
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFD) && (pMonitorDescriptor->flag3 == 0))
+            {
+                if (pMinVerticalRate != (unsigned char *)0)
+                    *pMinVerticalRate = pMonitorDescriptor->descriptor.monitorRange.minVertRate;
+
+                if (pMaxVerticalRate != (unsigned char *)0)
+                    *pMaxVerticalRate = pMonitorDescriptor->descriptor.monitorRange.maxVertRate;
+                    
+                if (pMinHorzFreq != (unsigned char *)0)
+                    *pMinHorzFreq = pMonitorDescriptor->descriptor.monitorRange.minHorzFrequency;
+                    
+                if (pMaxHorzFreq != (unsigned char *)0)
+                    *pMaxHorzFreq = pMonitorDescriptor->descriptor.monitorRange.maxHorzFrequency;
+                    
+                if (pMaxPixelClock != (unsigned long *)0)
+                    *pMaxPixelClock = (unsigned long) pMonitorDescriptor->descriptor.monitorRange.maxPixelClock * 10 * 1000000;
+                    
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  edidGetChannel1TimingSupport
+ *      This function gets the secondary GTF timing support.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pStartFrequency         - Pointer to a variable to store the start frequency of 
+ *                                the secondary GTF
+ *      pOffset                 - Pointer to a variable to store the Offset (C) value of
+ *                                the secondary GTF
+ *      pGradient               - Pointer to a variable to store the Gradient (M) value of
+ *                                the secondary GTF
+ *      pScalingFactor          - Pointer to a variable to store the Scaling Factor (K)
+ *                                value of the secondary GTF
+ *      pScalingFactorWeight    - Pointer to a variable to store the Scaling Factore Weight (J)
+ *                                value of the secondary GTF
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetChannel1TimingSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pStartFrequency,
+    unsigned char *pOffset,
+    unsigned short *pGradient,
+    unsigned char *pScalingFactor,
+    unsigned char *pScalingFactorWeight
+)
+{
+    unsigned char version, revision, tableIndex;
+            
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if ((version == 1) && (revision > 0) && (pEDIDBuffer != (unsigned char *)0))
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFD) && 
+                (pMonitorDescriptor->descriptor.monitorRange.secondaryTimingFlag == 0x02))
+            {
+                if (pStartFrequency != (unsigned short *)0)
+                    *pStartFrequency = (unsigned short)
+                        pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.startFrequency * 2 * 1000;
+
+                if (pOffset != (unsigned char *)0)
+                    *pOffset = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.cParam/2;
+                    
+                if (pGradient != (unsigned short *)0)
+                    *pGradient = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.mParam;
+                    
+                if (pScalingFactor != (unsigned char *)0)
+                    *pScalingFactor = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.kParam;
+                    
+                if (pScalingFactorWeight != (unsigned char *)0)
+                    *pScalingFactorWeight = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.jParam / 2;
+                    
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetMonitorName
+ *      This function gets the monitor name from the EDID structure.
+ *      This is a required field in EDID Version 1.3
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorName            - Pointer to a buffer to store the monitor name 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the monitor name
+ *                                The maximum size required is 13 bytes.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorName(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorName,
+    unsigned char bufferSize
+)
+{
+    unsigned char version, revision, tableIndex, charIndex;
+    
+    /* If no pointer is given or the buffer size is set to 0, then return fail. */
+    if ((pMonitorName == (char *)0) || (bufferSize == 0))
+        return (-1);
+        
+    /* Get EDID Version and revision */
+    version = ddk768_edidGetVersion(pEDIDBuffer, &revision);
+    
+    if (version == 1)
+    {
+        edid_version_1_t *pEDIDStructure;
+        monitor_desc_t *pMonitorDescriptor;
+        
+        /* EDID Structure Version 1. */
+        pEDIDStructure = (edid_version_1_t *)pEDIDBuffer;
+        for (tableIndex = 0; tableIndex < 4; tableIndex++)
+        {
+            pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex];
+            if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) &&
+                (pMonitorDescriptor->dataTypeTag == 0xFC) && (pMonitorDescriptor->flag3 == 0))
+            {
+                bufferSize = (bufferSize > 13) ? 13 : bufferSize;
+                for (charIndex = 0; charIndex < 13; charIndex++)
+                {
+                    if (pMonitorDescriptor->descriptor.monitorName[charIndex] == 0x0A)
+                    {
+                        pMonitorName[charIndex] = '\0';
+                        break;
+                    }
+                        
+                    pMonitorName[charIndex] = pMonitorDescriptor->descriptor.monitorName[charIndex];
+                }
+                
+                return 0;
+            }
+        }
+    }
+    
+    /* Data String is not found. */
+    return (-1);
+}
+
+/*
+ *  ddk768_edidGetPreferredTiming
+ *      This function gets the preferred/native timing of the monitor
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWidth              - Pointer to an unsigned long buffer to store the width 
+ *                            of the preferred (native) timing.
+ *      pHeight             - Pointer to an unsigned long buffer to store the height
+ *                            of the preferred (native) timing.
+ *      pVerticalFrequency  - Pointer to an unsigned long buffer to store the refresh
+ *                            rate of the preferred (native) timing.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetPreferredTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pVerticalFrequency
+)
+{
+    unsigned char index = 0;
+    vdif_t vdifBuffer;
+
+
+    {
+        /* The preferred (native) timing is available, so get the timing. It is located
+           at the first index of detailed timing.
+         */
+        if (ddk768_edidGetDetailedTiming(pEDIDBuffer, &index, &vdifBuffer) == 0)
+        {
+            if (pWidth != (unsigned long *)0)
+                *pWidth = vdifBuffer.horizontalActive;
+                
+            if (pHeight != (unsigned long *)0)
+                *pHeight = vdifBuffer.verticalActive;
+                
+            if (pVerticalFrequency != (unsigned long *)0)
+                *pVerticalFrequency = vdifBuffer.verticalFrequency;
+                
+            return 0;
+        }
+    }
+    
+    return (-1);
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.h
new file mode 100644
index 000000000000..b6e98252c012
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_edid.h
@@ -0,0 +1,1051 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  edid.h --- SMI DDK 
+*  This file contains the EDID structure and function API to
+*  interpret the EDID
+* 
+*******************************************************************/
+#ifndef _EDID_H_
+#define _EDID_H_
+
+#include "ddk768_display.h"
+#include "vdif.h"
+
+#define EDID_DEVICE_I2C_ADDRESS             0xA0
+#define TOTAL_EDID_REGISTERS                128
+
+/* Set the alignment to 1-bit aligned. Otherwise, it can't get the EDID correctly. */
+#pragma pack(1)
+
+#define TOTAL_EDID_REGISTERS_128                128
+#define TOTAL_EDID_REGISTERS_256                256
+#define EDID_EXTEND_BLOCK         126
+#define READ_EDID_CONTINUOUS
+
+
+/* Standard Timing Structure */
+typedef struct _standard_timing_t
+{
+    unsigned char horzActive;       /* (Horizontal active pixels / 8 ) - 31 */
+    struct
+    {
+        unsigned char refreshRate:6;    /* Refresh Rate (Hz) - 60; Range 60 --> 123 */
+        unsigned char aspectRatio:2;    /* Aspect Ratio:
+                                            Bit 7   Bit 6   Operation
+                                              0       0        1:1      (prior Version 1.3)
+                                              0       0       16:10     (Version 1.3)
+                                              0       1        4:3
+                                              1       0        5:4
+                                              1       1       16:9
+                                         */
+    } stdTimingInfo;
+} standard_timing_t;
+
+/* Detailed Timing Description Structure */
+typedef struct _detailed_timing_t
+{
+    unsigned short pixelClock;
+    unsigned char horzActive;
+    unsigned char horzBlanking;
+    struct 
+    {
+        unsigned char horzBlankingMSB:4;
+        unsigned char horzActiveMSB:4;
+    } horzActiveBlanking;
+    unsigned char vertActive;
+    unsigned char vertBlanking;
+    struct 
+    {
+        unsigned char vertBlankingMSB:4;
+        unsigned char vertActiveMSB:4;
+    } vertActiveBlanking;
+    unsigned char horzSyncOffset;
+    unsigned char horzSyncPulseWidth;
+    struct
+    {
+        unsigned char syncWidth:4;
+        unsigned char syncOffset:4;
+    } verticalSyncInfo;
+    struct
+    {
+        unsigned char vertSyncWidth:2;
+        unsigned char vertSyncOffset:2;
+        unsigned char horzSyncWidth:2;
+        unsigned char horzSyncOffset:2;
+    } syncAuxInfo;
+    unsigned char horzImageSize;
+    unsigned char vertImageSize;
+    struct
+    {
+        unsigned char vertImageSizeMSB:4;
+        unsigned char horzImageSizeMSB:4;
+    } horzVertImageSize;
+    unsigned char horzBorder;
+    unsigned char vertBorder;
+    struct
+    {
+        unsigned char interleaved:1;
+        unsigned char horzSyncFlag:1;
+        unsigned char vertSyncFlag:1;
+        unsigned char connectionType:2;
+        unsigned char stereo:2;
+        unsigned char interlaced:1;
+    } flags;
+} detailed_timing_t;
+
+typedef struct _color_point_t
+{
+    unsigned char whitePointIndex;
+    struct
+    {
+        unsigned char whiteYLowBits:2;
+        unsigned char whiteXLowBits:2;
+        unsigned char reserved:4;
+    } whiteLowBits;
+    unsigned char whiteX;
+    unsigned char whiteY;
+    unsigned char gamma;
+} color_point_t;
+
+typedef struct _monitor_desc_t
+{
+    unsigned short flag1;               /* Flag = 0000h when block used as descriptor */
+    unsigned char flag2;                /* Flag = 00h when block used as descriptor */
+    unsigned char dataTypeTag;          /* Data type tag:
+                                                FFh: Monitor Serial Number - Stored as ASCII, 
+                                                     code page #437, <= 13bytes
+                                                FEh: ASCII String - Stored as ASCII, code 
+                                                     page #437, <= 13 bytes
+                                                FDh: Monitor range limits, binary coded
+                                                FCh: Monitor name, stored as ASCII, code page #437
+                                                FBh: Descriptor contains additional color point data
+                                                FAh: Descriptor contains additional Standard Timing
+                                                     Identifications
+                                                F9h-11h: Currently undefined
+                                                10h: Dummy descriptor, used to indicate 
+                                                     that the descriptor space is unused
+                                                0Fh-00h: Descriptor defined by manufacturer.
+                                         */
+    unsigned char flag3;                /* Flag = 00h when block used as descriptor */
+    union
+    {
+        unsigned char serialNo[13];
+        unsigned char dataString[13];
+        struct
+        {
+            unsigned char minVertRate;
+            unsigned char maxVertRate;
+            unsigned char minHorzFrequency;
+            unsigned char maxHorzFrequency;
+            unsigned char maxPixelClock;        /* Binary coded clock rate in MHz / 10 
+                                                   Max Pixel Clock those are not a multiple of 10MHz
+                                                   is rounded up to a multiple of 10MHz
+                                                 */
+            unsigned char secondaryTimingFlag;  /* 00h = No secondary timing formula supported
+                                                   (Support for default GTF indicated in feature byte)
+                                                   02h = Channel1 GTF curve supported
+                                                   All other = Reserved for future timing formula
+                                                               definitions.
+                                                 */
+            union
+            {
+                unsigned char constantStr[7];
+                struct
+                {
+                    unsigned char reserved;
+                    unsigned char startFrequency;
+                    unsigned char cParam;
+                    unsigned short mParam;
+                    unsigned char kParam;
+                    unsigned char jParam;
+                } cmkjParam;
+            } secondaryTimingInfo;
+        } monitorRange;
+        
+        unsigned char monitorName[13];
+        struct
+        {
+            color_point_t white[2];
+            unsigned char reserved[3];          /* Set to (0Ah, 20h, 20h)*/
+        } colorPoint;
+        
+        struct
+        {
+            standard_timing_t stdTiming[6];
+            unsigned char reserved;             /* Set to 0Ah */
+        } stdTimingExt;
+        
+        unsigned char manufactureSpecifics[13];
+    } descriptor; 
+}
+monitor_desc_t;
+
+/* EDID Structuve Version 1. Within version 1 itself, there are 4 revisions mentioned
+   below: 
+    - EDID 1.0: The original 128-byte data format
+    - EDID 1.1: Added definitions for monitor descriptors as an alternate use of the space 
+                originally reserved for detailed timings, as well as definitions for 
+                previously unused fields.
+    - EDID 1.2: Added definitions to existing data fields.
+    - EDID 1.3: Added definitions for secondary GTF curve coefficients. This is the new
+                baseline for EDID data structures, which is recommended for all new monitor
+                designs.
+ */
+typedef struct _edid_version_1_t
+{
+    /* Header (8 bytes) */
+    unsigned char header[8];            /* Header */
+    
+    /* Vendor / Product ID (10 bytes) */
+    unsigned short manufacturerID;      /* Manufacture Identification */
+    unsigned short productCode;         /* Product code Identification */ 
+    unsigned long serialNumber;         /* Serial Number */
+    unsigned char weekOfManufacture;    /* Week of Manufacture */
+    unsigned char yearOfManufacture;    /* Year of Manufacture */
+    
+    /* EDID Structure version / revision (2 bytes) */
+    unsigned char version;              /* EDID Structure Version no. */
+    unsigned char revision;             /* Revision Version no. */
+    
+    /* Basic Display Parameters / Features (5 bytes) */
+    union
+    {
+        struct
+        {
+            unsigned char vsyncSerration:1;
+            unsigned char syncOnGreenSupport:1;
+            unsigned char compositeSyncSupport:1;
+            unsigned char separateSyncSupport:1;
+            unsigned char blank2Black:1;
+            unsigned char signalLevelStd:2;
+            unsigned char inputSignal:1;    /* Input Signal: Analog = 0, Digital = 1 */
+        } analogSignal;
+        struct
+        {
+            unsigned char dfp1Support:1;
+            unsigned char reserved:6;
+            unsigned char inputSignal:1;    /* Input Signal: Analog = 0, Digital = 1 */
+        } digitalSignal;
+    } videoInputDefinition;             /* Video Input Definition */
+
+    unsigned char maxHorzImageSize;     /* Maximum Horizontal Image Size */
+    unsigned char maxVertImageSize;     /* Maximum Vertical Image Size */
+    unsigned char displayTransferChar;  /* Display Transfer Characteristic (Gamma) */
+    struct
+    {
+        unsigned char defaultGTFSupport:1;  /* Support timings based on the GTF standard using
+                                               default GTF parameters 
+                                             */ 
+        unsigned char preferredTiming:1;    /* If set, the display's preferred timing mode is
+                                               indicated in the first detailed timing block.
+                                             */
+        unsigned char sRGBSupport:1;        /* If set, the display uses the sRGB standard
+                                               default color space as its primary color space
+                                             */
+        unsigned char displayType:2;        /* Display Type:
+                                                    00  - Monochrome / Grayscale display
+                                                    01  - RGB Color Display
+                                                    10  - Non-RGB multicolor display, e.g. R/G/Y
+                                                    11  - Undefined
+                                             */
+        unsigned char lowPowerSupport:1;    /* If set, the display consumes much less power when
+                                               it receives a timing signal outside its active
+                                               operating range. It will revert to normal if the
+                                               timing returns to the normal operating range.
+                                             */
+        unsigned char suspendSupport:1;     /* Support Suspend as defined in VESA DPMS spec. */
+        unsigned char standbySupport:1;     /* Support Standby as defined in VESA DPMS spec. */
+    } featureSupport;                   /* Feature Support */
+    
+    /* Color Characteristics (10 bytes) */
+    struct
+    {
+        unsigned char greenYLowBits:2;
+        unsigned char greenXLowBits:2;
+        unsigned char redYLowBits:2;
+        unsigned char redXLowBits:2;
+    } redGreenLowBits;                  /* Red/Green Low Bits */
+    struct
+    {
+        unsigned char whiteYLowBits:2;
+        unsigned char whiteXLowBits:2;
+        unsigned char blueYLowBits:2;
+        unsigned char blueXLowBits:2;
+    } blueWhiteLowBits;                 /* Blue/White Low Bits */
+    unsigned char redX;                 /* Red-x bits 9-2 */
+    unsigned char redY;                 /* Red-y bits 9-2 */
+    unsigned char greenX;               /* Green-x bits 9-2 */
+    unsigned char greenY;               /* Green-y bits 9-2 */
+    unsigned char blueX;                /* Blue-x bits 9-2 */
+    unsigned char blueY;                /* Blue-y bits 9-2 */
+    unsigned char whiteX;               /* White-x bits 9-2 */
+    unsigned char whiteY;               /* White-y bits 9-2 */
+    
+    /* Established Timings (3 bytes) */
+    unsigned char estTiming[3];         /* Established Timings */
+    
+    /* Standard Timing Identification (16 bytes) */
+    standard_timing_t stdTiming[8];     /* Standard Timings Identification */
+
+    /* Detailed Timing Descriptions (72 bytes) */
+    union
+    {
+        detailed_timing_t detailTiming[4];  /* Detailed Timing Descriptor */
+        monitor_desc_t monitorDesc[4];  /* Monitor descriptor */
+    } miscInformation;
+    
+    /* Extension Flag (1 byte) */
+    unsigned char extFlag;              /* Number of (optional) 1280byte EDID
+                                           extension blocks to follow. 
+                                         */
+                                         
+    /* Checksum (1 byte) */
+    unsigned char checksum;             /* The 1-byte sum of all 128 bytes in 
+                                           this EDID block shall equal zero. 
+                                         */
+}
+edid_version_1_t;
+
+#if 0   /* Temporary on hold. To be completed later. */
+
+/* EDID Version 2.0. Not widely used. Usually defined for displays that follow 
+   the original VESA Plug & Display (P&D) and Flat Panel Display Interface-2 (FPDI-2)
+   Standards
+ */
+typedef struct _edid_version_2_t
+{
+    /* 
+     * EDID Structure Version/Revision (1 byte) 
+     */
+    unsigned char version:4;
+    unsigned char revision:4;
+    
+    /* 
+     * Vendor / Product ID (7 bytes) 
+     */
+    unsigned short manufacturerID;              /* ID Manufacturer Name */
+    unsigned short productID;                   /* ID Product Code */
+    unsigned char manufactureWeek;              /* Week of Manufacture */
+    unsigned short manufactureYear;             /* Year of Manufacture */
+    
+    /* 
+     * Manufacturer/Product ID string (32 bytes) 
+     */
+    unsigned char productName;                  /* This string is compiresed of both manufacture name 
+                                                   and model name, which are separated using ASCII code 09h.
+                                                   If the entire string is <32 bytes, then it is terminated
+                                                   with ASCII code 0Ah and the field is padded with ASCII 
+                                                   code 20h 
+                                                 */
+                                             
+    /* 
+     * Serial number string (16 bytes) 
+     */
+    unsigned char serianNumber[16];             /* Serial number string. If <16 bytes then the string is
+                                                   terminated with ASCII code 0Ah and the field padded
+                                                   with ASCII code 20h
+                                                 */
+                                             
+    /* 
+     * Unused/Reserved (8 bytes) 
+     */
+    unsigned char reserved[8];
+    
+    /* 
+     * Display Interface Parameters (15 bytes) 
+     */
+    unsigned char secondaryPhysicalIF:4;        /* Look at defaultPhysicalIF description above. */
+    unsigned char defaultPhysicalIF:4;          /* Physical Connector Types. Consists of 2 fields. Bit 7-4
+                                                   indicates the connector for the default interface. If
+                                                   a secondary interface is available, its connector is
+                                                   indicated using bit 3-0. Both fields value description
+                                                   is listed below:
+                                                        0 = None (Not valid for default connector)
+                                                        1 = BNC
+                                                        2 = 15 pin VGA
+                                                        3 = 13w3
+                                                        4 = VESA EVC
+                                                        5 = VESA P&D-D
+                                                        6 = Micro-ribbon Connector (per the VESA P&D standard)
+                                                        7 = IEEE-1394 connector
+                                                        8 = VESA FPDI-2
+                                                        9-E = Reserved
+                                                        F = Non-standard connector
+                                                 */
+    unsigned char secondaryVideoIF:4;           /* Look at the defaultVideoIF description above. */
+    unsigned char defaultVideoIF:4;             /* Video Interface Types. Consists of 2 fields. Bit 7-4
+                                                   defines the default video interface. Bit 3-0 defines
+                                                   the secondary interface. Descriptions of the field is
+                                                   listed below:
+                                                        0 = None (Not valid for default interface)
+                                                        1 = Analog
+                                                        2 = Analog w/ sampled pixel clock
+                                                        3 = TMDS (Transition Minimized Differential Signaling)
+                                                        4 = IEEE-1394-1995
+                                                        5 = LVDS
+                                                        6 = Parallel
+                                                        7-F = Reserved
+                                                 */
+    unsigned char analogIFDataFormat[4];        /* Analog Interface Data Format */
+    unsigned char digitalIFDataFormat[4];       /* Digital Interface Data Format */
+    unsigned char secondaryColorEncodingIF:4;   /* Channel1 Color Encoding Interface */
+    unsigned char defaultColorEncodingIF:4;     /* Color Encoding default Interface */
+    unsigned char primarySubChannel1:4;         /* Supported bit-depth of sub-channel 1 ("Green") 
+                                                   of the Channel0 interface. */
+    unsigned char primarySubChannel0:4;         /* Supported bit-depth of sub-channel 0 ("Red") 
+                                                   of the Channel0 interface. */
+    unsigned char primarySubChannel3:4;         /* Supported bit-depth of sub-channel 3 of the 
+                                                   Channel0 interface. */
+    unsigned char primarySubChannel2:4;         /* Supported bit-depth of sub-channel 2 ("Blue") 
+                                                   of the Channel0 interface. */
+    unsigned char secondarySubChannel1:4;       /* Supported bit-depth of sub-channel 1 ("Green") 
+                                                   of the Channel1 interface. */
+    unsigned char secondarySubChannel0:4;       /* Supported bit-depth of sub-channel 0 ("Red") 
+                                                   of the Channel1 interface. */
+    unsigned char secondarySubChannel3:4;       /* Supported bit-depth of sub-channel 3 of the 
+                                                   Channel1 interface. */
+    unsigned char secondarySubChannel2:4;       /* Supported bit-depth of sub-channel 2 ("Blue") 
+                                                   of the Channel1 interface. */
+                                                   
+    /* 
+     * Display Device Description (5 bytes) 
+     */
+    unsigned char displayType;                  /* Display technology type/subtype*/
+    unsigned char displayCharacteristic;        /* Major display characteristics. */
+    unsigned char featureSupport[3];            /* Feature Support */
+    
+    /* 
+     * Display Response Time (2 bytes) 
+     */
+    unsigned char riseTimeResponse:4;           /* Rise time response in seconds */
+    unsigned char riseTimeExponent:4;           /* Rise time exponent */
+    unsigned char fallTimeResponse:4;           /* Fall time response in seconds */
+    unsigned char fallTimeExponent:4;           /* Fall time exponent */
+    
+    /* 
+     * Color / Luminance Description (28 bytes) 
+     */
+    unsigned char whiteGamme;                   /* (Gamma x 100) - 100, [range 1.00 --> 3.55] */
+    unsigned char redGamma;                     /* Color 0 ("red") Gamma (optional). Set to ffh if unused. */
+    unsigned char greenGamma;                   /* Color 1 ("green") Gamma (optional). Set to ffh if unused. */
+    unsigned char blueGamma;                    /* Color 2 ("blue") Gamma (optional). Set to ffh if unused. */
+    unsigned short maxLuminance;                /* Maximum LUminance (white) in units of cd/m^2*10 */
+    unsigned char colorConfig;                  /* Standard RGB Model, adjustable Gamma and its offset */
+    unsigned char offsetValue;                  /* Color Offset value */
+    
+    /* Calorimetry and White Point(s) */
+    unsigned char redGreenLowBits;              /* Red / Green Low Bits */
+}
+edid_version_2_t;
+
+#endif
+
+/* Restore alignment */
+#pragma pack()
+
+/**************************************************************
+ *  Function Prototypes
+ **************************************************************/
+
+/*
+ *  ddk768_edidGetVersion
+ *      This function gets the EDID version
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRevision   - Revision of the EDIE (if exist)
+ *
+ *  Output:
+ *      Revision number of the given EDID buffer.
+ */
+unsigned char ddk768_edidGetVersion(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pRevision
+);
+
+/*
+ *  ddk768_edidGetProductInfo
+ *      This function gets the vendor and product information.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor [in]
+ *      pManufacturerName   - Pointer to a 3 byte length variable to store the manufacturer name [out]
+ *      pProductCode        - Pointer to a variable to store the product code [out]
+ *      pSerialNumber       - Pointer to a variable to store the serial number [out]
+ *      pWeekOfManufacture  - Pointer to a variable to store the week of manufacture [out]
+ *      pYearOfManufacture  - Pointer to a variable to store the year of manufacture 
+ *                            or model year (if WeekOfManufacture is 0xff) [out]
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetProductInfo(
+    unsigned char *pEDIDBuffer,
+    char *pManufacturerName,
+    unsigned short *pProductCode,
+    unsigned long *pSerialNumber,
+    unsigned char *pWeekOfManufacture,
+    unsigned short *pYearOfManufacture
+);
+
+/*
+ *  ddk768_edidCheckMonitorInputSignal
+ *      This function checks whether the monitor is expected analog/digital 
+ *      input signal.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Analog
+ *      1   - Digital
+ */
+unsigned char ddk768_edidCheckMonitorInputSignal(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidGetAnalogSignalInfo
+ *      This function gets the analog video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pRefWhiteAboveBlank     - Pointer to a variable to store the reference white above blank
+ *                                value. The value is in milliVolt.
+ *      pSyncLevelBelowBlank    - Pointer to a variable to store the Sync tip level below blank
+ *                                The value is also in milliVolt
+ *      pBlank2BlackSetup       - Pointer to a variable to store the Blank to black setup or
+ *                                pedestal per appropriate Signal Level Standard flag. 
+ *                                1 means that the display expect the setup.
+ *      pSeparateSyncSupport    - Pointer to a variable to store the flag to indicate that the
+ *                                monitor supports separate sync.
+ *      pCompositeSyncSupport   - Pointer to a variable to store a flag to indicate that the
+ *                                monitor supports composite sync.
+ *      pSyncOnGreenSupport     - Pointer to a variable to store a flag to indicate that
+ *                                the monitor supports sync on green video.
+ *      pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration
+ *                                of the VSync pulse is required when composite sync or
+ *                                sync-on-green video is used.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetAnalogSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRefWhiteAboveBlank,
+    unsigned short *pSyncLevelBelowBlank,
+    unsigned char *pBlank2BlackSetup,
+    unsigned char *pSeparateSyncSupport,
+    unsigned char *pCompositeSyncSupport,
+    unsigned char *pSyncOnGreenSupport,
+    unsigned char *pVSyncSerrationRequired
+);
+
+/*
+ *  ddk768_edidGetDigitalSignalInfo
+ *      This function gets the digital video input signal information
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pDFP1xSupport   - Pointer to a variable to store the flag to indicate that
+ *                        the mointor interface is signal compatible with VESA
+ *                        DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color
+ *                        MSB aligned, DE active high
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDigitalSignalInfo(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDFP1xSupport
+);
+
+/*
+ *  ddk768_edidGetDisplaySize
+ *      This function gets the display sizes in cm.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMaxHorzImageSize   - Pointer to a variable to store the maximum horizontal 
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *      pMaxVertImageSize   - Pointer to a variable to store the maximum vertical
+ *                            image size to the nearest centimeter. A value of 0
+ *                            indicates that the size is indeterminate size.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDisplaySize(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMaxHorzImageSize,
+    unsigned char *pMaxVertImageSize
+);
+
+/*
+ *  ddk768_edidGetPowerManagementSupport
+ *      This function gets the monitor's power management support.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStandBy        - Pointer to a variable to store the flag to indicate that
+ *                        standby power mode is supported.
+ *      pSuspend        - Pointer to a variable to store the flag to indicate that
+ *                        suspend power mode is supported.
+ *      pLowPower       - Pointer to a variable to store the flag to indicate that
+ *                        the display consumes low power when it receives a timing
+ *                        signal that is outside its declared active operating range.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetPowerManagementSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStandBy,
+    unsigned char *pSuspend,
+    unsigned char *pLowPower
+);
+
+/*
+ *  ddk768_edidGetDisplayType
+ *      This function gets the display type.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Monochrome / grayscale display
+ *      1   - RGB Color Display
+ *      2   - Non-RGB multicolor display, e.g. R/G/Y
+ *      3   - Undefined
+ */
+unsigned char ddk768_edidGetDisplayType(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidChecksRGBUsage
+ *      This function checks if the display is using the sRGB standard default
+ *      color space as its primary color space. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Does not use sRGB as its primary color space
+ *      1   - Use sRGB as its primary color space
+ */
+unsigned char ddk768_edidChecksRGBUsage(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidIsPreferredTimingAvailable
+ *      This function checks whether the preffered timing mode is available.
+ *      Use of preferred timing mode is required by EDID structure version 1
+ *      Revision 3 and higher. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Preferred Timing is not available
+ *      1   - Preferred Timing is available
+ */
+unsigned char ddk768_edidIsPreferredTimingAvailable(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidIsDefaultGTFSupported
+ *      This function checks whether the display supports timings based on the
+ *      GTF standard using default GTF parameter values. 
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      0   - Default GTF is not supported
+ *      1   - Default GTF is supported
+ */
+unsigned char ddk768_edidIsDefaultGTFSupported(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidGetColorCharacteristic
+ *      This function gets the chromaticity and white point values expressed as
+ *      an integer value which represents the actual value times 1000.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      pRedX   - Pointer to a variable to store the Red X values
+ *      pRedY   - Pointer to a variable to store the Red Y values
+ *      pGreenX - Pointer to a variable to store the Green X values
+ *      pGreenY - Pointer to a variable to store the Green Y values
+ *      pBlueX  - Pointer to a variable to store the Blue X values
+ *      pBlueY  - Pointer to a variable to store the Blue Y values
+ *
+ *  Note:
+ *      To get the White color characteristic, use the ddk768_edidGetWhitePoint
+ */
+void ddk768_edidGetColorCharacteristic(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pRedX,
+    unsigned short *pRedY,
+    unsigned short *pGreenX,
+    unsigned short *pGreenY,
+    unsigned short *pBlueX,
+    unsigned short *pBlueY
+);
+
+/*
+ *  ddk768_edidGetWhitePoint
+ *      This function gets the white point.
+ *      To get the default white point, set the index to 0. For multiple white point,
+ *      call this function multiple times to check if more than 1 white point is supported.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWhitePointIndex    - Pointer to a variable that contains the white point index 
+ *                            to be retrieved.
+ *      pWhiteX             - Pointer to a variable to store the White X value
+ *      pWhiteY             - Pointer to a variable to store the White Y value
+ *      pWhiteGamma         - Pointer to a variable to store the White Gamma value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetWhitePoint(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pWhitePointIndex,
+    unsigned short *pWhiteX,
+    unsigned short *pWhiteY,
+    unsigned short *pWhiteGamma
+);
+
+/*
+ *  ddk768_edidGetExtension
+ *      This function gets the number of (optional) EDID extension blocks to follow
+ *      the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *
+ *  Output:
+ *      Total number of EDID Extension to follow the given EDID buffer.
+ */
+unsigned char ddk768_edidGetExtension(
+    unsigned char *pEDIDBuffer
+);
+
+/*
+ *  ddk768_edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      i2cNumber   - 0 = I2c0 and 1 = 12c1
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidReadMonitor(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+);
+
+/*
+ *  ddk768_edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidReadMonitorEx(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);
+
+/*
+ *  This function is same as editReadMonitorEx(), but using HW I2C.
+ *
+ *  Input:
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      i2cNumber   - 0 = I2C0 and 1 = I2C1
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidReadMonitorExHwI2C(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+);
+
+long ddk750_edidHeaderReadMonitorExHwI2C(void);
+long ddk750_edidHeaderReadMonitorEx(
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);	
+
+
+/*
+ *  ddk768_edidGetEstablishedTiming
+ *      This function gets the established timing list from the given EDID buffer,
+ *      table, and timing index.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor (In)
+ *      pEstTableIndex  - Pointer to the Established Timing Table index  (In/Out)
+ *      pIndex          - Pointer to the Establihsed Timing Index (In/Out)
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *      pSource         - Pointer to a variable to store the standard timing source:
+ *                          0 - VESA
+ *                          1 - IBM
+ *                          2 - Apple
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetEstablishedTiming(
+    unsigned char *pEDIDBuffer,
+    /*unsigned char *pEstTableIndex,*/
+    unsigned char *pIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate,
+    unsigned char *pSource
+);
+
+/*
+ *  ddk768_edidGetStandardTiming
+ *      This function gets the standard timing from the given EDID buffer and
+ *      calculates the width, height, and vertical frequency from that timing.
+ *
+ *  Input:
+ *      pEDIDBuffer     - Buffer that contains the EDID structure of the monitor
+ *      pStdTimingIndex - Pointer to a standard timing index to be retrieved
+ *      pWidth          - Pointer to a variable that to store the horizontal active / width
+ *                        value of the retrieved timing (Out)
+ *      pHeight         - Pointer to a variable to store the vertical active / height
+ *                        value of the retrieved timing (Out)
+ *      pRefreshRate    - Pointer to a variable to store the vertical frequency value
+ *                        of the retrieved timing (out)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetStandardTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pStdTimingIndex,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pRefreshRate
+);
+
+/*
+ *  ddk768_edidGetDetailedTiming
+ *      This function gets the detailed timing from the given EDID buffer.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pDetailedTimingIndex    - Pointer to a detailed timing index to be retrieved
+ *      pModeParameter          - Pointer to a mode_parameter_t structure that will be
+ *                                filled with the detailed timing.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDetailedTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pDetailedTimingIndex,
+    vdif_t *pVDIF
+);
+
+/*
+ *  ddk768_edidGetMonitorSerialNumber
+ *      This function gets the monitor serial number from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the serial number 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the serial number.
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorSerialNumber(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorSerialNumber,
+    unsigned char bufferSize
+);
+
+/*
+ *  ddk768_edidGetDataString
+ *      This function gets the data string from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorSerialNumber    - Pointer to a buffer to store the data string 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the data string
+ *                                The maximum size required is 13 bytes.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetDataString(
+    unsigned char *pEDIDBuffer,
+    char *pDataString,
+    unsigned char bufferSize
+);
+
+/*
+ *  ddk768_edidGetMonitorRangeLimit
+ *      This function gets the monitor range limits from the EDID structure.
+ *      Only EDID version 1 and revision 1 or above supports this feature.
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pMinVerticalRate    - Pointer to a variable to store the Minimum Vertical Rate (Hz)
+ *      pMaxVerticalRate    - Pointer to a variable to store the Maximum Vertical Rate (Hz)
+ *      pMinHorzFreq        - Pointer to a variable to store the Minimum Horz. Freq (kHz)
+ *      pMaxHorzFreq        - Pointer to a variable to store the Maximum Horz. Freq (kHz)
+ *      pMaxPixelClock      - Pointer to a variable to store the Maximum Pixel Clock (Hz)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorRangeLimit(
+    unsigned char *pEDIDBuffer,
+    unsigned char *pMinVerticalRate,
+    unsigned char *pMaxVerticalRate,
+    unsigned char *pMinHorzFreq,
+    unsigned char *pMaxHorzFreq,
+    unsigned long *pMaxPixelClock
+);
+
+/*
+ *  edidGetChannel1TimingSupport
+ *      This function gets the secondary GTF timing support.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pStartFrequency         - Pointer to a variable to store the start frequency of 
+ *                                the secondary GTF
+ *      pOffset                 - Pointer to a variable to store the Offset (C) value of
+ *                                the secondary GTF
+ *      pGradient               - Pointer to a variable to store the Gradient (M) value of
+ *                                the secondary GTF
+ *      pScalingFactor          - Pointer to a variable to store the Scaling Factor (K)
+ *                                value of the secondary GTF
+ *      pScalingFactorWeight    - Pointer to a variable to store the Scaling Factore Weight (J)
+ *                                value of the secondary GTF
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long edidGetChannel1TimingSupport(
+    unsigned char *pEDIDBuffer,
+    unsigned short *pStartFrequency,
+    unsigned char *pOffset,
+    unsigned short *pGradient,
+    unsigned char *pScalingFactor,
+    unsigned char *pScalingFactorWeight
+);
+
+/*
+ *  ddk768_edidGetMonitorName
+ *      This function gets the monitor name from the EDID structure.
+ *
+ *  Input:
+ *      pEDIDBuffer             - Buffer that contains the EDID structure of the monitor
+ *      pMonitorName            - Pointer to a buffer to store the monitor name 
+ *                                retrieved from the EDID
+ *      bufferSize              - The size of the buffer to store the monitor name
+ *                                The maximum size required is 13 bytes. 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetMonitorName(
+    unsigned char *pEDIDBuffer,
+    char *pMonitorName,
+    unsigned char bufferSize
+);
+
+/*
+ *  ddk768_edidGetPreferredTiming
+ *      This function gets the preferred/native timing of the monitor
+ *
+ *  Input:
+ *      pEDIDBuffer         - Buffer that contains the EDID structure of the monitor
+ *      pWidth              - Pointer to an unsigned long buffer to store the width 
+ *                            of the preferred (native) timing.
+ *      pHeight             - Pointer to an unsigned long buffer to store the height
+ *                            of the preferred (native) timing.
+ *      pVerticalFrequency  - Pointer to an unsigned long buffer to store the refresh
+ *                            rate of the preferred (native) timing.
+ * 
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk768_edidGetPreferredTiming(
+    unsigned char *pEDIDBuffer,
+    unsigned long *pWidth,
+    unsigned long *pHeight,
+    unsigned long *pVerticalFrequency
+);
+
+#endif  /* _EDID_H_ */
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.c
new file mode 100644
index 000000000000..43dccec25dcc
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.c
@@ -0,0 +1,911 @@
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+
+
+#include "ddk768_power.h"
+#include "ddk768_intr.h"
+#include "ddkdebug.h"
+#include "ddk768_edid.h"
+#include "ddk768_timer.h"
+
+
+#include "ddk768_ep952.h"
+
+#include "ddk768_swi2c.h"
+#include "../ddk750/ddk750_swi2c.h"
+
+
+#include "ddk768_help.h"
+#include "ddk768_display.h"
+#include "ddk768_reg.h"
+
+#include "ep952api.h"
+#include "ep952controller.h"  // HDMI Transmiter
+#include "ep952settingsdata.h"
+
+
+
+#ifdef HDMI_DEBUG
+#define HDMI_DEBUG_Printf   printk
+#else
+#define HDMI_DEBUG_Printf(fmt,...)
+#endif
+
+int is_SM768 = 0;
+
+void EP952_Register_Message(void);
+
+
+
+EP952C_REGISTER_MAP EP952C_Registers = {0};
+// Private Data
+unsigned char IIC_EP952_Addr, IIC_HDCPKey_Addr;
+unsigned short TempUSHORT;
+//unsigned char Temp_Data[15];
+
+// Global date for HDMI Transmiter
+unsigned char is_RSEN;
+unsigned char Cache_EP952_DE_Control;
+
+// Private Functions
+static unsigned char IIC_Write(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size);
+static unsigned char IIC_Read(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size);
+
+//==================================================================================================
+//
+// Private Functions
+//
+
+static unsigned char IIC_Write(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size)
+{
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // return 0; for success
+    // return 2; for No_ACK
+    // return 4; for Arbitration
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+
+    unsigned char status = 0;
+    unsigned int i;
+	
+	
+    for (i = 0; i < Size; i++)
+    {
+		if(is_SM768)
+        	ddk768_swI2CWriteReg(IICAddr, (ByteAddr + i), *(Data + i));
+		else
+			swI2CWriteReg(IICAddr, (ByteAddr + i), *(Data + i));
+	}
+    return status;
+
+}
+
+static unsigned char IIC_Read(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size)
+{
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+    // return 0; for success
+    // return 2; for No_ACK
+    // return 4; for Arbitration
+    /////////////////////////////////////////////////////////////////////////////////////////////////
+
+    unsigned char status = 0;
+    unsigned int i;
+
+    for (i = 0; i < Size; i++)
+    {
+    	if(is_SM768)
+        	*(Data + i) = ddk768_swI2CReadReg(IICAddr,(ByteAddr + i));
+		else
+			*(Data + i) = swI2CReadReg(IICAddr,(ByteAddr + i));
+	}	
+
+    return status;
+
+}
+//--------------------------------------------------------------------------------------------------
+//
+// Hardware Interface
+//
+
+unsigned char EP952_Reg_Read(unsigned char ByteAddr, unsigned char *Data, unsigned int Size)
+{
+    return IIC_Read(IIC_EP952_Addr, ByteAddr, Data, Size);
+}
+
+unsigned char EP952_Reg_Write(unsigned char ByteAddr, unsigned char *Data, unsigned int Size)
+{
+    return IIC_Write(IIC_EP952_Addr, ByteAddr, Data, Size);
+}
+
+unsigned char EP952_Reg_Set_Bit(unsigned char ByteAddr, unsigned char BitMask)
+{
+    int result = 1;
+	unsigned char Temp_Data[15] = {0};
+    result = IIC_Read(IIC_EP952_Addr, ByteAddr, Temp_Data, 1);
+    if(result == 0)
+    {
+        // Write back to Reg Reg_Addr
+        Temp_Data[0] |= BitMask;
+
+        return IIC_Write(IIC_EP952_Addr, ByteAddr, Temp_Data, 1);
+    }
+    else
+    {
+        return result;
+    }
+}
+
+unsigned char EP952_Reg_Clear_Bit(unsigned char ByteAddr, unsigned char BitMask)
+{
+    int result = 1;
+	unsigned char Temp_Data[15] = {0};
+    result = IIC_Read(IIC_EP952_Addr, ByteAddr, Temp_Data, 1);
+    if(result == 0)
+    {
+        // Write back to Reg Reg_Addr
+        Temp_Data[0] &= ~BitMask;
+
+        return IIC_Write(IIC_EP952_Addr, ByteAddr, Temp_Data, 1);
+    }
+    else
+    {
+        return result;
+    }
+}
+
+//==================================================================================================
+//
+// Public Function Implementation
+//
+
+//--------------------------------------------------------------------------------------------------
+// Hardware Interface
+
+void EP952_IIC_Initial()
+{
+	unsigned char Temp_Data[15] = {0};
+    IIC_EP952_Addr = 0x52;	  // EP952 slave address
+    IIC_HDCPKey_Addr = 0xA8;  // HDCP Key (EEPROM) slave address
+
+
+    // Initial Variables
+    Temp_Data[0] = EP952_TX_PHY_Control_0__TERM_ON;
+    EP952_Reg_Write(EP952_TX_PHY_Control_0, Temp_Data, 1);
+
+    Temp_Data[0] = 0;
+    EP952_Reg_Write(EP952_TX_PHY_Control_1, Temp_Data, 1);
+
+	
+}
+
+void EP952_Info_Reset(void)
+{
+    int i;
+	unsigned char Temp_Data[15] = {0};
+    // Global date for HDMI Transmiter
+    is_RSEN = 0;
+    Cache_EP952_DE_Control = 0x03;
+
+    // Initial Settings
+    EP952_Reg_Set_Bit(EP952_Packet_Control, EP952_Packet_Control__VTX0);
+    EP952_Reg_Set_Bit(EP952_General_Control_1, EP952_General_Control_1__INT_OD);
+
+    //
+    // Set Default AVI Info Frame
+    //
+    memset(Temp_Data, 0x00, 14);
+
+    // Set AVI Info Frame to RGB
+    Temp_Data[1] &= 0x60;
+    Temp_Data[1] |= 0x00; // RGB
+
+    // Set AVI Info Frame to 601
+    Temp_Data[2] &= 0xC0;
+    Temp_Data[2] |= 0x40;
+
+    // Write AVI Info Frame
+    Temp_Data[0] = 0;
+    for(i=1; i<14; ++i) {
+    	Temp_Data[0] += Temp_Data[i];
+    }
+    Temp_Data[0] = ~(Temp_Data[0] - 1);
+    EP952_Reg_Write(EP952_AVI_Packet, Temp_Data, 14);
+
+    //
+    // Set Default ADO Info Frame
+    //
+    memset(Temp_Data, 0x00, 6);
+
+    // Write ADO Info Frame
+    Temp_Data[0] = 0;
+    for(i=1; i<6; ++i) {
+    	Temp_Data[0] += Temp_Data[i];
+    }
+    Temp_Data[0] = ~(Temp_Data[0] - 1);
+    EP952_Reg_Write(EP952_ADO_Packet, Temp_Data, 6);
+
+    //
+    // Set Default CS Info Frame
+    //
+    memset(Temp_Data, 0x00, 5);
+    	
+    EP952_Reg_Write(EP952_Channel_Status, Temp_Data, 5);
+/*
+    //
+    // clear Packet_1 Info Frame
+    //
+    Temp_Data[0] = 0;
+    for(i=EP952_Data_Packet_Header; i<= 0x5F; i++) {	
+    	EP952_Reg_Write(i, Temp_Data, 1);
+    }
+*/
+}
+
+
+// System flags
+unsigned char is_Cap_dsel;
+unsigned char is_Cap_HDMI;
+unsigned char is_Cap_YCC444;
+unsigned char is_Cap_YCC422;
+unsigned char is_Forced_Output_RGB;
+
+unsigned char is_Hot_Plug;
+unsigned char is_Connected;
+unsigned char is_ReceiverSense;
+unsigned char ChkSum, ConnectionState;
+unsigned char EP952_Debug = 0;
+
+// System Data
+unsigned char HP_ChangeCount;
+unsigned char PowerUpCount;
+TX_STATE TX_State;
+VDO_PARAMS Video_Params;
+ADO_PARAMS Audio_Params;
+PEP952C_REGISTER_MAP pEP952C_Registers;
+
+//------------------------------------
+// Special for config
+
+void HDMI_Tx_AMute_Enable(void)
+{
+	EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AMUTE);
+	EP952_Reg_Set_Bit(EP952_Pixel_Repetition_Control, EP952_Pixel_Repetition_Control__CTS_M);
+
+	EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__ADO_EN);		
+	EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__AUDIO_EN);	
+}
+
+void HDMI_Tx_AMute_Disable(void)
+{
+	EP952_Reg_Clear_Bit(EP952_Pixel_Repetition_Control, EP952_Pixel_Repetition_Control__CTS_M);
+	EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AVMUTE);
+	EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AMUTE);
+
+	EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__ADO_EN);	
+	EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__AUDIO_EN);
+}
+
+void HDMI_Tx_VMute_Enable(void)
+{		
+	EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__VMUTE);
+}
+
+void HDMI_Tx_VMute_Disable(void)
+{
+	EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AVMUTE);
+	EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__VMUTE);
+}
+
+//--------------------------------------------------------------------------------------------------
+//
+// HDMI Transmiter (EP952-Tx Implementation)
+//
+
+void HDMI_Tx_HDMI(void)
+{
+	EP952_Reg_Set_Bit(EP952_General_Control_4, EP952_General_Control_4__HDMI);
+}
+
+void HDMI_Tx_DVI(void)
+{
+	EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__HDMI);
+}
+
+void HDMI_Tx_Power_Down(void)
+{
+	// Software power down
+	EP952_Reg_Clear_Bit(EP952_General_Control_1, EP952_General_Control_1__PU);
+}
+
+void HDMI_Tx_Power_Up(void)
+{
+	// Software power up
+	EP952_Reg_Set_Bit(EP952_General_Control_1, EP952_General_Control_1__PU);	
+}
+
+void HDMI_Tx_Mute_Enable(void)
+{
+	HDMI_Tx_AMute_Enable();
+	HDMI_Tx_VMute_Enable();	
+}
+
+void HDMI_Tx_Mute_Disable(void)
+{
+	HDMI_Tx_VMute_Disable();	
+	HDMI_Tx_AMute_Disable();
+}
+
+void HDMI_Tx_HDCP_Disable(void)
+{
+	EP952_Reg_Clear_Bit(EP952_General_Control_5, EP952_General_Control_5__ENC_EN);
+}
+
+void EP952_HDCP_Reset(void)
+{
+	pEP952C_Registers->System_Status |= EP_TX_System_Status__KEY_FAIL;
+	pEP952C_Registers->System_Configuration |= EP_TX_System_Configuration__HDCP_DIS;
+}
+
+VDO_SETTINGS EP952_VDO_Settings[] = {
+	//                   HVRes_Type,             		DE_Gen(DLY,CNT,TOP,LIN),                E_Sync, 				AR_PR,       Pix_Freq_Type,
+	{  0,{       0,   0,   0,    0},{  0,   0,  0,   0},{0x00,  0,  0,  0,  0,   0},  0x00,                  PIX_FREQ_25175KHz}, // 0:
+	// HDMI Mode
+	{  1,{VNegHNeg, 800, 525,16666},{ 48, 640, 34, 480},{0x00, 12, 96, 10,  2,   0},  0x10,  PIX_FREQ_25175KHz}, // 1:    640 x  480p
+	{  2,{VNegHNeg, 858, 525,16666},{ 60, 720, 31, 480},{0x00, 12, 62,  9,  6,   0},  0x10,  PIX_FREQ_27000KHz}, // 2:    720 x  480p  4:3
+	{  3,{VNegHNeg, 858, 525,16666},{ 60, 720, 31, 480},{0x00, 12, 62,  9,  6,   0},  0x20,  PIX_FREQ_27000KHz}, // 3:    720 x  480p 16:9
+	{  4,{VPosHPos,1650, 750,16666},{220,1280, 21, 720},{0x00,106, 40,  5,  5,   0},  0x20,  PIX_FREQ_74176KHz}, // 4:   1280 x  720p
+	{  5,{VPosHPos,2200, 563,16666},{148,1920, 16, 540},{0x09, 84, 44,  2,  5,1100},  0x20,  PIX_FREQ_74176KHz}, // 5:   1920 x 1080i
+	{  6,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x09, 15, 62,  4,  3, 429},  0x15,  PIX_FREQ_27000KHz}, // 6:    720 x  480i, pix repl
+	{  7,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x09, 15, 62,  4,  3, 429},  0x25,  PIX_FREQ_27000KHz}, // 7:    720 x  480i, pix repl
+	{  8,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x00, 15, 62,  4,  3,   0},  0x15,  PIX_FREQ_27000KHz}, // 8:    720 x  240p, pix repl
+	{  9,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x00, 15, 62,  4,  3,   0},  0x25,  PIX_FREQ_27000KHz}, // 9:    720 x  240p, pix repl
+	{ 10,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x09, 72,248,  4,  3,1716},  0x10,  PIX_FREQ_54000KHz}, // 10:  2880 x  480i 4:3
+	{ 11,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x09, 72,248,  4,  3,1716},  0x20,  PIX_FREQ_54000KHz}, // 11:  2880 x  480i 16:9
+	{ 12,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x00, 72,248,  4,  3,   0},  0x10,  PIX_FREQ_54000KHz}, // 12:  2880 x  240p 4:3
+	{ 13,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x00, 72,248,  4,  3,   0},  0x20,  PIX_FREQ_54000KHz}, // 13:  2880 x  240p 16:9
+	{ 14,{VNegHNeg,1716, 525,16666},{120,1440, 31, 480},{0x00, 28,124,  9,  6,   0},  0x10,  PIX_FREQ_54000KHz}, // 14:  1440 x  480p 4:3
+	{ 15,{VNegHNeg,1716, 525,16666},{120,1440, 31, 480},{0x00, 28,124,  9,  6,   0},  0x20,  PIX_FREQ_54000KHz}, // 15:  1440 x  480p 16:9
+	{ 16,{VPosHPos,2200,1125,16666},{148,1920, 37,1080},{0x00, 84, 44,  4,  5,   0},  0x20, PIX_FREQ_148500KHz}, // 16:  1920 x 1080p
+	{ 17,{VNegHNeg, 864, 625,20000},{ 68, 720, 40, 576},{0x00,  8, 64,  5,  5,   0},  0x10,  PIX_FREQ_27000KHz}, // 17:   720 x  576p 4:3
+	{ 18,{VNegHNeg, 864, 625,20000},{ 68, 720, 40, 576},{0x00,  8, 64,  5,  5,   0},  0x20,  PIX_FREQ_27000KHz}, // 18:   720 x  576p 16:9
+	{ 19,{VPosHPos,1980, 750,20000},{220,1280, 21, 720},{0x00,436, 40,  5,  5,   0},  0x20,  PIX_FREQ_74250KHz}, // 19:  1280 x  720p, 50 Hz
+	{ 20,{VPosHPos,2640, 563,20000},{148,1920, 16, 540},{0x09,524, 44,  2,  5,1320},  0x20,  PIX_FREQ_74250KHz}, // 20:  1920 x 1080i, 50 Hz
+	{ 21,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x09,  8, 63,  2,  3, 432},  0x15,  PIX_FREQ_27000KHz}, // 21:   720 x  576i, pix repl
+	{ 22,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x09,  8, 63,  2,  3, 432},  0x25,  PIX_FREQ_27000KHz}, // 22:   720 x  576i, pix repl
+	{ 23,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x00,  8, 63,  3,  3,   0},  0x15,  PIX_FREQ_27000KHz}, // 23:   720 x  288p, pix repl
+	{ 24,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x00,  8, 63,  3,  3,   0},  0x25,  PIX_FREQ_27000KHz}, // 24:   720 x  288p, pix repl
+	{ 25,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x09, 44,252,  2,  3,1728},  0x10,  PIX_FREQ_54000KHz}, // 25:  2880 x  576i
+	{ 26,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x09, 44,252,  2,  3,1728},  0x20,  PIX_FREQ_54000KHz}, // 26:  2880 x  576i
+	{ 27,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x00, 44,252,  3,  3,   0},  0x10,  PIX_FREQ_54000KHz}, // 27:  2880 x  288p
+	{ 28,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x00, 44,252,  3,  3,   0},  0x20,  PIX_FREQ_54000KHz}, // 28:  2880 x  288p
+	{ 29,{VPosHNeg,1728, 625,20000},{136,1440, 40, 576},{0x00, 20,128,  5,  5,   0},  0x10,  PIX_FREQ_54000KHz}, // 29:  1440 x  576p
+	{ 30,{VPosHNeg,1728, 625,20000},{136,1440, 40, 576},{0x00, 20,128,  5,  5,   0},  0x20,  PIX_FREQ_54000KHz}, // 30:  1440 x  576p
+	{ 31,{VPosHPos,2640,1125,20000},{148,1920, 37,1080},{0x00,524, 44,  4,  5,   0},  0x20, PIX_FREQ_148500KHz}, // 31:  1920 x 1080p, 50 Hz
+	{ 32,{VPosHPos,2750,1125,41666},{148,1920, 37,1080},{0x00,634, 44,  4,  5,   0},  0x20,  PIX_FREQ_74176KHz}, // 32:  1920 x 1080p
+	{ 33,{VPosHPos,2640,1125,40000},{148,1920, 37,1080},{0x00,524, 44,  4,  5,   0},  0x20,  PIX_FREQ_74250KHz}, // 33:  1920 x 1080p, 25 Hz
+	{ 34,{VPosHPos,2200,1125,33333},{148,1920, 37,1080},{0x00, 84, 44,  4,  5,   0},  0x20,  PIX_FREQ_74176KHz}, // 34:  1920 x 1080p
+
+};
+
+unsigned char EP952_VDO_Settings_Max = (sizeof(EP952_VDO_Settings)/sizeof(EP952_VDO_Settings[0]));
+
+void HDMI_Tx_Video_Config(PVDO_PARAMS Params)
+{
+    int i;
+	unsigned char Temp_Data[15] = {0};
+
+    // Disable auto transmission AVI packet 
+    EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__AVI_EN);
+
+    ////////////////////////////////////////////////////////
+    // Video Interface
+
+    // De_Skew
+    EP952_Reg_Read(EP952_General_Control_3, Temp_Data, 1);
+    Temp_Data[0] &= ~0xF0;
+    Temp_Data[0] |= Params->Interface & 0xF0;
+    EP952_Reg_Write(EP952_General_Control_3, Temp_Data, 1);	
+
+    // input DSEL BSEL EDGE
+    EP952_Reg_Read(EP952_General_Control_1, Temp_Data, 1);
+    Temp_Data[0] &= ~0x0E;
+    Temp_Data[0] |= Params->Interface & 0x0E;
+	if(is_Cap_dsel)
+    	Temp_Data[0] |= 0x08;   // DSEL = 1
+    else
+		Temp_Data[0] &= 0xf7;   // DSEL = 0
+    EP952_Reg_Write(EP952_General_Control_1, Temp_Data, 1);	
+
+    if(Params->Interface & 0x01) {
+        EP952_Reg_Set_Bit(EP952_General_Control_4, EP952_General_Control_4__FMT12);
+    }
+    else {
+        EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__FMT12);
+    }
+
+    // update HVPol
+    EP952_Reg_Read(EP952_General_Control_4, Temp_Data, 1);
+    Params->HVPol = Temp_Data[0] & (EP952_DE_Control__VSO_POL | EP952_DE_Control__HSO_POL);	
+
+    ////////////////////////////////////////////////////////
+    // Sync Mode
+    switch(Params->SyncMode) {
+        default:
+        case SYNCMODE_HVDE:
+            // Disable E_SYNC
+            EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__E_SYNC);
+            // Disable DE_GEN
+            Cache_EP952_DE_Control &= ~EP952_DE_Control__DE_GEN;
+
+            // Regular VSO_POL, HSO_POL
+            if((Params->HVPol & VNegHPos) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VNegHPos)) { // V
+                Cache_EP952_DE_Control |= EP952_DE_Control__VSO_POL; // Invert
+            }
+            else {
+                Cache_EP952_DE_Control &= ~EP952_DE_Control__VSO_POL;
+            }
+            if((Params->HVPol & VPosHNeg) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VPosHNeg)) { // H
+                Cache_EP952_DE_Control |= EP952_DE_Control__HSO_POL; // Invert
+            }
+            else {
+                Cache_EP952_DE_Control &= ~EP952_DE_Control__HSO_POL;
+            }
+            break;
+
+        case SYNCMODE_HV:
+            // Disable E_SYNC
+            EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__E_SYNC);
+            // Enable DE_GEN
+            Cache_EP952_DE_Control |= EP952_DE_Control__DE_GEN;
+
+            // Regular VSO_POL, HSO_POL
+            if((Params->HVPol & VNegHPos) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VNegHPos)) { // V
+                Cache_EP952_DE_Control |= EP952_DE_Control__VSO_POL; // Invert
+            }
+            else {
+                Cache_EP952_DE_Control &= ~EP952_DE_Control__VSO_POL;
+            }
+            if((Params->HVPol & VPosHNeg) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VPosHNeg)) { // H
+                Cache_EP952_DE_Control |= EP952_DE_Control__HSO_POL; // Invert
+            }
+            else {
+                Cache_EP952_DE_Control &= ~EP952_DE_Control__HSO_POL;
+            }
+
+            // Set DE generation params
+            if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) {
+                Cache_EP952_DE_Control &= ~0x03;
+
+#ifdef Little_Endian
+                Cache_EP952_DE_Control |= ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[1];
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[0];
+                EP952_Reg_Write(EP952_DE_DLY, Temp_Data, 1);
+#else	// Big Endian
+                Cache_EP952_DE_Control |= ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[0];
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[1];
+                EP952_Reg_Write(EP952_DE_DLY, Temp_Data, 1);
+#endif
+
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_TOP)[0];
+                EP952_Reg_Write(EP952_DE_TOP, Temp_Data, 1);
+
+#ifdef Little_Endian
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[0];
+                Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[1];
+                EP952_Reg_Write(EP952_DE_CNT, Temp_Data, 2);
+#else	// Big Endian
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[1];
+                Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[0];
+                EP952_Reg_Write(EP952_DE_CNT, Temp_Data, 2);
+#endif
+
+
+#ifdef Little_Endian
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[1];
+                Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[0];
+                EP952_Reg_Write(EP952_DE_LIN, Temp_Data, 2);
+#else	// Big Endian
+                Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[1];
+                Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[0];
+                EP952_Reg_Write(EP952_DE_LIN, Temp_Data, 2);
+#endif
+
+            }
+            else {
+                //DBG_printf(("ERROR: VideoCode overflow DE_GEN table\r\n"));
+            }
+            break;
+    }
+    EP952_Reg_Write(EP952_DE_Control, &Cache_EP952_DE_Control, 1);
+	
+    ////////////////////////////////////////////////////////
+    // Pixel Repetition
+    EP952_Reg_Read(EP952_Pixel_Repetition_Control, Temp_Data, 1);
+    Temp_Data[0] &= ~EP952_Pixel_Repetition_Control__PR;
+    if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) {
+        Temp_Data[0] |= EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x03;
+    }
+    EP952_Reg_Write(EP952_Pixel_Repetition_Control, Temp_Data, 1);
+
+    ////////////////////////////////////////////////////////
+    // Color Space
+    // Set to RGB
+    EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__YCC_IN | EP952_General_Control_4__422_IN);
+    if(Params->VideoSettingIndex < EP952_VDO_Settings_IT_Start) { // CE Timing
+        EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_OUT | EP952_Color_Space_Control__422_OUT);
+        EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_Range); // Output limit range RGB
+    }
+    else { // IT Timing
+        EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_OUT | EP952_Color_Space_Control__422_OUT | EP952_Color_Space_Control__YCC_Range);
+    }
+
+    // Color Space
+    switch(Params->ColorSpace) {
+        default:
+        case COLORSPACE_601:
+            // Set to 601
+            EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__COLOR);
+            break;
+
+        case COLORSPACE_709:
+            // Set to 709
+            EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__COLOR);
+            break;
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    // AVI Info Frame
+    //
+
+    // clear AVI Info Frame
+    memset(Temp_Data, 0x00, 14);
+
+    // AVI InfoFrame Data Byte 1
+    //switch(Params->FormatOut) {
+    Temp_Data[1] |= 0x00; // AVI_Y1,Y0 = RGB
+    Temp_Data[1] |= 0x10; // AVI_A0 = Active Format Information valid
+	
+    //SCAN
+    switch(Params->SCAN) {
+        default:
+        case 0: 					
+            Temp_Data[1] &= ~0x03;	// AVI_S1,S0 = No Data
+            break;
+        case 1: 					// AVI_S1,S0 = overscan
+            Temp_Data[1] |= 0x01;	
+            break;
+        case 2: 					// AVI_S1,S0 = underscan
+            Temp_Data[1] |= 0x02;	
+            break;
+    }
+
+    // AVI InfoFrame Data Byte 2
+    switch(Params->ColorSpace) {
+        default:
+        case COLORSPACE_601:
+            Temp_Data[2] |= 0x40;	// AVI_C1,C0 = 601
+            break;
+
+        case COLORSPACE_709:
+            Temp_Data[2] |= 0x80;	// AVI_C1,C0 = 709
+            break;
+    }
+
+    if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) {
+        Temp_Data[2] |= EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x30; // AVI_M1,M0 : Picture Aspect Ratio
+    }
+    Temp_Data[2] |= Params->AFARate & 0x0F;// AVI_R3~0: Active format Aspect Ratio
+
+    // AVI InfoFrame Data Byte 3 is 0
+
+    // AVI InfoFrame Data Byte 4 is VIC
+    if(Params->VideoSettingIndex < EP952_VDO_Settings_IT_Start) {
+        Temp_Data[4] |= EP952_VDO_Settings[Params->VideoSettingIndex].VideoCode;// AVI_VIC6~0 : Vedio Identification code
+    }
+
+    // AVI InfoFrame Data Byte 5
+    if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) {
+        Temp_Data[5] |= (EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x0C) >> 2;// AVI_PR3~0 : Pixel Repetition
+    }
+
+    // AVI InfoFrame Data Byte 0 is checksum
+    Temp_Data[0] = 0x91;
+        for(i=1; i<6; ++i) {
+        Temp_Data[0] += Temp_Data[i];
+    }
+    Temp_Data[0] = ~(Temp_Data[0] - 1);	// checksum
+	
+    // Write AVI InfoFrame Data Byte
+    EP952_Reg_Write(EP952_AVI_Packet, Temp_Data, 14);
+
+    // Enable auto transmission AVI packet 
+    EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__AVI_EN | EP952_IIS_Control__GC_EN);
+
+
+}
+
+//--------------------------------------------------------------------------------------------------------------------
+
+void EP952Controller_Initial(PEP952C_REGISTER_MAP pEP952C_RegMap)
+{		
+    // Save the Logical Hardware Assignment
+    pEP952C_Registers = pEP952C_RegMap;
+
+    // Initial IIC address
+    if(is_SM768)
+    	ddk768_swI2CInit(30, 31);
+	else
+		swI2CInit(30, 31);
+	
+    EP952_IIC_Initial();
+
+    // Software power down
+    HDMI_Tx_Power_Down();
+
+    // Enable Audio Mute and Video Mute
+    HDMI_Tx_Mute_Enable();	
+
+    // Reset Variables
+    is_Cap_HDMI = 0;
+    is_Cap_YCC444 = is_Cap_YCC422 = 0;
+    is_Forced_Output_RGB = 0;
+    is_Connected = 1;
+    TX_State = TXS_Search_EDID;
+    HP_ChangeCount = 0;
+    PowerUpCount = 0;
+    is_ReceiverSense = 0;
+
+    // Reset all EP952 parameters
+    pEP952C_Registers->System_Status = 0;
+    pEP952C_Registers->EDID_ASFreq = 0;
+    pEP952C_Registers->EDID_AChannel = 0;
+    pEP952C_Registers->Video_change = 0;
+    pEP952C_Registers->Audio_change = 0; 
+    pEP952C_Registers->System_Configuration = 0;
+    pEP952C_Registers->Video_Input_Format[1]= 0;
+    //pEP952C_Registers->Video_Output_Format = 0;		// Auto select output 
+    pEP952C_Registers->Video_Output_Format = 0x03;	    // Forced set RGB out
+
+    // Disable HDCP
+    HDMI_Tx_HDCP_Disable();
+
+    // HDCP KEY reset
+    EP952_HDCP_Reset();
+
+    // Info Frame Reset
+    EP952_Info_Reset();
+}
+
+
+
+#if 0
+void EP_HDMI_DumpMessage(void)
+{
+    unsigned char temp_R = 0xFF, reg_addr = 0;
+
+    ddk768_swI2CInit(30, 31);
+    IIC_EP952_Addr = 0x52;	  // EP952 slave address
+    IIC_HDCPKey_Addr = 0xA8;  // HDCP Key (EEPROM) slave address
+
+    printk("[Samtest EP952 Register value]\r\n");
+    printk("    -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F\r\n");
+    printk("    -----------------------------------------------");
+    for(reg_addr=0; reg_addr<=0x88; reg_addr++)
+    {
+        EP952_Reg_Read(reg_addr, &temp_R, 1);
+
+        if(reg_addr%16 == 0)
+        {
+            printk("\r\n%02x| ",((reg_addr/16)<<4));
+        }
+        printk("%02x ",temp_R);
+
+    }
+    printk("\r\n");
+    printk("    -----------------------------------------------\r\n");
+}
+
+void EP_HDMI_DumpRegister(void)
+{
+    unsigned char temp_R = 0xFF, reg_addr = 0;
+
+    ddk768_swI2CInit(30, 31);
+    IIC_EP952_Addr = 0x52;	  // EP952 slave address
+    IIC_HDCPKey_Addr = 0xA8;  // HDCP Key (EEPROM) slave address
+
+    printk("    +++++");
+    for(reg_addr=0x3A; reg_addr<=0x3D; reg_addr++)
+    {
+        EP952_Reg_Read(reg_addr, &temp_R, 1);
+
+        printk("$%02X=%02X ", reg_addr, temp_R);
+
+    }
+    printk("    -----\r\n");
+}
+#endif
+void EP_HDMI_Init(int chipID)
+{
+	if(chipID)
+		is_SM768 = 1;
+	else
+		is_SM768 = 0;
+	
+    EP952Controller_Initial(&EP952C_Registers);
+}
+
+void EP952_Video_reg_set(void)
+{
+    // Mute Control
+    HDMI_Tx_Mute_Enable();
+
+    //if(pEP952C_Registers->Video_Input_Format[0] != 0)
+    {
+        // HDMI Mode
+        if(!is_Cap_HDMI ) {
+            HDMI_Tx_DVI();	// Set to DVI output mode (The Info Frame and Audio Packets would not be send)
+            is_Forced_Output_RGB = 1;
+        }
+        else {
+            HDMI_Tx_HDMI();	// Set to HDMI output mode
+        }
+
+    	///////////////////////////////////////////////////////////////////////
+    	// Update Video Params
+    	//
+    	
+    	// Video Interface
+    	Video_Params.Interface = pEP952C_Registers->Video_Interface[0];
+    	//Video_Params.Interface = 0x87
+    		
+    	// Video Timing
+    	if(pEP952C_Registers->Video_Input_Format[0] < 35) {
+    		Video_Params.VideoSettingIndex = pEP952C_Registers->Video_Input_Format[0];
+    		//Video_Params.VideoSettingIndex = 0x16;
+    	}
+    	else{
+    		Video_Params.VideoSettingIndex = 0;
+    	}
+    		
+    	// Select Sync Mode
+    	Video_Params.SyncMode = (SYNCMODE)((pEP952C_Registers->Video_Interface[1] & EP_TX_Video_Interface_Setting_1__SYNC) >> 2);
+		//Video_Params.SyncMode = 0;
+    		
+    	// Select Color Space
+    	switch(Video_Params.VideoSettingIndex) {
+    		case  4: case  5: case 16: case 19: case 20: case 31: case 32: 
+    		case 33: case 34: 													// HD Timing
+    			Video_Params.ColorSpace = COLORSPACE_709;
+    			break;
+    		
+    		default:
+    			if(Video_Params.VideoSettingIndex) { 							// SD Timing
+    				Video_Params.ColorSpace = COLORSPACE_601;
+    			}
+    			else {															// IT Timing
+    				Video_Params.ColorSpace = COLORSPACE_709;
+    			}
+    			break;
+    	}
+
+    	// Forced Output RGB Format
+    	if(pEP952C_Registers->Video_Output_Format == 0x03) {
+    		is_Forced_Output_RGB = 1;
+    	}
+    		
+    	// Set In and Output Color Format	
+    	switch(pEP952C_Registers->Video_Interface[1] & EP_TX_Video_Interface_Setting_1__VIN_FMT) {
+    		
+    		default:
+    		case EP_TX_Video_Interface_Setting_1__VIN_FMT__RGB:	 	// input is RGB
+    			Video_Params.FormatIn = COLORFORMAT_RGB;
+    			Video_Params.FormatOut = COLORFORMAT_RGB;
+    			break;
+    		
+    		case EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC444: 	// input is YCC444
+    			Video_Params.FormatIn = COLORFORMAT_YCC444;
+    			if(!is_Forced_Output_RGB && is_Cap_YCC444) {
+    				Video_Params.FormatOut = COLORFORMAT_YCC444;
+    			}
+    			else {
+    				Video_Params.FormatOut = COLORFORMAT_RGB;
+    			}
+    			break;
+    	
+    		case EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC422: 	// inut is YCC422
+    			Video_Params.FormatIn = COLORFORMAT_YCC422;
+    			if(!is_Forced_Output_RGB && is_Cap_YCC422) {
+    				Video_Params.FormatOut = COLORFORMAT_YCC422;
+    			}
+    			else {
+    				Video_Params.FormatOut = COLORFORMAT_RGB;
+    			}
+    			break;
+    	}
+    	// AFAR
+    	Video_Params.AFARate = AFAR_VideoCode;
+
+    	// SCAN 		
+    	Video_Params.SCAN = SCAN_NoData;
+
+    	// Update EP952 Video Registers 
+    	HDMI_Tx_Video_Config(&Video_Params);
+
+    	// mute control
+    	HDMI_Tx_Mute_Disable();
+    }
+
+    // clear flag
+    pEP952C_Registers->Video_change = 0;
+
+}
+
+void EP_HDMI_Set_Video_Timing(unsigned int isHDMI, unsigned int dsel) //(logicalMode_t *pLogicalMode, unsigned int isHDMI)
+{
+    /////////////////////////////////////////////////////////////////////////
+    //
+    // need to select EP952 video input interface
+    // detail description need reference to file " Video_Interface[0].jpg " and " Video_Interface[1].jpg "
+    //
+    /////////////////////////////////////////////////////////////////////////
+    EP952C_Registers.Video_Interface[0] = 0x87;	// reference to Video_Interface[0].jpg;
+    		
+    EP952C_Registers.Video_Interface[1] = 0x00;	// reference to Video_Interface[1].jpg;
+
+
+    /////////////////////////////////////////////////////////////////////////
+    // need to select video timing, timing detail description as below
+    //
+    //  [Example]:
+    // 		EP_HDMI_Set_Video_Timing(16); 	// 1080P 60Hz
+    //
+    // 		EP_HDMI_Set_Video_Timing(4); 	// 720P 60Hz
+    //
+    /////////////////////////////////////////////////////////////////////////
+    EP952C_Registers.Video_Input_Format[0] = 16;		
+    EP952C_Registers.Video_change = 1;					// Vedio setting change flag
+
+    if (isHDMI)
+        is_Cap_HDMI = 1;
+    else
+        is_Cap_HDMI = 0;
+
+    if (dsel)
+        is_Cap_dsel = 1;
+    else
+        is_Cap_dsel = 0;
+
+    // power down Tx
+    HDMI_Tx_Power_Down();
+
+    // update EP952 register setting
+    //EP952_Audio_reg_set();
+    EP952_Video_reg_set();
+
+    EP952_Debug = 1;
+    	
+    // Power Up Tx
+    HDMI_Tx_Power_Up();
+
+    TX_State = TXS_Stream;
+}
+
+void EP952_Register_Message(void)
+{
+	unsigned char temp[0x90] = {0};
+    unsigned char reg_addr = 0;
+
+    //ddk768_swI2CInit(30, 31);
+    IIC_EP952_Addr = 0x52;	  // EP952 slave address
+    IIC_HDCPKey_Addr = 0xA8;  // HDCP Key (EEPROM) slave address
+
+    printk(KERN_INFO "[Samtest EP952 Register value]");
+    printk(KERN_INFO " \t-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F");
+    printk(KERN_INFO " \t-----------------------------------------------");
+    for(reg_addr=0; reg_addr<=0x88; reg_addr++)
+    {
+        EP952_Reg_Read(reg_addr, &temp[reg_addr], 1);
+    }
+	print_hex_dump(KERN_INFO, " \t", DUMP_PREFIX_NONE, 16, 1, temp, 0x90, false);
+    printk(KERN_INFO " \t-----------------------------------------------");
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.h
new file mode 100644
index 000000000000..c183d2082d42
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_ep952.h
@@ -0,0 +1,62 @@
+#ifndef  _HDMI_H_
+#define  _HDMI_H_
+
+
+//-----------------------------------------------------------------------------
+// Type Definition
+//-----------------------------------------------------------------------------
+
+typedef enum _HDMI_PNP_STATUS_
+{
+    HDMI_INTR_HOT_PLUG, 
+    HDMI_INTR_OTHERS = 0xFF, 
+}HDMI_PNP_STATUS;
+
+
+/*
+ *  Function:
+ *      HDMI_Set_Mode
+ *
+ *  Input:
+ *      pLogicalMode
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      0 - Success
+ *      -1 - Error 
+ *
+ */
+int EP952_HDMI_Set_Mode (logicalMode_t *pLogicalMode);
+
+/*
+ *  Function:
+ *      HDMI_Read_Edid.
+ *		 
+ *  Input:
+ *      pEDIDBuffer - EDID buffer
+ *      bufferSize - EDID buffer size (usually 128-bytes or 256 bytes)
+ *  Output:
+ *      -1 - Error
+ *      0 - exist block0 EDID (128 Bytes)
+ *      1 - exist block0 & block1 EDID (256 Bytes)
+ */
+int EP952_HDMI_Read_Edid(char *pEDIDBuffer, unsigned long bufferSize);
+
+/*
+ *  Function:
+ *      HDMI_hotplug_check
+ *		 
+ *  Input:
+ *      None
+ * 
+ *  Output:
+ *      0 - unplugged
+ *      1 - plugged
+ * 
+ */
+
+void hdmiHandler(void);
+
+#endif  /* _HDMI_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.c
new file mode 100644
index 000000000000..580ef6a941c3
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.c
@@ -0,0 +1,1559 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  Hdmi.c ---  
+*  This file contains the source code for HDMI functions.
+* 
+*******************************************************************/
+
+
+
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include "ddk768_help.h"
+#include "ddk768_hdmi.h"
+#include "ddk768_reg.h"
+#include "ddk768_power.h"
+#include "hdmiregs.h"
+
+
+//-----------------------------------------------------------------------------
+// Parameter Table
+//-----------------------------------------------------------------------------
+
+/*
+ *  Hdmi parameter for some popular modes.
+ *  Note that the most timings in this table is made according to CEA standard
+ *  parameters for the popular modes.
+ */
+static hdmi_PHY_param_t gHdmiPHYParamTable[] =
+{
+/* TMDS clock range 0-50 MHz [8bpc] */
+ { 0x22, 0x06, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x10, 0x00}, //640x480 5D: 0x70->0x10
+
+/* TMDS clock range 50-100 MHz [8bpc] */
+ { 0x22, 0x0A, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x70, 0x00},
+
+/* TMDS clock range 100-150 MHz [8bpc] */  
+//{ 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x91, 0x2E, 0x70, 0x00}, //1080P  5B:0x92->0x91
+ { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x95, 0x2E, 0x72, 0x00}, //1080P  5B:0x92->0x91
+
+/* TMDS clock range 150-200 MHz [8bpc] */
+ { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x71, 0x00},
+
+/* TMDS clock range 200-250 MHz [8bpc] */
+ { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x71, 0x00},
+
+/* TMDS clock range 250-297 MHz  [8bpc] */
+ //{ 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x95, 0x2E, 0x71, 0x00},
+ { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x5E, 0x95, 0x7E, 0x64, 0x00},     // SLI uses it to run 4K compliance test
+
+/* End of table. */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+/* HDMI mode VIC value table.*/
+static hdmi_vic_param_t gHdmiVICParamTable[] = 
+{
+    {640,  480,  1},
+    {720,  480,  2},   
+    {1280, 720,  4}, 
+    {1440, 480,  14}, 
+    {1920, 1080, 16}, 
+    {2880, 480,  35}, 
+    {1680, 720,  83}, 
+    {2560, 1080, 90}, 
+    {3840, 2160, 95},
+    
+    /* End of table. */
+    {0, 0, 0},
+};
+
+//-----------------------------------------------------------------------------
+// Global Variable
+//-----------------------------------------------------------------------------
+
+BYTE g_INT_94h = 0;
+BYTE g_INT_95h = 0;
+BYTE PowerMode = PowerMode_A;
+BYTE g_ucHDMIedidRead=0;
+BYTE AudioMode = 0;
+BYTE gEdidBuffer[256] = {0};
+
+/* Find mode VIC parameer from the table according to Width & Height*/
+unsigned char FindVicParam(unsigned long Width, unsigned long Height)
+{
+    unsigned char index = 0;
+    hdmi_vic_param_t * pVicTable = gHdmiVICParamTable;
+
+    while (pVicTable[index].Width != 0)
+    {
+        if ((pVicTable[index].Width == Width) && (pVicTable[index].Height == Height)) 
+            return pVicTable[index].Vic;
+       
+        /* Next entry */
+        index++;
+    }
+
+    /* If no such a mode, set vic to 0. */
+    return 0;
+}
+void Delay (void)
+{
+    unsigned long d;
+    for (d = 0; d < 0x13FF; d++)
+        ;
+}
+
+void DelayMs (BYTE millisecond)
+{
+	mdelay(millisecond);
+}
+
+//-----------------------------------------------------------------------------
+// HDMI Interrupt functions
+//-----------------------------------------------------------------------------
+typedef struct _hdmi_interrupt_t
+{
+    struct _hdmi_interrupt_t *next;
+    void (*handler)(void);
+}
+hdmi_interrupt_t;
+
+static hdmi_interrupt_t *g_pHdmiIntHandlers = ((hdmi_interrupt_t *)0);
+
+/* HDMI Interrupt Service Routine */
+void hdmiISR(
+    unsigned long status
+)
+{
+    hdmi_interrupt_t *pfnHandler;
+
+    if (FIELD_GET(status, INT_STATUS, HDMI) == INT_STATUS_HDMI_ACTIVE)
+    {
+        /* Walk all registered handlers for handlers that support this interrupt status */
+        for (pfnHandler = g_pHdmiIntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next)
+            pfnHandler->handler();
+        
+        // Save interrupt status value for further usage. 
+        if (PowerMode == PowerMode_A)
+        {
+            // PS mode a->b
+            HDMI_System_PD(PowerMode_B);
+            DelayMs(1);
+        }
+        g_INT_94h = readHDMIRegister (X94_INT1_ST);
+        g_INT_95h = readHDMIRegister (X95_INT2_ST);
+
+        // clear all interrupt status
+        writeHDMIRegister (X94_INT1_ST, 0xFF);
+        writeHDMIRegister (X95_INT2_ST, 0xFF);
+    }            
+}
+
+/*
+ * This is the main interrupt hook for HDMI engine.
+ */
+long hookHDMIInterrupt(
+    void (*handler)(void)
+)
+{
+
+#if 0
+	hdmi_interrupt_t *pfnNewHandler, *pfnHandler;
+    unsigned short returnValue = 0;
+
+    /* Allocate a new interrupt structure */
+    pfnNewHandler = (hdmi_interrupt_t *)malloc(sizeof(hdmi_interrupt_t));
+    if (pfnNewHandler == ((hdmi_interrupt_t *)0))
+    {
+        /* No more memory */
+        return (-1);
+    }
+
+    /* Make sure that it has not been register more than once */
+    for (pfnHandler = g_pHdmiIntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next)
+    {
+        if (pfnHandler->handler == handler)
+            return (-1);                   /* Duplicate entry */
+    }
+        
+    /* If this is the first interrupt handler, register this panel VSync ISR */
+    if (g_pHdmiIntHandlers == ((hdmi_interrupt_t *)0))
+        returnValue = registerHandler(hdmiISR, FIELD_SET(0, INT_MASK, HDMI, ENABLE));
+
+    if (returnValue == 0)
+    {
+        /* Fill interrupt structure. */
+        pfnNewHandler->next = g_pHdmiIntHandlers;
+        pfnNewHandler->handler = handler;
+        g_pHdmiIntHandlers = pfnNewHandler;
+    }
+#endif   
+    return 0;//returnValue;
+}
+
+/*
+ * This function un-register HDMI Interrupt handler.
+ */
+long unhookHDMIInterrupt(
+    void (*handler)(void)
+)
+{
+#if 0
+    hdmi_interrupt_t *pfnHandler, *prev;
+
+    /* Find the requested handle to unregister */
+    for (pfnHandler = g_pHdmiIntHandlers, prev = ((hdmi_interrupt_t *)0); 
+         pfnHandler != ((hdmi_interrupt_t *)0); 
+         prev = pfnHandler, pfnHandler = pfnHandler->next)
+    {
+        if (pfnHandler->handler == handler)
+        {
+            /* Remove the interrupt handler */
+            if (prev == ((hdmi_interrupt_t *)0))
+                g_pHdmiIntHandlers = pfnHandler->next;
+            else
+                prev->next = pfnHandler->next;
+
+            free(pfnHandler);
+            
+            /* If this was the last interrupt handler, remove the IRQ handler */
+            if (g_pHdmiIntHandlers == ((hdmi_interrupt_t *)0))
+                unregisterHandler(hdmiISR);
+            
+            /* Success */
+            return (0);
+        }
+    }
+#endif
+    /* Oops, handler is not registered */
+    return (-1);
+}
+
+//-----------------------------------------------------------------------------
+// HDMI Misc. functions
+//-----------------------------------------------------------------------------
+
+/*
+ *  Function: 
+ *      writeHDMIRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (could be from 0x01 to 0xFF)
+ *      value   - HDMI register value
+ *
+ *  Output:
+ *      None
+ *
+ *  
+ *  WRITE is a 2 step process. For example, write a value of 0x82 to register with index 0x45, the steps are:
+ *  (MMIO base + 0x800C0) = 0x00018245
+ *  (MMIO base + 0x800C0) = 0x00008245
+ *
+ */
+void writeHDMIRegister(unsigned char addr, unsigned char value)
+{
+
+    pokeRegisterDWord(HDMI_CONFIG, 
+        FIELD_SET(0, HDMI_CONFIG, WRITE, ENABLE) | 
+        FIELD_VALUE(0, HDMI_CONFIG, DATA, value) | 
+        FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr));
+
+    DelayMs(1);
+    
+    pokeRegisterDWord(HDMI_CONFIG, 
+        FIELD_VALUE(0, HDMI_CONFIG, DATA, value) | 
+        FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr));
+
+    DelayMs(1);
+}
+
+/*
+ *  Function: 
+ *      readHDMIRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (could be from 0x01 to 0xFF)
+ *
+ *  Output:
+ *      register value
+ *
+ *  
+ *  READ is a 3 step process, For example, read a value from register with index 0x45.
+ *  (MMIO base + 0x800C0) = 0x20045
+ *  (MMIO base + 0x800C0) = 0x00045
+ *  Value = (MMIO base + 0x800C0) =0x1845
+ *
+ */
+unsigned char readHDMIRegister(unsigned char addr)
+{
+    unsigned long value;
+
+    pokeRegisterDWord(HDMI_CONFIG, 
+        FIELD_SET(0, HDMI_CONFIG, READ, ENABLE) | 
+        FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr));
+    
+    DelayMs(1);
+    
+    pokeRegisterDWord(HDMI_CONFIG, FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr));
+    
+    DelayMs(1);
+
+    value = peekRegisterDWord(HDMI_CONFIG);
+    
+    return (unsigned char)((value >> 8) & 0xFF);
+}
+
+/*
+ *  Function: 
+ *      writeHDMIControlRegister
+ *      This functions writes HDMI System Control register (index 0x00). 
+ *
+ *  Input:
+ *      value   - HDMI register 0x00 value
+ *
+ *  Output:
+ *      None
+ *  
+ */
+void writeHDMIControlRegister(unsigned char value)
+{
+
+    pokeRegisterDWord(HDMI_CONTROL, value); 
+    
+}
+
+/*
+ *  Function: 
+ *      readHDMIRegister
+ *      This functions reads HDMI System Control register (index 0x00). 
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      register value
+ *
+ */
+unsigned char readHDMIControlRegister(void)
+{
+    unsigned long value;
+
+    // Need to write 0x800c0[7:0] (config address) to 00 first, otherwise could not read back
+    // real value of HDMI control register. 
+    pokeRegisterDWord(HDMI_CONFIG, 
+        FIELD_SET(0, HDMI_CONFIG, READ, ENABLE) | 
+        FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, 0));
+    
+    DelayMs(1);
+    
+    value = peekRegisterDWord(HDMI_CONTROL);
+    
+    return (unsigned char)(value & 0xFF);
+}
+
+/*
+ *  Function: 
+ *      writeHdmiPHYRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (for PHY registers only, could be from 0x57 to 0x5E)
+ *      value   - HDMI register value
+ *
+ *  Output:
+ *      None
+ *
+ */
+void writeHdmiPHYRegister(unsigned char addr, unsigned char value)
+{
+    writeHDMIRegister(addr, value);
+    
+    writeHDMIControlRegister(0x2D);     // PLLA/B reset
+    DelayMs(1);     // wait 100us
+
+    writeHDMIControlRegister(0x21);     // PLLA/B release
+    DelayMs(1);     // wait 1ms for PLL lock
+}
+
+/*
+ *  Function:
+ *      setHDMIChannel
+ *
+ *  Input:
+ *      channel number      -   0 = Select Channel 0 to HDMI
+ *                                  -   1 = Select Channel 1 to HDMI
+ *
+ *  Output:
+ *      None
+ *
+ */
+void setHDMIChannel(unsigned char Channel)
+{
+    unsigned long value;
+
+    value = peekRegisterDWord(DISPLAY_CTRL);
+    if (Channel == 0)
+    {
+        pokeRegisterDWord(DISPLAY_CTRL, 
+            FIELD_SET(value, DISPLAY_CTRL, HDMI_SELECT, CHANNEL0));
+    }
+    else
+    {
+        pokeRegisterDWord(DISPLAY_CTRL, 
+            FIELD_SET(value, DISPLAY_CTRL, HDMI_SELECT, CHANNEL1));
+    }
+
+}
+
+/*
+ *  Function:
+ *      enableHdmiI2C
+ *
+ *  Input:
+ *      enable/disable      -   0 = HDMI I2C to GPIO[7:6]
+ *                                  -   1 = HW I2C to GPIO[7:6]
+ *
+ *  Output:
+ *      None
+ *
+ */
+void enableHdmI2C(unsigned long enable)
+{
+    unsigned long value;
+
+    value = peekRegisterDWord(TEST_CONTROL);
+
+    if (enable)
+        value = FIELD_SET(value, TEST_CONTROL, I2C, HDMI);
+    else
+        value = FIELD_SET(value, TEST_CONTROL, I2C, I2C1);
+
+    pokeRegisterDWord(TEST_CONTROL, value);
+}
+
+/*
+ *  Function:
+ *      HDMI_Dump_Registers (Used for debug)
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Linda: for debug purpose only
+ */
+void HDMI_Dump_Registers (void)
+{
+    unsigned char i = 0, j = 0;
+
+    printk("++++++++++ HDMI Regsiters 0x00 - 0x7F ++++++++++\n");
+
+    for (i = 0; i < 16; i++)
+    {
+        printk("Offset 0x%02x:  ", (i * 8));
+        for (j = 0; j < 8; j++)
+            printk("%02x  ", readHDMIRegister((j + i * 8)));
+        printk("\n");
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// HDMI Functions
+//-----------------------------------------------------------------------------
+
+//
+// Parameters   : unsigned char mode. 4 modes available.
+//                  MODE_A (sleep), MODE_B (register access), MODE_D (clock), MODE_E (active).
+//
+void HDMI_System_PD (unsigned char mode) 
+{
+    PowerMode = mode;
+
+    // PLL A/B Reset
+    if (PowerMode != PowerMode_A)
+    {
+        writeHDMIControlRegister (mode | 0x0C);
+       	DelayMs(8);    // wait 8ms
+    }
+    // PLL A/B Release
+    writeHDMIControlRegister (mode);
+    DelayMs(10);    // wait 10ms
+
+
+}
+
+/*
+ *  Function:
+ *      HDMI_Set_Control_Packet
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ */
+void HDMI_Init(void)
+{
+    unsigned char temp;
+    
+    // Enable HDMI clock
+     ddk768_enableHDMI(1);
+    
+    // select channel 0 to HDMI by default
+    setHDMIChannel(0);
+    
+    // set INT polarity to Active High
+    temp = readHDMIControlRegister();
+    writeHDMIControlRegister (temp | 0x01);
+    
+    // Set to power mode B, in order to read/write to registers
+    HDMI_System_PD (PowerMode_B);
+    DelayMs(1);
+
+    // Setting AVI InfoFrame
+    writeHDMIRegister (X5F_PACKET_INDEX, AVI_INFO_PACKET); // Index.6 AVI InfoFrame
+    // HB0 for generic control packet
+    writeHDMIRegister (X41_SEND_CPKT_AUTO, 0x10);
+    writeHDMIRegister (X60_PACKET_HB0, 0x82); // HB0
+    writeHDMIRegister (X61_PACKET_HB1, 0x02); // HB1
+    writeHDMIRegister (X62_PACKET_HB2, 0x0D); // HB2
+    writeHDMIRegister (X63_PACKET_PB0, 0x16); // PB0
+    writeHDMIRegister (X64_PACKET_PB1, 0x00); // PB1
+    writeHDMIRegister (X65_PACKET_PB2, 0x00); // PB2
+    writeHDMIRegister (X66_PACKET_PB3, 0x12); // PB3
+    writeHDMIRegister (X67_PACKET_PB4, 0x00); // PB4
+    writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5
+    writeHDMIRegister (X69_PACKET_PB6, 0xe4); // PB6
+    writeHDMIRegister (X6A_PACKET_PB7, 0xb5); // PB7
+    writeHDMIRegister (X6B_PACKET_PB8, 0x4e); // PB8
+    writeHDMIRegister (X6C_PACKET_PB9, 0x59); // PB9
+    writeHDMIRegister (X6D_PACKET_PB10, 0xd2); // PB10
+    writeHDMIRegister (X6E_PACKET_PB11, 0xeb); // PB11
+    writeHDMIRegister (X6F_PACKET_PB12, 0x18); // PB12
+    writeHDMIRegister (X70_PACKET_PB13, 0x1d); // PB13
+
+    // Setting Audio InfoFrame
+    writeHDMIRegister (X5F_PACKET_INDEX, AUDIO_INFO_PACKET); // Index.8 Audio
+    writeHDMIRegister (X60_PACKET_HB0, 0x84); // HB0
+    writeHDMIRegister (X61_PACKET_HB1, 0x01); // HB1
+    writeHDMIRegister (X62_PACKET_HB2, 0x0A); // HB2
+    writeHDMIRegister (X63_PACKET_PB0, 0x70); // PB0
+    writeHDMIRegister (X64_PACKET_PB1, 0x01); // PB1
+    writeHDMIRegister (X65_PACKET_PB2, 0x00); // PB2
+    writeHDMIRegister (X66_PACKET_PB3, 0x00); // PB3
+    writeHDMIRegister (X67_PACKET_PB4, 0x00); // PB4
+    writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5
+
+    // init DDC bus frequency
+    writeHDMIRegister (X81_ISRC2_PB0, 0x20);
+    writeHDMIRegister (X82_ISRC2_PB1, 0x00);
+
+    // Unmask MSENS detect interrupt. Hot plug interrupt is enough for hot-plug
+    // detection, we don't need to detect both at the same time.
+    // writeHDMIRegister (X92_INT_MASK1, 0x80);
+}
+
+/*
+ *  Function:
+ *      HDMI_Control_Packet_Auto_Send
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ */
+void HDMI_Control_Packet_Auto_Send (void)
+{
+    writeHDMIRegister (X42_AUTO_CHECKSUM, 0x01);    // enable auto checksum
+    writeHDMIRegister (X40_CTRL_PKT_EN, 0x00);
+}
+
+void HDMI_Audio_Setting_48000Hz (mode_parameter_t *pModeParam)
+{
+    unsigned long N = 6144, CTS = 0;    // default N value is 6144
+    unsigned char regValue = 0;
+
+    // calculate CTS with recommended N
+    // recommended N value is 5120 for 4K mode
+    if ((pModeParam->horizontal_display_end >= 3840 && pModeParam->horizontal_display_end < 5120) && 
+        (pModeParam->vertical_display_end >= 2160 && pModeParam->vertical_display_end < 2880))
+    {
+        N = 5120;
+    }
+    
+    // CTS = (fTMDS_clock x N) / (128 x fS)
+    CTS = ((pModeParam->pixel_clock / 1000) * N / 128) * 10 / 480;
+
+    // set N and CTS into registers
+    regValue = (unsigned char)((N >> 16) & 0x0F);
+    writeHDMIRegister(X01_N19_16, regValue);
+    regValue = (unsigned char)(N >> 8);
+    writeHDMIRegister(X02_N15_8, regValue);
+    regValue = (unsigned char)N;
+    writeHDMIRegister(X03_N7_0, regValue);
+
+    regValue = (unsigned char)((CTS >> 16) & 0x0F);
+    writeHDMIRegister(X07_CTS_EXT, regValue);
+    regValue = (unsigned char)(CTS >> 8);
+    writeHDMIRegister(X08_CTS_EXT, regValue);
+    regValue = (unsigned char)CTS;
+    writeHDMIRegister(X09_CTS_EXT, regValue);
+
+    // set audio setting registers
+    writeHDMIRegister(X0A_AUDIO_SOURCE, 0x00);      // internal CTS
+    writeHDMIRegister(X0B_AUDIO_SET2, 0x40);
+    writeHDMIRegister(X0C_I2S_MODE, 0x04);      // I2S 2ch (0x3C for 8ch) + I2S
+    //writeHDMIRegister(X0D_DSD_MODE, 0x00);      // DSD audio disabled
+    writeHDMIRegister(X10_I2S_PINMODE, 0x00);      // I2S input pin swap
+    writeHDMIRegister(X11_ASTATUS1, 0x0D);      // Original Fs = 48kHz
+    writeHDMIRegister(X12_ASTATUS2, 0x22);
+    writeHDMIRegister(X13_CAT_CODE, 0x00);
+    writeHDMIRegister(X14_A_SOURCE, 0x02);      // 16 bits word length 
+    
+    regValue = ((readHDMIRegister(X15_AVSET1) & 0x0F) | 0x20);       // set freq 48kHz
+    writeHDMIRegister(X15_AVSET1, regValue);
+
+    regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0x9F;
+    writeHDMIRegister(X0A_AUDIO_SOURCE, regValue);      // dounsampling none (bit 6:5 = 00)
+    
+    regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0xF7;
+    writeHDMIRegister(X0A_AUDIO_SOURCE, regValue);      // disable SPDIF
+    
+}
+
+
+/*
+ *  Function:
+ *      HDMI_Audio_Setting_44100Hz
+ *
+ *  Input:
+ *      pLogicalMode
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Setting_44100Hz (mode_parameter_t *pModeParam)
+{
+    unsigned long N = 6272, CTS = 0;    // default N value is 6272
+    unsigned char regValue = 0;
+
+    // calculate CTS with recommended N
+    // recommended N value is 4704 for 4K mode
+    if ((pModeParam->horizontal_display_end >= 3840 && pModeParam->horizontal_display_end < 5120) && 
+        (pModeParam->vertical_display_end >= 2160 && pModeParam->vertical_display_end < 2880))
+    {
+        N = 4704;
+    }
+    
+    // CTS = (fTMDS_clock x N) / (128 x fS)
+    CTS = ((pModeParam->pixel_clock / 1000) * N / 128) * 10 / 441;
+    //printf("44100Hz: N = %d, CTS = %d\n", N, CTS);
+
+    // set N and CTS into registers
+    regValue = (unsigned char)((N >> 16) & 0x0F);
+    writeHDMIRegister(X01_N19_16, regValue);
+    regValue = (unsigned char)(N >> 8);
+    writeHDMIRegister(X02_N15_8, regValue);
+    regValue = (unsigned char)N;
+    writeHDMIRegister(X03_N7_0, regValue);
+
+    regValue = (unsigned char)((CTS >> 16) & 0x0F);
+    writeHDMIRegister(X07_CTS_EXT, regValue);
+    regValue = (unsigned char)(CTS >> 8);
+    writeHDMIRegister(X08_CTS_EXT, regValue);
+    regValue = (unsigned char)CTS;
+    writeHDMIRegister(X09_CTS_EXT, regValue);
+
+    // set audio setting registers
+    writeHDMIRegister(X0A_AUDIO_SOURCE, 0x00);      // internal CTS
+    writeHDMIRegister(X0B_AUDIO_SET2, 0x40);
+    writeHDMIRegister(X0C_I2S_MODE, 0x04);      // I2S 2ch (0x3C for 8ch) + I2S
+    //writeHDMIRegister(X0D_DSD_MODE, 0x00);      // DSD audio disabled
+    writeHDMIRegister(X10_I2S_PINMODE, 0x00);      // I2S input pin swap
+    writeHDMIRegister(X11_ASTATUS1, 0x0F);      // Original Fs = 44.1kHz
+    writeHDMIRegister(X12_ASTATUS2, 0x22);
+    writeHDMIRegister(X13_CAT_CODE, 0x00);
+    writeHDMIRegister(X14_A_SOURCE, 0x02);      // 16 bits word length 
+    
+    regValue = (readHDMIRegister(X15_AVSET1) & 0x0F);       // set freq 44.1kHz
+    writeHDMIRegister(X15_AVSET1, regValue);
+
+    regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0x9F;
+    writeHDMIRegister(X0A_AUDIO_SOURCE, regValue);      // dounsampling none (bit 6:5 = 00)
+    
+    regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0xF7;
+    writeHDMIRegister(X0A_AUDIO_SOURCE, regValue);      // disable SPDIF
+    
+}
+
+/*
+ *  Function:
+ *      HDMI_Video_Setting
+ *      isHDMI      - 1: HDMI monitor; 0: DVI monitor
+ *
+ *  Input:
+ *      pModeParam
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Video_Setting (mode_parameter_t *pModeParam, bool isHDMI)
+{
+    unsigned long temp = 0;
+    unsigned char regValue = 0;
+
+    // video set timing
+    regValue = readHDMIRegister(X30_EXT_VPARAMS);
+    regValue &= 0xF2;
+    regValue = 
+        (pModeParam->vertical_sync_polarity == POS
+        ? FIELD_SET(regValue, X30_EXT_VPARAMS, VSYNC_PHASE, POS)
+        : FIELD_SET(regValue, X30_EXT_VPARAMS, VSYNC_PHASE, NEG))
+        | (pModeParam->horizontal_sync_polarity == POS
+        ? FIELD_SET(regValue, X30_EXT_VPARAMS, HSYNC_PHASE, POS)
+        : FIELD_SET(regValue, X30_EXT_VPARAMS, HSYNC_PHASE, NEG))
+        | FIELD_SET(regValue, X30_EXT_VPARAMS, USE, EXTERNAL);
+    writeHDMIRegister(X30_EXT_VPARAMS, regValue);
+
+    writeHDMIRegister(X31_EXT_HTOTAL, (pModeParam->horizontal_total & 0xFF));   // horizontal total
+    writeHDMIRegister(X32_EXT_HTOTAL, (pModeParam->horizontal_total & 0xFF00)>>8);
+
+    temp = pModeParam->horizontal_total - pModeParam->horizontal_display_end;   // horizontal blanking
+    writeHDMIRegister(X33_EXT_HBLANK, (temp & 0xFF));
+    writeHDMIRegister(X34_EXT_HBLANK, (temp & 0xFF00)>>8);
+
+    temp = pModeParam->horizontal_total - pModeParam->horizontal_sync_start;    // horizontal delay
+    writeHDMIRegister(X35_EXT_HDLY, (temp & 0xFF));
+    writeHDMIRegister(X36_EXT_HDLY, (temp & 0xFF00)>>8);
+
+    writeHDMIRegister(X37_EXT_HS_DUR, (pModeParam->horizontal_sync_width & 0xFF));  // horizontal duration
+    writeHDMIRegister(X38_EXT_HS_DUR, (pModeParam->horizontal_sync_width & 0xFF00)>>8);
+
+    writeHDMIRegister(X39_EXT_VTOTAL, (pModeParam->vertical_total & 0xFF)); // vertical total
+    writeHDMIRegister(X3A_EXT_VTOTAL, (pModeParam->vertical_total & 0xFF00)>>8);
+
+    temp = pModeParam->vertical_total - pModeParam->vertical_display_end;   // vertical blanking
+    writeHDMIRegister(X3D_EXT_VBLANK, temp);
+
+    temp = pModeParam->vertical_total - pModeParam->vertical_sync_start;   // vertical delay
+    writeHDMIRegister(X3E_EXT_VDLY, temp);
+
+    writeHDMIRegister(X3F_EXT_VS_DUR, pModeParam->vertical_sync_height);    // vertical duration
+
+    // video set color - deep_color_8bit
+    regValue = readHDMIRegister(X17_DC_REG);
+    regValue = (regValue & 0x3F) | 0x00;
+    writeHDMIRegister(X17_DC_REG, regValue);
+    
+    writeHDMIRegister(X16_VIDEO1, 0x30);
+
+    // video set format
+    regValue = (readHDMIRegister(X15_AVSET1) & 0xF0);
+    regValue |= 0x01;       // set RGB & external DE
+    writeHDMIRegister(X15_AVSET1, regValue);
+    writeHDMIRegister(X3B_AVSET2, 0x40);
+    //writeHDMIRegister(X40_CTRL_PKT_EN, 0x00);
+    //writeHDMIRegister(X45_VIDEO2, 0x83);
+    writeHDMIRegister(X46_OUTPUT_OPTION, 0x04);
+    writeHDMIRegister(XD3_CSC_CONFIG1, 0x01);
+
+    // video set output - setting to HDMI/DVI mode
+    regValue = readHDMIRegister(XAF_HDCP_CTRL);
+    if (isHDMI)
+        writeHDMIRegister(XAF_HDCP_CTRL, (regValue | 0x02));
+    else
+        writeHDMIRegister(XAF_HDCP_CTRL, (regValue & 0xFD));
+
+    // set DDC bus access frequency control register based on pixel clock value (400kHz is preferred)
+    // At mode_d/mode_e: 
+    // DDC Bus access frequency = TDMS_CK input clock frequency / (register value) / 4
+    temp = pModeParam ->pixel_clock / 4 / 400000;
+    writeHDMIRegister(X81_ISRC2_PB0, (temp & 0xFF));    // LSB
+    writeHDMIRegister(X82_ISRC2_PB1, (temp & 0xFF00)>>8);   // MSB
+    
+}
+
+/*
+ *  Function:
+ *      HDMI_PHY_Setting
+ *
+ *  Input:
+ *      pLogicalMode
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      0 - Success
+ *      -1 - Error 
+ *
+ */
+long HDMI_PHY_Setting (mode_parameter_t *pModeParam)
+{
+    unsigned long clkIndex;
+    hdmi_PHY_param_t *pPHYParamTable;
+
+    // Decide which PHY params to use depend on TMDS clock range. 
+    if (pModeParam->pixel_clock > 0 && pModeParam->pixel_clock < 50000000)
+    {
+        clkIndex = CLK_0_to_50;
+    }
+    else if (pModeParam->pixel_clock >= 50000000 && pModeParam->pixel_clock < 100000000)
+    {
+        clkIndex = CLK_50_to_100;
+    }
+    else if (pModeParam->pixel_clock >= 100000000 && pModeParam->pixel_clock < 150000000)
+    {
+        clkIndex = CLK_100_to_150;
+    }
+    else if (pModeParam->pixel_clock >= 150000000 && pModeParam->pixel_clock < 200000000)
+    {
+        clkIndex = CLK_150_to_200;
+    }
+    else if (pModeParam->pixel_clock >= 200000000 && pModeParam->pixel_clock < 250000000)
+    {
+        clkIndex = CLK_200_to_250;
+    }
+    else if (pModeParam->pixel_clock >= 250000000 && pModeParam->pixel_clock <= 297000000)
+    {
+        clkIndex = CLK_4Kmode;
+    }
+    else
+    {
+        // Does not support TMDS clock higher than 297MHz.
+        return (-1);
+    }
+
+    pPHYParamTable = (hdmi_PHY_param_t *)gHdmiPHYParamTable;
+    
+    // load PHY parameters into registers
+    writeHdmiPHYRegister(X57_PHY_CTRL, pPHYParamTable[clkIndex].X57_PHY_value);
+    writeHdmiPHYRegister(X58_PHY_CTRL, pPHYParamTable[clkIndex].X58_PHY_value);
+    writeHdmiPHYRegister(X59_PHY_CTRL, pPHYParamTable[clkIndex].X59_PHY_value);
+    writeHdmiPHYRegister(X5A_PHY_CTRL, pPHYParamTable[clkIndex].X5A_PHY_value);
+    writeHdmiPHYRegister(X5B_PHY_CTRL, pPHYParamTable[clkIndex].X5B_PHY_value);
+    writeHdmiPHYRegister(X5C_PHY_CTRL, pPHYParamTable[clkIndex].X5C_PHY_value);
+    writeHdmiPHYRegister(X5D_PHY_CTRL, pPHYParamTable[clkIndex].X5D_PHY_value);
+    writeHdmiPHYRegister(X5E_PHY_CTRL, pPHYParamTable[clkIndex].X5E_PHY_value);
+    writeHdmiPHYRegister(X56_PHY_CTRL, pPHYParamTable[clkIndex].X56_PHY_value);
+    writeHdmiPHYRegister(X17_DC_REG, pPHYParamTable[clkIndex].X17_PHY_value);
+    
+    return 0;
+}
+
+/*
+ *  Function:
+ *      HDMI_Set_Mode
+ *
+ *  Input:
+ *      pLogicalMode
+ *      isHDMI      - 1: HDMI monitor; 0: DVI monitor
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      0 - Success
+ *      -1 - Error 
+ *
+ */
+long HDMI_Set_Mode (logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI)
+{
+    
+    unsigned char temp = 0;
+    unsigned long ret = 0;
+    
+    // set mode b
+    if (PowerMode != PowerMode_B)
+    {
+        HDMI_System_PD (PowerMode_B);
+    }
+
+	if (!pLogicalMode->valid_edid)
+    {
+    	 // find mode parameters for input mode
+        pModeParam = ddk768_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, 0);
+        if (pModeParam == (mode_parameter_t *)0)
+            return -1;
+    }
+
+    /* Set VIC */
+    if((pLogicalMode->x == 3840) && (pLogicalMode->y == 2160))
+    {        
+        /* Write 4K specail vic parameters.*/
+        writeHDMIRegister (X5F_PACKET_INDEX, VENDOR_INFO_PACKET); 
+        writeHDMIRegister (X60_PACKET_HB0, 0x81); // HB0 0x82
+        writeHDMIRegister (X61_PACKET_HB1, 0x01); // HB1 0x02
+        writeHDMIRegister (X62_PACKET_HB2, 0x07); // HB2 0x0D
+        writeHDMIRegister (X64_PACKET_PB1, 0x03); // PB1 0x00
+        writeHDMIRegister (X65_PACKET_PB2, 0x0C); // PB2 0x00
+        writeHDMIRegister (X66_PACKET_PB3, 0x00); // PB3 0x12
+        writeHDMIRegister (X67_PACKET_PB4, 0x20); // PB4
+        writeHDMIRegister (X68_PACKET_PB5, 0x01); // PB5 0x00
+        writeHDMIRegister (X69_PACKET_PB6, 0x00); // PB6 0xe4
+        writeHDMIRegister (X6A_PACKET_PB7, 0x00); // PB7 0xb5
+    }
+    else
+    {
+        writeHDMIRegister (X5F_PACKET_INDEX, AVI_INFO_PACKET); 
+        writeHDMIRegister (X67_PACKET_PB4, FindVicParam(pLogicalMode->x, pLogicalMode->y));
+
+	    /* For un-4k mode, the following registers should be re-write.*/
+	    writeHDMIRegister (X60_PACKET_HB0, 0x82); // HB0
+	    writeHDMIRegister (X61_PACKET_HB1, 0x02); // HB1
+	    writeHDMIRegister (X62_PACKET_HB2, 0x0D); // HB2 
+	    writeHDMIRegister (X64_PACKET_PB1, 0x00); //0x18); // PB1
+	    writeHDMIRegister (X65_PACKET_PB2, 0x00); //0xc8); // PB2
+	    writeHDMIRegister (X66_PACKET_PB3, 0x12); // PB3
+	    writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5
+	    writeHDMIRegister (X69_PACKET_PB6, 0xe4); // PB6
+	    writeHDMIRegister (X6A_PACKET_PB7, 0xb5); // PB7
+        
+    }
+    // Index.8 Audio
+    writeHDMIRegister(X5F_PACKET_INDEX, AUDIO_INFO_PACKET); 
+    
+    // set video param
+    HDMI_Video_Setting(pModeParam, isHDMI);
+
+    // set audio param
+    HDMI_Audio_Setting_48000Hz(pModeParam);
+    
+    // control packet auto send
+    HDMI_Control_Packet_Auto_Send();
+
+    // set PHY param
+    ret = HDMI_PHY_Setting(pModeParam);
+    if (ret != 0)
+    {
+        return ret;
+    }
+
+    // disable video & audio output: write 11b to #45h[1:0]
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, (temp | 0x03));
+
+    // set Channel # to HDMI
+    setHDMIChannel((unsigned char)pLogicalMode->dispCtrl);
+    
+    // mode b->d: (0x4d, 100us) -> (0x49, 100us) -> 0x41
+    PowerMode = PowerMode_D;
+    writeHDMIControlRegister (PowerMode | 0x0C);
+    DelayMs (1);
+    writeHDMIControlRegister (PowerMode | 0x08);
+    DelayMs (1);
+    writeHDMIControlRegister (PowerMode);
+    DelayMs (1);
+
+    // mode d->e: 0x81
+    //HDMI_System_PD (PowerMode_E);
+    writeHDMIControlRegister (PowerMode_E);
+    DelayMs(10);    // wait 10ms
+
+    if (AudioMode)
+    {
+        // enable video & audio output: write 00b to #45h[1:0]
+        temp = readHDMIRegister(X45_VIDEO2);
+        temp &= 0xFB;
+        writeHDMIRegister(X45_VIDEO2, (temp & 0xFC));
+        
+        // Audio reset/release
+        // Audio is mute after reset of audio is set.
+        // Therefore, set it in the following procedures.
+        //   Audio:  Save value of now => Audio Reset => Audio Active => Set value again
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, temp | 0x06 );   // Reset
+        DelayMs(1);                                    // Followed by 1ms wait time
+        writeHDMIRegister(X45_VIDEO2, temp & 0xFB );   // Reset Release and Audio Mute)
+        DelayMs(1);                                    // Followed by 1ms wait time
+        writeHDMIRegister(X45_VIDEO2, temp );
+        
+    }
+    else
+    {
+        // enable video output: write 0b to #45h[0]
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, (temp & (~0x01)));
+    }
+
+
+#if 0   // for debug only
+    HDMI_Dump_Registers();
+#endif
+    
+    return 0;
+}
+void HDMI_Enable_Output(void)
+{
+    unsigned char temp = 0;
+
+	if (PowerMode == PowerMode_E)
+		return;
+
+	if (PowerMode == PowerMode_B){
+	    // mode b->d: (0x4d, 100us) -> (0x49, 100us) -> 0x41
+	    PowerMode = PowerMode_D;
+	    writeHDMIControlRegister (PowerMode | 0x0C);
+	    DelayMs (1);
+	    writeHDMIControlRegister (PowerMode | 0x08);
+	    DelayMs (1);
+	    writeHDMIControlRegister (PowerMode);
+	    DelayMs (1);
+
+	    // mode d->e: 0x81
+	    HDMI_System_PD (PowerMode_E);
+	}
+
+    // enable video & audio output: write 00b to #45h[1:0]
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, (temp & (~0x03)));
+    
+    // Audio reset/release
+    // Audio is mute after reset of audio is set.
+    // Therefore, set it in the following procedures.
+    //   Audio:  Save value of now => Audio Reset => Audio Active => Set value again
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, temp | 0x04 );   // Reset
+    DelayMs(1);                                    // Followed by 1ms wait time
+    writeHDMIRegister(X45_VIDEO2, temp & 0xFB );   // Reset Release and Audio Mute)
+
+#if 0   // for debug only
+    HDMI_Dump_Registers();
+#endif
+    
+    return ;
+
+}
+
+/*
+ *  Function:
+ *      HDMI_Disable_Output
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Disable_Output (void)
+{
+    unsigned char temp = 0;
+    
+    // disable video & audio output: write 11b to #45h[1:0]
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, (temp | 0x03));
+
+    // audio reset: write 1b to #45h[2], followed by 500us wait time
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, (temp | 0x04));
+    DelayMs(1);
+
+    // PS mode e->d->b
+    HDMI_System_PD (PowerMode_D);
+    HDMI_System_PD (PowerMode_B);
+}
+
+/*
+ *  Function:
+ *      HDMI_Unplugged
+ *
+ *  Input:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Unplugged (void)
+{
+    unsigned char temp = 0;
+    
+    // disable video & audio output: write 11b to #45h[1:0]
+    temp = readHDMIRegister(X45_VIDEO2);
+    writeHDMIRegister(X45_VIDEO2, (temp | 0x03));
+
+    // PS mode e->d->b->a
+    HDMI_System_PD (PowerMode_D);
+    HDMI_System_PD (PowerMode_B);
+    HDMI_System_PD (PowerMode_A);
+}
+
+/*
+ *  Function:
+ *      HDMI_Audio_Reset
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Reset (void)
+{
+    unsigned char temp = 0;
+    
+    if (PowerMode == PowerMode_E)
+    {
+        // Audio reset/release
+        // Audio is mute after reset of audio is set.
+        // Therefore, set it in the following procedures.
+        //   Audio:  Save value of now => Audio Reset => Audio Active => Set value again
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, temp | 0x06 );   // Reset
+        DelayMs(1);                                    // Followed by 1ms wait time
+        writeHDMIRegister(X45_VIDEO2, temp & 0xFB );   // Reset Release and Audio Mute)
+        DelayMs(1);                                    // Followed by 1ms wait time
+        writeHDMIRegister(X45_VIDEO2, temp );   // Reset Release and Audio Mute)
+    }
+}
+
+/*
+ *  Function:
+ *      HDMI_Audio_Mute
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Mute (void)
+{
+    unsigned char temp = 0;
+    
+    if (PowerMode == PowerMode_E)
+    {
+        // disable audio output: write 1b to #45h[1]
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, (temp | 0x02));
+    }
+
+	 AudioMode = Audio_Mute;
+}
+
+/*
+ *  Function:
+ *      HDMI_Audio_Unmute
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Unmute (void)
+{
+    unsigned char temp = 0;
+    
+    if (PowerMode == PowerMode_E)
+    {
+        // enable audio output: write 0b to #45h[1]
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, (temp & (~0x02)));
+
+        // Audio reset/release
+        // Audio is mute after reset of audio is set.
+        // Therefore, set it in the following procedures.
+        //   Audio:  Save value of now => Audio Reset => Audio Active => Set value again
+        temp = readHDMIRegister(X45_VIDEO2);
+        writeHDMIRegister(X45_VIDEO2, temp | 0x04 );   // Reset
+        DelayMs(1);                                    // Followed by 1ms wait time
+        writeHDMIRegister(X45_VIDEO2, temp & (~0x04) );   // Reset Release and Audio Mute)
+    }
+	AudioMode = Audio_Unmute;
+}
+
+
+
+/*
+ *  Function:
+ *      HDMI_Edid_ReadFirstByte
+ *
+ *  Input:
+ *      None
+ *
+ *  Return:
+ *      Fisrt byte of HDMI EDID FIFO
+ *
+ */
+unsigned char HDMI_Edid_ReadFirstByte(void)
+{
+    unsigned long value;
+
+    pokeRegisterDWord(HDMI_CONFIG, 
+        FIELD_SET(0, HDMI_CONFIG, READ, LATCH) | 
+        FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, X80_EDID));
+    
+    DelayMs(1);
+    
+    pokeRegisterDWord(HDMI_CONFIG, FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, X80_EDID));
+    
+    DelayMs(1);
+    
+    value = peekRegisterDWord(HDMI_CONFIG);
+
+    return (unsigned char)((value >> 8) & 0xFF);
+}
+
+/*
+ *  Function:
+ *      HDMI_Edid_CheckSum
+ *
+ *  Input:
+ *      array - EDID data
+ *      size - size of array
+ *
+ *  Return:
+ *      byChecksum
+ *
+ */
+BYTE HDMI_Edid_CheckSum (BYTE* array, unsigned long size)
+{
+    BYTE i, sum = 0;
+    for (i = 0; i < size; i++)
+        sum += array[i];
+
+    return sum;
+}
+
+/*
+ *  Function:
+ *      HDMI_Read_Edid.
+ *		 
+ *  Input:
+ *      pEDIDBuffer - EDID buffer
+ *      bufferSize - EDID buffer size (usually 128-bytes or 256 bytes)
+ *  Output:
+ *      -1 - Error
+ *      0 - exist block0 EDID (128 Bytes)
+ *      1 - exist block0 & block1 EDID (256 Bytes)
+ */
+long HDMI_Read_Edid(BYTE *pEDIDBuffer, unsigned long bufferSize)
+{
+    BYTE byEDID_current = 0;
+    BYTE byEDID_size = 0;
+    BYTE byEDID_finish = 0;
+    #define EDID_WORD   ((byEDID_current % 2) ? 0x80 : 0x00)
+    #define EDID_SEG    (byEDID_current /2)
+    #define EDID_EXT    (gEdidBuffer[126])
+    
+    BYTE byChecksum = 0, regValue;
+    unsigned long i = 0;
+    unsigned long retry = 1000;
+            
+    if (pEDIDBuffer == (unsigned char *)0)
+    {
+        printk("buffer is NULL!\n");
+        return (-1);
+    }
+    
+    // PS mode a -> b if current power mode is in PS mode a
+    if (PowerMode == PowerMode_A)
+    {
+        HDMI_System_PD (PowerMode_B);
+    }
+
+    // clear interrupt status before reading EDID
+    writeHDMIRegister (X94_INT1_ST, 0xFF);
+    writeHDMIRegister (X95_INT2_ST, 0xFF);
+
+    // Enable EDID interrupt
+    regValue = readHDMIRegister (X92_INT_MASK1);
+    writeHDMIRegister (X92_INT_MASK1, (regValue | 0x06));
+
+    while(byEDID_finish == 0)
+    {			
+    	// Set EDID word address (set to 00h for the first 128 bytes)
+    	writeHDMIRegister (XC5_EDID_WD_ADDR, EDID_WORD);	
+    	// Set EDID segment pointer 0
+    	// (Regsiter write to XC4_SEG_PTR will start EDID reading)
+    	writeHDMIRegister (XC4_SEG_PTR, EDID_SEG);
+        
+    	/* Hook the interrupt before going to the while */ 
+        //hookHDMIInterrupt(HdmiHandler);
+    	
+        retry = 1000;
+        while(retry)
+    	{		
+            retry--;
+
+            g_INT_94h = readHDMIRegister (X94_INT1_ST);
+            g_INT_95h = readHDMIRegister (X95_INT2_ST);	
+
+            // EDID ERR interrupt, or EDID not ready
+            if ((g_INT_94h & EDID_ERR))
+            {
+                // clear error interrupt 
+                writeHDMIRegister (X94_INT1_ST, 0xFF);
+                writeHDMIRegister (X95_INT2_ST, 0xFF);
+                DelayMs(1);
+            }
+            else if (g_INT_94h & EDID_RDY)
+            {		
+                // clear ready interrupt 
+                writeHDMIRegister (X94_INT1_ST, 0xFF);
+                writeHDMIRegister (X95_INT2_ST, 0xFF);
+                
+                // Read EDID for current block (128bytes)         
+                gEdidBuffer[byEDID_current* 0x80] = HDMI_Edid_ReadFirstByte();
+                
+                for(i=1;i<128;i++)
+                {
+                    gEdidBuffer[byEDID_current* 0x80+i] = readHDMIRegister(X80_EDID);
+                    DelayMs(1);
+                }
+                printk("EDID read finish\n");
+                
+                // Calculate EDID data byChecksum 
+                byChecksum = HDMI_Edid_CheckSum(gEdidBuffer + (byEDID_current * 0x80), 128);                     
+              //  printf("checksum = %x\n", byChecksum);
+                
+                if (byChecksum != 0)
+                {
+                    // Return fail
+                    printk("Block %x Checksum != 0, fail.\n",byEDID_current);
+                    if (byEDID_current == 0)
+                    {
+                        // Disable EDID interrupt
+                        regValue = readHDMIRegister (X92_INT_MASK1);
+                        writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06)));
+
+                        return (-1);
+                    }
+                    else
+                    {
+                        // Disable EDID interrupt
+                        regValue = readHDMIRegister (X92_INT_MASK1);
+                        writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06)));
+
+                     //   DDKDEBUGPRINT((DISPLAY_LEVEL, "Return the first 128 bytes only.\n"));
+                        // Copy 128 bytes data to the given buffer
+                        for (i = 0; i < 128; i++)
+                        {
+                          //  printf("%x ", gEdidBuffer[i]);
+                            pEDIDBuffer[i] = gEdidBuffer[i];
+                        }
+                        printk("\n");
+                        
+                        return 0;   // read first 128 bytes successfully, extension 128 bytes failed. 
+                    }
+                }
+                else
+                {
+                    //Read Extension flag of EDID
+                    byEDID_size = EDID_EXT;
+
+                    if ((byEDID_size==1) && (byEDID_current < 1))
+                    {
+                        // Move to next EDID block
+                        byEDID_current++;
+                        printk("Exist extern EDID information.\n");
+                        // EDID read block1
+                        //byEDID_STATE = HDMI_STATE_EDID_START;	
+                        break;
+                    }
+                    else
+                    {
+                        printk("HDMI EDID Finished.\n");
+                        byEDID_finish = 1;
+                        break;
+                    }  
+                    
+                }
+                            
+            }
+        }
+        
+        if (retry == 0)
+        {
+            printk("Read HDMI EDID fail.\n");
+            // Disable EDID interrupt
+            regValue = readHDMIRegister (X92_INT_MASK1);
+            writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06)));
+            
+            return (-1);
+        }
+        /* unhook the interrupt */
+        //unhookHDMIInterrupt(HdmiHandler);
+    }
+                   	
+    // Disable EDID interrupt
+    regValue = readHDMIRegister (X92_INT_MASK1);
+    writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06)));
+
+    // Copy data to the given buffer
+    for (i = 0; i < bufferSize; i++)
+    {
+        pEDIDBuffer[i] = gEdidBuffer[i];
+    }
+
+#if 0   // for debug only
+    // Print EDID data
+    for (j = 0; j < 8; j++)
+    {
+        printf("0x%02x: ", (j*16));
+        for (i = 0; i < 16; i++)
+            printf("%02x ", gEdidBuffer[(j*16+i)]);
+        printf("\n");
+    }
+    if (byEDID_current > 0)
+    {
+        printf("E_EDID:\n");
+        for (j = 8; j < 16; j++)
+        {
+            printf("0x%02x: ", (j*16));
+            for (i = 0; i < 16; i++)
+                printf("%02x ", gEdidBuffer[(j*16+i)]);
+            printf("\n");
+        }
+        printf("\n");
+    }
+#endif
+
+    // Return EDID block number
+    return byEDID_current;
+}
+
+/*
+ *  Function:
+ *      HDMI_hotplug_check
+ *		 
+ *  Input:
+ *      None
+ * 
+ *  Output:
+ *      0 - unplugged
+ *      1 - plugged
+ * 
+ */
+BYTE HDMI_connector_detect(void)
+{
+	unsigned long value = 0;
+
+	//enable GPIO
+	pokeRegisterDWord(GPIO_INTERRUPT_SETUP, 0);
+	value = FIELD_SET(peekRegisterDWord(GPIO_DATA_DIRECTION), GPIO_DATA_DIRECTION, 1, INPUT);
+	pokeRegisterDWord(GPIO_DATA_DIRECTION, value);
+	value = peekRegisterDWord(GPIO_DATA);
+
+	return (value & (1<<1));
+}
+
+/*
+ *  Function:
+ *      HDMI_hotplug_check
+ *		 
+ *  Input:
+ *      None
+ * 
+ *  Output:
+ *      0 - unplugged
+ *      1 - plugged
+ * 
+ */
+BYTE HDMI_hotplug_check (void)
+{
+    BYTE STAT_DFh;
+
+    // Wait time before check hot plug & MSENS pin status
+    DelayMs (15);
+
+    STAT_DFh = readHDMIRegister (XDF_HPG_STATUS);
+
+    if ((STAT_DFh & HPG_MSENS) == HPG_MSENS)        // HPD & MSENS status both high? 
+    {
+        // DDC I2C master controller reset ... ddc_ctrl_reset[bit4]
+        writeHDMIRegister (X3B_AVSET2, readHDMIRegister (X3B_AVSET2) | 0x10);
+        writeHDMIRegister (X3B_AVSET2, readHDMIRegister (X3B_AVSET2) & 0xEF);
+        
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+
+}
+
+
+int hdmi_detect(void)
+{
+    unsigned int intStatus;
+
+
+    intStatus = peekRegisterDWord(INT_STATUS);
+	
+    if (FIELD_GET(intStatus, INT_STATUS, HDMI) == INT_STATUS_HDMI_ACTIVE)
+    {
+        
+
+        if (PowerMode == PowerMode_A)
+        {
+            // PS mode a->b
+            HDMI_System_PD(PowerMode_B);
+        }
+
+        // Save interrupt status from the last interrupt
+        g_INT_94h = readHDMIRegister(X94_INT1_ST);
+        g_INT_95h = readHDMIRegister(X95_INT2_ST);
+
+        // check if plug-in or plug-out detect
+        if ((g_INT_94h & HPG_MSENS) == HPG_MSENS)        // HPD & MSENS status both high? 
+        {
+            // clear all interrupts
+            writeHDMIRegister(X94_INT1_ST, 0xFF);
+            writeHDMIRegister(X95_INT2_ST, 0xFF);
+
+            if (HDMI_hotplug_check())
+            {
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+
+        }
+
+    }
+   return 3; //nothing to do 
+}
+
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.h
new file mode 100644
index 000000000000..f15b8ed883df
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_hdmi.h
@@ -0,0 +1,489 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  HDMI.H --- SMI DDK 
+*  This file contains the source code for the HDMI controller chip
+* 
+*******************************************************************/
+
+#ifndef  _HDMI_HEADER_H_
+#define  _HDMI_HEADER_H_
+
+#include "ddk768_mode.h"
+
+#define SMI_HDMI_LIB_VERSION    ("2.0")
+
+#ifndef BYTE
+typedef unsigned char   BYTE;
+#endif
+
+// This macro is for HDMI PNP detection - interrupt mode
+//#define HDMI_PNP_USE_INT
+
+//-----------------------------------------------------------------------------
+// Global Constants
+//-----------------------------------------------------------------------------
+
+// Video setting constants
+#define VID_01_640x480p     1
+#define VID_02_720x480p     2
+#define VID_03_720x480p     3
+#define VID_04_1280x720p    4
+#define VID_05_1920x1080i   5
+#define VID_06_720x480i     6
+#define VID_07_720x480i     7
+#define VID_08_720x240p     8
+#define VID_09_720x240p     9
+#define VID_10_2880x480i    10
+#define VID_11_2880x480i    11
+#define VID_12_2880x240p    12
+#define VID_13_2880x240p    13
+#define VID_14_1440x480p    14
+#define VID_15_1440x480p    15
+#define VID_16_1920x1080p   16
+#define VID_17_720x576p     17
+#define VID_18_720x576p     18
+#define VID_19_1280x720p    19
+#define VID_20_1920x1080i   20
+#define VID_21_720x576i     21
+#define VID_22_720x576i     22
+#define VID_23_720x288p     23
+#define VID_24_720x288p     24
+#define VID_25_2880x576i    25
+#define VID_26_2880x576i    26
+#define VID_27_2880x288p    27
+#define VID_28_2880x288p    28
+#define VID_29_1440x576p    29
+#define VID_30_1440x576p    30
+#define VID_31_1920x1080p   31
+#define VID_32_1920x1080p   32
+#define VID_33_1920x1080p   33
+#define VID_34_1920x1080p   34
+#define VID_35_2880x480p    35
+#define VID_36_2880x480p    36
+#define VID_37_2880x576p    37
+#define VID_38_2880x567p    38
+#define VID_39_1920x1080i   39
+#define VID_40_1920x1080i   40
+#define VID_41_1280x720p    41
+#define VID_42_720x576p     42
+#define VID_43_720x576p     43
+#define VID_44_720x576i     44
+#define VID_45_720x576i     45
+#define VID_46_1920x1080i   46
+#define VID_47_1280x720p    47
+#define VID_48_720x480p     48
+#define VID_49_720x480p     49
+#define VID_50_720x480i     50
+#define VID_51_720x480i     51
+#define VID_52_720x576p     52
+#define VID_53_720x576p     53
+#define VID_54_720x576i     54
+#define VID_55_720x576i     55
+#define VID_56_720x480p     56
+#define VID_57_720x480p     57
+#define VID_58_720x480i     58
+#define VID_59_720x480i     59
+
+// Audio setting constants
+#define AUD_48K         0x10
+#define AUD_96K         0x20
+#define AUD_192K        0x30
+#define AUD_2CH         0x40    // 2ch audio
+#define AUD_8CH         0x80    // 8ch audio
+//#define DS_none           0x00    // No Downsampling
+#define DS_none         0x01    // No Downsampling
+#define DS_2            0x04    // Downsampling 96k to 48k
+#define DS_4            0x08    // DOwnsampling 192k to 48k
+#define AUD_SPDIF       0x01
+#define AUD_I2S         0x02
+
+// Power Mode - System Control
+#define PowerMode_A             0x11
+#define PowerMode_B             0x21
+#define PowerMode_D             0x41
+#define PowerMode_E             0x81
+
+// Audio Mode - For HDMI_Set_Mode's use, in case audio command is received before mode setting
+#define Audio_Mute               0x00
+#define Audio_Unmute             0x01
+
+// Output Format
+#define FORMAT_RGB              0
+#define FORMAT_YCC422           1
+#define FORMAT_YCC444           2
+
+// Deep Color Bit,
+// Should follow GCP_CD[3:0] definition
+#define DEEP_COLOR_8BIT         4
+#define DEEP_COLOR_10BIT        5
+#define DEEP_COLOR_12BIT        6
+
+// Register Values for Register 94h: Interrupt Status 1
+#define INT1_RSVD               0x09
+#define HOT_PLUG                0x80
+#define HPG_MSENS               0xC0
+#define EDID_ERR                0x02
+#define EDID_RDY                0x04
+#define VSYNC                   0x20
+
+// Register Values for Register 95h: Interrupt Status 2
+#define INT2_RSVD               0x07
+#define HDCP_ERR                0x80
+#define BKSV_RDY                0x60
+#define HDCP_AUTH               0x08
+#define HDCP_DONE               0x10
+
+// STATE
+#define HDMI_STATE_IDLE         0x01
+#define HDMI_STATE_HOTPLUG      0x02
+#define HDMI_STATE_EDID_START   0x03
+#define HDMI_STATE_EDID_READY   0x04
+#define HDMI_STATE_EDID_READ    0x05
+#define HDMI_STATE_EDID_PROCESS 0x06
+#define HDMI_STATE_TX_SETTING   0x07
+#define HDMI_STATE_TX_START     0x08
+#define HDMI_STATE_TX_RUNNING   0x09
+#define HDMI_STATE_HDCP_START   0x0A
+#define HDMI_STATE_HDCP_READY   0x0B
+#define HDMI_STATE_HDCP_READ    0x0C
+#define HDMI_STATE_HDCP_AUTH    0x0D
+//#define HDMI_STATE_PHY_RESET    0x0E
+#define HDMI_STATE_ERROR        0x00
+#define STATE_DEBUG             0xFF
+
+
+//-----------------------------------------------------------------------------
+// Type Definition
+//-----------------------------------------------------------------------------
+
+typedef enum _aspect_ratio_t
+{
+    AR_4to3, /* 4:3 */
+    AR_16to9, /* 16:9 */
+}
+aspect_ratio_t;
+
+typedef enum _TMDS_clk_t
+{
+    CLK_0_to_50, /* 0-50MHz TMDS clock */
+    CLK_50_to_100, /* 50-100MHz TMDS clock */
+    CLK_100_to_150, /* 100-150MHz TMDS clock */
+    CLK_150_to_200, /* 150-200MHz TMDS clock */
+    CLK_200_to_250, /* 200-250MHz TMDS clock */
+    CLK_4Kmode, /* 4K mode uses seperate PHY parameters */
+}
+TMDS_clk_t;
+
+typedef struct _hdmi_PHY_param_t
+{
+    unsigned char X17_PHY_value;
+    unsigned char X56_PHY_value;
+    unsigned char X57_PHY_value;
+    unsigned char X58_PHY_value;
+    unsigned char X59_PHY_value;
+    unsigned char X5A_PHY_value;
+    unsigned char X5B_PHY_value;
+    unsigned char X5C_PHY_value;
+    unsigned char X5D_PHY_value;
+    unsigned char X5E_PHY_value;
+}
+hdmi_PHY_param_t;
+
+typedef struct _hdmi_vic_param_t
+{
+    unsigned long Width;
+    unsigned long Height;
+    unsigned char Vic;
+}
+hdmi_vic_param_t; 
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+
+/*
+ * This is the main interrupt hook for HDMI engine.
+ */
+long hookHDMIInterrupt(
+    void (*handler)(void)
+);
+
+/*
+ * This function un-register HDMI Interrupt handler.
+ */
+long unhookHDMIInterrupt(
+    void (*handler)(void)
+);
+
+/*
+ *  Function: 
+ *      writeHDMIRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (could be from 0x01 to 0xFF)
+ *      value   - HDMI register value
+ *
+ *  Output:
+ *      None
+ *
+ */
+void writeHDMIRegister(unsigned char addr, unsigned char value);
+
+/*
+ *  Function: 
+ *      readHDMIRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (could be from 0x01 to 0xFF)
+ *
+ *  Output:
+ *      register value
+ *
+ */
+unsigned char readHDMIRegister(unsigned char addr);
+
+/*
+ *  Function: 
+ *      writeHDMIControlRegister
+ *      This functions writes HDMI System Control register (index 0x00). 
+ *
+ *  Input:
+ *      value   - HDMI register 0x00 value
+ *
+ *  Output:
+ *      None
+ *  
+ */
+void writeHDMIControlRegister(unsigned char value);
+
+/*
+ *  Function: 
+ *      readHDMIRegister
+ *      This functions reads HDMI System Control register (index 0x00). 
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      register value
+ *
+ */
+unsigned char readHDMIControlRegister(void);
+
+/*
+ *  Function: 
+ *      writeHdmiPHYRegister
+ *
+ *  Input:
+ *      addr    - HDMI register index (for PHY registers only, could be from 0x57 to 0x5E)
+ *      value   - HDMI register value
+ *
+ *  Output:
+ *      None
+ *
+ */
+void writeHdmiPHYRegister(unsigned char addr, unsigned char value);
+
+/*
+ *  Function:
+ *      setHDMIChannel
+ *
+ *  Input:
+ *      channel number      -   0 = Select Channel 0 to HDMI
+ *                                  -   1 = Select Channel 1 to HDMI
+ *
+ *  Output:
+ *      None
+ *
+ */
+void setHDMIChannel(unsigned char Channel);
+
+/*
+ *  Function:
+ *      enableHdmiI2C
+ *
+ *  Input:
+ *      enable/disable      -   0 = HDMI I2C to GPIO[7:6]
+ *                                  -   1 = HW I2C to GPIO[7:6]
+ *
+ *  Output:
+ *      None
+ *
+ */
+void enableHdmI2C(unsigned long enable);
+
+/*
+ *  Function:
+ *      HDMI_Dump_Registers (Used for debug)
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ */
+void HDMI_Dump_Registers (void);
+
+//
+// Parameters   : unsigned char mode. 4 modes available.
+//                  MODE_A (sleep), MODE_B (register access), MODE_D (clock), MODE_E (active).
+//
+void HDMI_System_PD (unsigned char mode);
+
+/*
+ *  Function:
+ *      HDMI_Set_Control_Packet
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ */
+void HDMI_Init (void);
+
+/*
+ *  Function:
+ *      HDMI_Set_Mode
+ *
+ *  Input:
+ *      pLogicalMode
+ *      isHDMI      - 1: HDMI monitor; 0: DVI monitor
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      0 - Success
+ *      -1 - Error 
+ *
+ */
+long HDMI_Set_Mode (logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI);
+
+
+void HDMI_Enable_Output(void);
+
+/*
+ *  Function:
+ *      HDMI_Disable_Output
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Disable_Output (void);
+
+/*
+ *  Function:
+ *      HDMI_Unplugged
+ *
+ *  Input:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Unplugged (void);
+
+/*
+ *  Function:
+ *      HDMI_Audio_Reset
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Reset (void);
+
+/*
+ *  Function:
+ *      HDMI_Audio_Mute
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Mute (void);
+
+/*
+ *  Function:
+ *      HDMI_Audio_Unmute
+ *
+ *  Input:
+ *      None
+ *
+ *  Output:
+ *      None
+ *
+ *  Return:
+ *      None
+ *
+ */
+void HDMI_Audio_Unmute (void);
+
+
+
+
+/*
+ *  Function:
+ *      HDMI_Read_Edid.
+ *		 
+ *  Input:
+ *      pEDIDBuffer - EDID buffer
+ *      bufferSize - EDID buffer size (usually 128-bytes or 256 bytes)
+ *  Output:
+ *      -1 - Error
+ *      0 - exist block0 EDID (128 Bytes)
+ *      1 - exist block0 & block1 EDID (256 Bytes)
+ */
+long HDMI_Read_Edid(BYTE *pEDIDBuffer, unsigned long bufferSize);
+
+/*
+ *  Function:
+ *      HDMI_hotplug_check
+ *		 
+ *  Input:
+ *      None
+ * 
+ *  Output:
+ *      0 - unplugged
+ *      1 - plugged
+ * 
+ */
+BYTE HDMI_hotplug_check (void);
+
+int hdmi_detect(void);
+
+BYTE HDMI_connector_detect(void);
+
+void hdmiHandler(void);
+void Delay (void);
+void DelayMs (BYTE millisecond);
+
+#endif  /* _HDMI_HEADER_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_help.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_help.c
new file mode 100644
index 000000000000..804f095a725a
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_help.c
@@ -0,0 +1,16 @@
+#include "ddk768_help.h"
+
+volatile unsigned char __iomem * mmio768 = NULL;
+char revId768 = 0;
+unsigned short devId768 = 0;
+
+/* after driver mapped io registers, use this function first */
+void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId)
+{
+	mmio768 = addr;
+	devId768 = devId;
+	revId768 = revId;
+	printk("Found SM768 SOC Chip\n");
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_help.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_help.h
new file mode 100644
index 000000000000..0b712b3b17d1
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_help.h
@@ -0,0 +1,37 @@
+#ifndef _DDK768_HELP_H__
+#define _DDK768_HELP_H__
+
+#ifndef USE_INTERNAL_REGISTER_ACCESS
+
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+
+
+#define PEEK32(addr) readl((addr)+mmio768)
+#define POKE32(addr,data) writel((data),(addr)+mmio768)
+
+
+#define peekRegisterDWord(addr) readl((addr)+mmio768)
+#define pokeRegisterDWord(addr,data) writel((data),(addr)+mmio768)
+
+#define peekRegisterByte(addr) readb((addr)+mmio768)
+#define pokeRegisterByte(addr,data) writeb((data),(addr)+mmio768)
+
+
+/* Size of SM768 MMIO and memory */
+#define SM768_PCI_ALLOC_MMIO_SIZE       (2*1024*1024)
+#define SM768_PCI_ALLOC_MEMORY_SIZE     (128*1024*1024)
+
+
+void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId);
+
+extern volatile unsigned  char __iomem * mmio768;
+extern char revId768;
+extern unsigned short devId768;
+#else
+/* implement if you want use it*/
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.c
new file mode 100644
index 000000000000..9407956d1410
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.c
@@ -0,0 +1,84 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  helper.c --- SM750 DDK 
+*  This file contains helper functions those are used throughout
+*  the DDK library.
+* 
+*******************************************************************/
+#include "ddkdebug.h"
+
+/* A test counter to be shared by all modules */
+static unsigned long gTestCounter;
+
+/* Functions to manipulate a test counter. */
+unsigned long getTestCounter(void)
+{
+    return gTestCounter;
+}
+
+void setTestCounter(unsigned long value)
+{
+    gTestCounter = value;
+}
+
+void incTestCounter(void)
+{
+    gTestCounter++;
+}
+
+/* Perform a rounded division with signed number. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+long lRoundedDiv(long num, long denom)
+{
+    /* n / d + 1 / 2 = (2n + d) / 2d */
+    return (2 * num + denom) / (2 * denom);
+}
+
+/* Perform a rounded division. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+unsigned long ddk768_roundedDiv(unsigned long num, unsigned long denom)
+{
+    /* n / d + 1 / 2 = (2n + d) / 2d */
+    return (2 * num + denom) / (2 * denom);
+}
+
+/* Perform a rounded division with unsigned number. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+unsigned long ulRoundedDiv(unsigned long num, unsigned long denom)
+{
+    return ddk768_roundedDiv(num, denom);
+}
+
+/* Absolute differece between two numbers */
+unsigned long ddk768_absDiff(unsigned long a, unsigned long b)
+{
+    if ( a >= b )
+        return(a - b);
+    else
+        return(b - a);
+}
+
+/* This function calculates 2 to the power of x 
+   Input is the power number.
+ */
+unsigned long ddk768_twoToPowerOfx(unsigned long x)
+{
+    unsigned long i;
+    unsigned long result = 1;
+
+    for (i=1; i<=x; i++)
+        result *= 2;
+
+    return result;
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.h
new file mode 100644
index 000000000000..cd6f9f8bf0eb
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_helper.h
@@ -0,0 +1,44 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  helper.h --- SMI DDK 
+*  This file contains the helper functions those are used throughout
+*  the library
+* 
+*******************************************************************/
+#ifndef _DDK768_HELPER_H_
+#define _DDK768_HELPER_H_
+
+/* Functions to manipulate a test counter. */
+unsigned long getTestCounter(void);
+
+void setTestCounter(unsigned long value);
+
+void incTestCounter(void);
+
+
+/* Perform a rounded division with signed number. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+long lRoundedDiv(long num, long denom);
+
+/* Perform a rounded division. 
+ * For example, if the result is 4.5, this function returns 5.
+ * If the result is 4.4, this function returns 4.
+ */
+unsigned long ddk768_roundedDiv(unsigned long num, unsigned long denom);
+
+/* Absolute differece between two numbers */
+unsigned long ddk768_absDiff(unsigned long a, unsigned long b);
+
+/* This function calculates 2 to the power of x 
+   Input is the power number.
+ */
+unsigned long ddk768_twoToPowerOfx(unsigned long x);
+
+#endif  /* _HELPER_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.c
new file mode 100644
index 000000000000..71e23cf057c5
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.c
@@ -0,0 +1,426 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  hwi2c.c --- SMI DDK 
+*  This file contains the source code for hardware i2c.
+* 
+*******************************************************************/
+
+
+#include "ddk768_reg.h"
+#include "ddk768_power.h"
+#include "ddk768_hwi2c.h"
+#include "ddk768_help.h"
+
+unsigned long hwI2CWriteData(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+);
+
+unsigned long hwI2CReadData(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+);
+
+static int ddk768_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+                           int num)
+{
+    struct smi_connector *connector = i2c_get_adapdata(adap);
+    unsigned char i2cNumber = connector->i2cNumber;
+    unsigned long ret;
+    int i, count = 0;
+
+    if(i2cNumber > 1)
+    {
+        return -EOPNOTSUPP;
+    }
+    for (i = 0; i < (num - 1); i++)
+        if (msgs[i].flags & I2C_M_RD)
+        {
+            pr_err("only one read message supported, has to be last\n");
+            return -EOPNOTSUPP;
+        }
+
+    while (msgs->len && (count < num))
+    {
+	    msgs->addr = msgs->addr << 1;
+        if (!(msgs->flags & I2C_M_RD))
+        {
+            ret = hwI2CWriteData(
+                i2cNumber, // I2C0 or I2C1
+                msgs->addr,
+                msgs->len,
+                msgs->buf);
+            if (ret < msgs->len)
+            {
+                pr_err("ddk768 i2c xfer tx failed %ld.\n", ret);
+                break;
+            }
+        }
+        else
+        {
+            ret = hwI2CReadData(
+                i2cNumber, // I2C0 or I2C1
+                msgs->addr,
+                msgs->len,
+                msgs->buf);
+            if (ret < msgs->len)
+            {
+                pr_err("ddk768 i2c xfer rx failed %ld.\n", ret);
+                break;
+            }
+        }
+
+        msgs++;
+        count++;
+    }
+
+    if (count < num)
+    {
+        pr_err("ddk768 i2c xfer failed %d(%d).\n", count, num);
+        return -EIO;
+    }
+
+    return num;
+}
+
+static u32 ddk768_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+const struct i2c_algorithm ddk768_i2c_algo = {
+	.master_xfer	= ddk768_i2c_xfer,
+	.functionality	= ddk768_i2c_func
+};
+
+/*
+ *  This function initializes the hardware i2c
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to initialize i2c
+ */
+long ddk768_hwI2CInit(
+    unsigned char i2cNumber //I2C0 or I2C1
+)
+{
+    unsigned long value, offset;
+    if(i2cNumber > 1) {
+        return -1;
+    }
+
+    /* Enable GPIO pins as IIC clock & data */
+    if (i2cNumber == 0)
+    {
+        value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C0, ENABLE);
+        pokeRegisterDWord(GPIO_MUX, value);
+        offset = 0;
+    }
+    else
+    {
+        value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C1, ENABLE);
+        pokeRegisterDWord(GPIO_MUX, value);
+        offset = I2C_OFFSET;
+    }
+              
+    /* Enable the I2C Controller and set the bus speed mode */
+    value = FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, EN, ENABLE);
+    value = FIELD_SET(value, I2C_CTRL, MODE, FAST);        
+    pokeRegisterByte(I2C_CTRL+offset, value);
+
+    return 0;
+}
+
+/*
+ *  This function closes the hardware i2c.
+ */
+void ddk768_hwI2CClose(
+    unsigned char i2cNumber //I2C0 or I2C1
+)
+{
+    unsigned long value, offset;
+    
+    /* Set GPIO 30 & 31 back as GPIO pins */
+    if (i2cNumber == 0)
+    {
+        value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C0, DISABLE);
+        pokeRegisterDWord(GPIO_MUX, value);
+        offset = 0;
+    }
+    else
+    {
+        value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C1, DISABLE);
+        pokeRegisterDWord(GPIO_MUX, value);
+        offset = I2C_OFFSET;
+    }
+
+    /* Disable I2C controller */
+    value = FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, EN, DISABLE);
+    pokeRegisterByte(I2C_CTRL+offset, value);
+}
+
+
+/*
+ *  This function waits until the transfer is completed within the timeout value.
+ *
+ *  Return Value:
+ *       0   - Transfer is completed
+ *      -1   - Tranfer is not successful (timeout)
+ */
+long ddk768_hwI2CWaitTXDone(
+    unsigned char i2cNumber //I2C0 or I2C1
+)
+{
+    unsigned long timeout, offset;
+
+    offset = (i2cNumber == 0)? 0 : I2C_OFFSET;
+
+    /* Wait until the transfer is completed. */
+    timeout = HWI2C_WAIT_TIMEOUT;
+    while ((FIELD_GET(peekRegisterByte(I2C_STATUS+offset), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) &&
+           (timeout != 0))
+        timeout--;
+    
+    if (timeout == 0)
+        return (-1);
+
+    return 0;
+}
+
+/*
+ *  This function writes data to the i2c slave device registers.
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address
+ *      length          - Total number of bytes to be written to the device
+ *      pBuffer         - The buffer that contains the data to be written to the
+ *                     i2c device.   
+ *
+ *  Return Value:
+ *      Total number of bytes those are actually written.
+ */
+unsigned long hwI2CWriteData(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned char count, i;
+    unsigned long offset, totalBytes = 0;
+    
+    offset = (i2cNumber == 0)? 0 : I2C_OFFSET;
+
+    /* Set the Device Address */
+    pokeRegisterByte(I2C_SLAVE_ADDRESS+offset, deviceAddress & ~0x01);
+    
+    /* Write data.
+     * Note:
+     *      Only 16 byte can be accessed per i2c start instruction.
+     */
+    do
+    {
+        /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */
+        pokeRegisterByte(I2C_RESET+offset, 0);
+        
+        /* Set the number of bytes to be written */
+        if (length < MAX_HWI2C_FIFO)
+            count = length - 1;
+        else
+            count = MAX_HWI2C_FIFO - 1;
+        pokeRegisterByte(I2C_BYTE_COUNT+offset, count);
+        
+        /* Move the data to the I2C data register */
+        for (i = 0; i <= count; i++)
+            pokeRegisterByte(I2C_DATA0 + i + offset, *pBuffer++);
+
+        /* Start the I2C */
+        pokeRegisterByte(I2C_CTRL+offset, FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, CTRL, START));
+        
+        /* Wait until the transfer is completed. */
+        if (ddk768_hwI2CWaitTXDone(i2cNumber) != 0)
+            break;
+    
+        /* Substract length */
+        length -= (count + 1);
+        
+        /* Total byte written */
+        totalBytes += (count + 1);
+        
+    } while (length > 0);
+            
+    return totalBytes;
+}
+
+/*
+ *  This function reads data from the slave device and stores them
+ *  in the given buffer
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address
+ *      length          - Total number of bytes to be read
+ *      pBuffer         - Pointer to a buffer to be filled with the data read
+ *                     from the slave device. It has to be the same size as the
+ *                     length to make sure that it can keep all the data read.   
+ *
+ *  Return Value:
+ *      Total number of actual bytes read from the slave device
+ */
+unsigned long hwI2CReadData(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress,
+    unsigned long length,
+    unsigned char *pBuffer
+)
+{
+    unsigned char count, i;
+    unsigned long offset, totalBytes = 0; 
+    
+    offset = (i2cNumber == 0)? 0 : I2C_OFFSET;
+
+    /* Set the Device Address */
+    pokeRegisterByte(I2C_SLAVE_ADDRESS+offset, deviceAddress | 0x01);
+    
+    /* Read data and save them to the buffer.
+     * Note:
+     *      Only 16 byte can be accessed per i2c start instruction.
+     */
+    do
+    {
+        /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */
+        pokeRegisterByte(I2C_RESET+offset, 0);
+        
+        /* Set the number of bytes to be read */
+        if (length <= MAX_HWI2C_FIFO)
+            count = length - 1;
+        else
+            count = MAX_HWI2C_FIFO - 1;
+        pokeRegisterByte(I2C_BYTE_COUNT+offset, count);
+
+        /* Start the I2C */
+        pokeRegisterByte(I2C_CTRL+offset, FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, CTRL, START));
+        
+        /* Wait until transaction done. */
+        if (ddk768_hwI2CWaitTXDone(i2cNumber) != 0)
+            break;
+
+        /* Save the data to the given buffer */
+        for (i = 0; i <= count; i++)
+        {
+            *pBuffer++ = peekRegisterByte(I2C_DATA0 + i + offset);
+        }
+
+        /* Substract length by 16 */
+        length -= (count + 1);
+    
+        /* Number of bytes read. */
+        totalBytes += (count + 1); 
+        
+    } while (length > 0);
+    
+    return totalBytes;
+}
+
+/*
+ *  This function reads the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      registerIndex   - Slave device's register to be read
+ *
+ *  Return Value:
+ *      Register value
+ */
+unsigned char ddk768_hwI2CReadReg(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+)
+{
+    unsigned char value = (0xFF);
+
+    if (hwI2CWriteData(i2cNumber, deviceAddress, 1, &registerIndex) == 1)
+        hwI2CReadData(i2cNumber, deviceAddress, 1, &value);
+
+    return value;
+}
+
+/*
+ *  This function writes a value to the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk768_hwI2CWriteReg(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+)
+{
+    unsigned char value[2];
+    
+    value[0] = registerIndex;
+    value[1] = data;
+    if (hwI2CWriteData(i2cNumber, deviceAddress, 2, value) == 2)
+        return 0;
+
+    return (-1);
+}
+
+
+long ddk768_AdaptHWI2CInit(struct smi_connector *connector)
+{
+    int ret;
+
+    if (connector->base.connector_type == DRM_MODE_CONNECTOR_VGA)
+    connector->i2cNumber = 1;
+    else if (connector->base.connector_type == DRM_MODE_CONNECTOR_DVII)
+    connector->i2cNumber = 0;
+    else
+    connector->i2cNumber = 2; // No exist.
+
+    ddk768_hwI2CInit(connector->i2cNumber);
+
+    connector->adapter.owner = THIS_MODULE;
+    connector->adapter.class = I2C_CLASS_DDC;
+    snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI HW I2C Bus");
+    connector->adapter.dev.parent = connector->base.dev->dev;
+    i2c_set_adapdata(&connector->adapter, connector);
+	connector->adapter.algo = &ddk768_i2c_algo;
+    ret = i2c_add_adapter(&connector->adapter);
+	if (ret)
+    {
+        pr_err("HW i2c add adapter failed. %d\n", ret);
+		return -1;
+    }
+
+    return 0;
+}
+
+long ddk768_AdaptHWI2CCleanBus(struct smi_connector *connector)
+{
+    ddk768_hwI2CClose(connector->i2cNumber);
+    return 0;
+}
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.h
new file mode 100644
index 000000000000..47be028de17f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_hwi2c.h
@@ -0,0 +1,81 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  hwi2c.H --- SMI DDK 
+*  This file contains the definitions for Hardware I2C.
+* 
+*******************************************************************/
+#ifndef _DDK768_HWI2C_H_
+#define _DDK768_HWI2C_H_
+
+
+#include "../smi_drv.h"
+
+
+#define MAX_HWI2C_FIFO 16
+#define HWI2C_WAIT_TIMEOUT 0x7FF
+
+extern const struct i2c_algorithm ddk768_i2c_algo;
+
+
+/*
+ *  This function initializes the hardware i2c
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to initialize i2c
+ */
+long ddk768_hwI2CInit(
+    unsigned char i2cNumber //I2C0 or I2C1
+);
+
+/* 
+ * This function close the hardware i2c 
+ */
+void ddk768_hwI2CClose(
+    unsigned char i2cNumber //I2C0 or I2C1
+);
+
+/* 
+ * This function read the i2c device register value
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be read
+ *
+ * Output:
+ *          The value of the register being read.
+ */
+unsigned char ddk768_hwI2CReadReg(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+);
+
+/* 
+ * This function writes a value to the i2c device register.
+ *
+ * Input:   deviceAddress   - I2C Device Address
+ *          registerIndex   - Register index to be written to
+ *          data            - Data to be written to
+ *
+ * Output:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk768_hwI2CWriteReg(
+    unsigned char i2cNumber, //I2C0 or I2C1
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+);
+
+long ddk768_AdaptHWI2CInit(struct smi_connector *connector);
+long ddk768_AdaptHWI2CCleanBus(struct smi_connector *connector);
+
+
+
+#endif  /* _HWI2C_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.c
new file mode 100644
index 000000000000..7424c5dc3cad
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.c
@@ -0,0 +1,274 @@
+/*******************************************************************
+*
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+*
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+*
+*  This file contains the definitions for the IIS functions.
+*
+*******************************************************************/
+
+
+#include "ddk768_reg.h"
+#include "ddk768_iis.h"
+#include "ddk768_help.h"
+#include "ddk768_power.h"
+#include "ddk768_chip.h"
+
+
+/*
+ * Set up I2S and GPIO registers to transmit/receive data.
+ */
+void iisOpen(
+   unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit
+   unsigned long sampleRate  //Sampling rate.
+)
+{
+    unsigned long value, clockDivider, iisRefClk;
+    unsigned char ws;
+
+    ddk768_enableI2S(1); //Turn on I2S clock
+
+    /* Configure GPIO Mux for I2s output */
+    value = peekRegisterDWord(GPIO_MUX);
+    value |= (1 << GPIO_MUX_IIS_RX_SHIFT);        // I2S Data Input
+    value &= ~(1 << GPIO_MUX_GPIO_IIS_TX_SHIFT);         // I2S Tx Output
+    value &= ~(1 << GPIO_MUX_GPIO_IIS_WS_SHIFT);          // I2S Word Select
+    value &= ~(1 << GPIO_MUX_GPIO_IIS_CLK_SHIFT);        //  I2S Clock Out
+    value |= (1 << GPIO_MUX_IIS_TX_SELECT_SHIFT);
+    value |= (1 << GPIO_MUX_IIS_WS_SELECT_SHIFT);
+    value |= (1 << GPIO_MUX_IIS_CLK_SELECT_SHIFT);
+    pokeRegisterDWord(GPIO_MUX, value);
+
+    /* Make sure GPIO data direction (0x10004) bit 28 = 0 (input) */
+    value = peekRegisterDWord(GPIO_DATA_DIRECTION);
+    value &= ~(1 << GPIO_DATA_DIRECTION_IIS_RX_SHIFT);
+    pokeRegisterDWord(GPIO_DATA_DIRECTION, value);
+
+    /* IIS register set up */
+    pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers
+    pokeRegisterDWord(I2S_TX_DATA_R, 0);    
+
+    //Figure out Word Select value
+    switch (wordLength)
+    {
+        case 32:
+            ws = 2;
+            break;
+        case 24:
+            ws = 1;
+            break;
+        default:
+            ws = 0;
+    }
+
+	/* Calculate IIS_REF_CLOCK.*/
+    value = FIELD_GET(peekRegisterDWord(USBH_CLOCK), USBH_CLOCK, FS_IIS);
+
+	if (ddk768_getCrystalType())
+		iisRefClk = 24576000 * value / 8;
+	else
+		iisRefClk = 24000000 * value / 8;
+
+    clockDivider = (iisRefClk / (4 * sampleRate * wordLength)) - 1;
+
+    pokeRegisterDWord(I2S_CTRL, 
+          FIELD_VALUE(0, I2S_CTRL, CS, ws)
+        | FIELD_VALUE(0, I2S_CTRL , CDIV, clockDivider));
+
+    pokeRegisterDWord(I2S_SRAM_DMA, 0);  //Default no DMA. Call another function to set up DMA
+}
+
+
+/*
+ *    Turn off I2S and close GPIO 
+ */
+void iisClose()
+{
+    unsigned long value;
+
+    /* Close GPIO Mux for I2s output   Clear bit 28 and 4:2*/
+    value = peekRegisterDWord(GPIO_MUX);
+    value &= ~(1 << GPIO_MUX_IIS_RX_SHIFT);
+    value &= ~(1 << GPIO_MUX_IIS_TX_SELECT_SHIFT);
+    value &= ~(1 << GPIO_MUX_IIS_WS_SELECT_SHIFT);
+    value &= ~(1 << GPIO_MUX_IIS_CLK_SELECT_SHIFT);
+    pokeRegisterDWord(GPIO_MUX, value);
+
+    pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers
+    pokeRegisterDWord(I2S_TX_DATA_R, 0);    
+    pokeRegisterDWord(I2S_STATUS, 0);    //Disable Tx line out
+    pokeRegisterDWord(I2S_CTRL, 0);      //Clear clock setting.
+    pokeRegisterDWord(I2S_SRAM_DMA, 0);  //Clear DMA setting.
+
+}
+
+
+
+
+/*
+ *  This function set up I2S to DMA data from SRAM.
+ *
+ *  SRAM area has max size of 2048 bytes (or 512 DWords).
+ *  Max size of each I2S DMA session is 256 DWords.
+ *
+ *  Inputs: 
+ *        offset address in SRAM to start DMA (DWord aligned)
+ *        Number of bytes to DMA (DWord aligned)
+ */
+void iisTxDmaSetup(
+    unsigned long offset, /* Offset from start of SRAM to start DMA */
+    unsigned long len     /* Number of bytes to DMA */
+    )
+{
+    unsigned long dmaPointer;
+
+    offset >>= 2; //I2S DMA register requires offset to be expressed in DWord
+    len >>= 2;
+    len--; //I2S DMA register requires length to be expressed as DWord - 1.
+
+    dmaPointer = FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS);
+
+    //If DMA pointer already at the requested offset. Just set up the length.
+    if (dmaPointer == offset)
+    {
+        pokeRegisterDWord(I2S_SRAM_DMA,
+          FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE)
+        | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len)
+        | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset));
+
+        return;
+    }
+
+    //Position DMA pointer to the new base pointer (or offset).
+    //Note that DMA reload base pointer only when it gets to end of SRAM.
+    //Therefore, we need to advance DMA from current position to the end.
+    pokeRegisterDWord(I2S_SRAM_DMA,
+          FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE)
+        | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, (0x1FF - dmaPointer))
+        | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, dmaPointer));
+
+    iisStartNoTx();//Start DMA without output the old data from Tx line.
+
+    //Once DMA starts, make the new base pointer ready.
+    pokeRegisterDWord(I2S_SRAM_DMA,
+          FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE)
+        | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len)
+        | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset));
+
+    // When DMA get to the end of SRAM, it loads the new base pointer.
+    do
+    {
+      dmaPointer = FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS);
+    } while(dmaPointer != offset);
+
+    iisStop();
+}
+
+/*
+ * Return current IIS DMA position.
+ */
+unsigned long iisDmaPointer(void)
+{
+    return(FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS));
+}
+
+/*
+ * This function start IIS without enabling Tx line.
+ * It can be used to flush left over SRAM data without
+ * sending them to Codec.
+ */
+void iisStartNoTx(void)
+{
+    unsigned long value;
+
+    value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER);
+    pokeRegisterDWord(I2S_CTRL, value);
+}
+
+
+/*
+ * This function is needed only when I2S is intended to operate in master mode.
+ *
+ * For slave mode, just use iisOpen() is enough, because I2S will start
+ * functioning as soon as an external clock is detected after iisOpen().
+ *
+ */
+
+void iisStart(void)
+{
+	unsigned long value;
+	
+	pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, ENABLE));  //Enable Tx line out
+	
+	value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER);
+	pokeRegisterDWord(I2S_CTRL, value);
+
+}
+
+/*
+ * This function is useful only when I2S is operating in master mode.
+ *
+ * For slave mode, clock is external and cannot be stopped by IIS
+ * control register.
+ *
+ */
+void iisStop(void)
+{
+    unsigned long value;
+
+    value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, SLAVE);
+    pokeRegisterDWord(I2S_CTRL, value);
+
+    pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, DISABLE));  //Disable Tx line out
+
+}
+
+
+/*
+ * Set values for left Tx and right Tx register.
+ */
+void iisSetTx(
+    unsigned long left, //Data for left channel Tx
+    unsigned long right //Data for right channel Tx
+    )
+{
+    pokeRegisterDWord(I2S_TX_DATA_L, left);
+    pokeRegisterDWord(I2S_TX_DATA_R, right);
+}
+
+
+
+/*
+ * This function clears the RAW interrupt status of I2S.
+ *
+ * When I2S completes sending data, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different sessions of countdown.
+ *
+ */
+void iisClearRawInt(void)
+{
+    /* Read I2S Control & TX to clear INT when IIS get data from Tx & Rx. */
+    peekRegisterDWord(I2S_STATUS);
+
+    /* Write 0 to I2S SRAM DMA status when IIS get data from SRAM */
+    pokeRegisterDWord(I2S_SRAM_DMA_STATUS, 0);
+
+}
+
+
+/* 
+ * This function returns the INT mask for IIS.
+ *
+ */
+unsigned long iisIntMask(void)
+{
+    unsigned long mask = 0;
+
+    mask |= FIELD_SET(0, INT_MASK, I2S, ENABLE);
+
+    return mask;
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.h
new file mode 100644
index 000000000000..230a7cb0ab8d
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_iis.h
@@ -0,0 +1,109 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  This file contains the definitions for the IIS functions.
+* 
+*******************************************************************/
+#ifndef _IIS_H_
+#define _IIS_H_
+
+
+#define IIS_REF_CLOCK 48000000
+
+
+/*
+ * Set up I2S and GPIO registers to transmit/receive data.
+ */
+void iisOpen(
+   unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit
+   unsigned long sampleRate  //Sampling rate.
+);
+
+/*
+ *    Turn off I2S and close GPIO 
+ */
+void iisClose(void);
+
+/*
+ *  This function set up I2S to DMA data from SRAM.
+ *
+ *  SRAM area has max size of 2048 bytes (or 512 DWords).
+ *  Max size of each I2S DMA session is 256 DWords.
+ *
+ *  Inputs: 
+ *        offset address in SRAM to start DMA (DWord aligned)
+ *        Number of bytes to DMA (DWord aligned)
+ */
+void iisTxDmaSetup(
+    unsigned long offset, /* Offset from start of SRAM area */
+    unsigned long len     /* Number of bytes to DMA */
+    );
+
+/*
+ * Return current IIS DMA position.
+ */
+unsigned long iisDmaPointer(void);
+
+/*
+ * This function start IIS without enabling Tx line.
+ * It can be used to flush left over SRAM data without
+ * sending them to Codec.
+ */
+void iisStartNoTx(void);
+
+/*
+ * This function is needed only when I2S is intended to operate in master mode.
+ *
+ * For slave mode, just use iisOpen() is enough, because I2S will start
+ * functioning as soon as an external clock is detected after iisOpen().
+ *
+ */
+void iisStart(void);
+
+/*
+ * This function is useful only when I2S is operating in master mode.
+ *
+ * For slave mode, clock is external and cannot be stopped by IIS
+ * control register.
+ *
+ */
+void iisStop(void);
+
+/*
+ * Set values for left Tx and right Tx register.
+ */
+void iisSetTx(
+    unsigned long left, //Data for left channel Tx
+    unsigned long right //Data for right channel Tx
+    );
+
+/*
+ * This function clears the RAW interrupt status of I2S.
+ * 
+ * When I2S completes sending data, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different sessions of countdown.
+ * 
+ */
+void iisClearRawInt(void);
+
+/* 
+ * This function returns the INT mask for IIS.
+ *
+ */
+unsigned long iisIntMask(void);
+
+/*
+ * This is a reference sample showing how to implement ISR for I2S.
+ * It works wiht libsrc\intr.c together.
+ * 
+ * Refer to Apps\iis\tstiis.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+
+
+#endif /* _IIS_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.c
new file mode 100644
index 000000000000..16ad93c7e838
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.c
@@ -0,0 +1,62 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  intr.c --- SM750/SM718 DDK 
+*  This file contains the source code for the interrupt management.
+* 
+*******************************************************************/
+
+#include "ddk768_reg.h"
+#include "ddk768_chip.h"
+#include "ddk768_intr.h"
+#include "ddk768_help.h"
+
+
+/* 
+ * Change interrupt mask 
+ */
+void setIntMask(
+    unsigned long mask_on, 
+    unsigned long mask_off
+)
+{
+    unsigned long mask;
+
+    /* Get current interrupt mask */
+    mask = peekRegisterDWord(INT_MASK);
+
+    /* Enable new masks and disable old masks */
+    mask = mask | mask_on;
+    mask = mask & ~mask_off;
+
+    /* Program new interrupt mask */
+    pokeRegisterDWord(INT_MASK, mask);
+}
+
+
+void sb_IRQMask(int irq_num)
+{
+		unsigned int mask;
+        mask = peekRegisterDWord(INT_MASK);
+        mask &= ~(0x1<<irq_num);
+        pokeRegisterDWord(INT_MASK,mask);  
+  
+}
+
+
+
+
+void sb_IRQUnmask(int irq_num)
+{
+		unsigned int mask;
+        mask = peekRegisterDWord(INT_MASK);
+        mask = mask | 0x1<<irq_num;
+        pokeRegisterDWord(INT_MASK,mask);  
+  
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.h
new file mode 100644
index 000000000000..2cee65bd199b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_intr.h
@@ -0,0 +1,116 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2008 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  intr.h --- SM750/SM718 DDK 
+*  This file contains the source code for the interrupt mechanism 
+* 
+*******************************************************************/
+#ifndef _INTR_H_
+#define _INTR_H_
+
+
+/*******************************************************************
+ * Interrupt implementation
+ * 
+ * This implementation is used for handling the interrupt.
+ *******************************************************************/
+
+typedef void (*PFNINTRHANDLER)(unsigned long);
+
+/*
+ * Register an interrupt handler function to an interrupt status
+ */ 
+short registerHandler(
+    void (*handler)(unsigned long status), 
+    unsigned long mask
+);
+
+/*
+ * Un-register a registered interrupt handler
+ */
+short unregisterHandler(
+    void (*handler)(unsigned long status)
+);
+
+/* 
+ * Hook a ISR function to the interrupt.
+ *
+ * This is a low level function providing one to one mapping of a single ISR to the interrupt line.
+ * It is a quick method to verify if a specific interrupt is working.
+ * However, it does not provide the structure of chaining several ISR together (use registerHandler() to chain ISR, instead).
+ *
+ * Note: 
+ *   1. If this function is used to hook up interrupt, unhookInterrupt() must be use to release the INT.
+ *      Don't use unregisterHandler() to release interrupt set up by this function.
+ *
+ * Output:
+ *      0   - Success
+ *      -1  - Out of memory
+ * 
+ */
+short hookInterrupt(
+    void (*handler)(void),      /* Interrupt function to be registered */
+    unsigned long mask          /* interrupt mask */
+);
+
+/* 
+ * Unregister a registered interrupt handler
+ * The matching call for singleIsrRegisterHandler()
+ *
+ * Output:
+ *      0   - Success
+ *      -1  - Handler is not found 
+ */
+short unhookInterrupt(
+    unsigned long mask          /* interrupt mask */
+);
+
+/*
+ * When hookInterrupt() is used to set up interrupt.
+ * ISR should call this function before exit.
+ *
+ */
+void notifyEndOfISR(void);
+
+
+void sb_IRQMask(int irq_num);
+void sb_IRQUnmask(int irq_num);
+
+#define SB_IRQ_VAL_TC3     	31
+#define SB_IRQ_VAL_TC2     	30
+#define SB_IRQ_VAL_TC1     	29
+#define SB_IRQ_VAL_TC0     	28
+#define SB_IRQ_VAL_USBH		25
+#define SB_IRQ_VAL_USBS		24
+#define SB_IRQ_VAL_I2S		23
+#define SB_IRQ_VAL_USART1  22
+#define SB_IRQ_VAL_USART0  21
+#define SB_IRQ_VAL_SSP1  	20
+#define SB_IRQ_VAL_SSP0		19
+#define SB_IRQ_VAL_I2C1		18
+#define SB_IRQ_VAL_I2C0		17	
+#define SB_IRQ_VAL_PWM		16
+#define SB_IRQ_VAL_GPIO6	15
+#define SB_IRQ_VAL_GPIO5	14
+#define SB_IRQ_VAL_GPIO4	13
+#define SB_IRQ_VAL_GPIO3	12
+#define SB_IRQ_VAL_GPIO2	11
+#define SB_IRQ_VAL_GPIO1	10
+#define SB_IRQ_VAL_GPIO0	9
+#define SB_IRQ_VAL_DMA		8
+#define SB_IRQ_VAL_CPU		7
+#define SB_IRQ_VAL_CSC		5
+#define SB_IRQ_VAL_DE			4
+#define SB_IRQ_VAL_C			3
+#define SB_IRQ_VAL_DC1		2
+#define SB_IRQ_VAL_DC0		1
+#define SB_IRQ_VAL_VGA		0
+
+
+
+
+#endif /* _INTR_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.c
new file mode 100644
index 000000000000..5a546f10d152
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.c
@@ -0,0 +1,1147 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  MODE.C --- SMI DDK 
+*  This file contains the source code for the mode table.
+* 
+*******************************************************************/
+
+#include "linux/string.h"
+#include <linux/delay.h>	
+
+
+#include "ddk768_reg.h"
+
+#include "ddk768_chip.h"
+#include "ddk768_clock.h"
+#include "ddk768_power.h"
+#include "ddk768_mode.h"
+
+#include "ddk768_help.h"
+
+extern int lvds_channel;
+
+extern int clk_phase;
+
+
+/* The valid signature of the user data pointer  for the setmode function. 
+   The following definition is ASCII representation of the word 'USER'
+ */
+#define MODE_USER_DATA_SIGNATURE            0x55534552
+
+/*
+ *  Default Timing parameter for some popular modes.
+ *  Note that the most timings in this table is made according to standard VESA 
+ *  parameters for the popular modes.
+ */
+static mode_parameter_t gDefaultModeParamTable[] =
+{
+/* 640 x 480  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */
+/* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */
+ { 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG},
+ { 840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG},
+ { 832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG},
+
+/* 720 x 480  [3:2] */
+ { 889, 720, 738,108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG},
+
+/* 720 x 540  [4:3] -- Not a popular mode */
+ { 886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG},
+
+/*720 x 576 [5:4] -- Not a popular mode*/
+ { 912, 720, 744, 96, POS, 597, 576, 580, 1, NEG, 32670000, 35820, 60, POS}, 
+
+/* 800 x 480  [5:3] -- Not a popular mode */
+ { 973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG},
+
+/* 800 x 600  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */
+/* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */
+ {1056, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG},
+ {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG},
+ {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG},
+
+/* 960 x 720  [4:3] -- Not a popular mode */
+ {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG},
+      
+/* 1024 x 600  [16:9] 1.7 */
+ {1313,1024,1064,104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG},
+     
+/* 1024 x 768  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */
+/* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */
+ {1344,1024,1048,136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG},
+ {1312,1024,1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG},
+ {1376,1024,1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG},
+  
+/* 1152 x 864  [4:3] -- Widescreen eXtended Graphics Array */
+/* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/
+ {1475,1152,1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG},
+ {1600,1152,1216,128, POS, 900, 864, 865, 3, POS,108000000, 67500, 75, NEG},
+ 
+/* 1280 x 720  [16:9] -- HDTV (WXGA) */
+ {1664,1280,1336,136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG},
+
+/* 1280 x 768  [5:3] -- Not a popular mode */
+ {1678,1280,1350,136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG},
+
+/* 1280 x 800  [8:5] -- Not a popular mode */
+ {1650,1280,1344,136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG},
+
+/* 1280 x 960  [4:3] */
+/* The first commented line below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/
+ {1800,1280,1376,112, POS,1000, 960, 961, 3, POS,108000000, 60000, 60, NEG},
+ {1728,1280,1344,160, POS,1011, 960, 961, 3, POS,148500000, 85938, 85, NEG},
+    
+/* 1280 x 1024 [5:4] */
+#if 1
+ /* GTF with C = 40, M = 600, J = 20, K = 128 */
+ {1712,1280,1360,136, NEG,1060,1024,1025, 3, POS,108883200, 63600, 60, NEG},
+ {1728,1280,1368,136, NEG,1069,1024,1025, 3, POS,138542400, 80175, 75, NEG},
+ {1744,1280,1376,136, NEG,1075,1024,1025, 3, POS,159358000, 91375, 85, NEG},
+#else
+ /* VESA Standard */
+ {1688,1280,1328,112, POS,1066,1024,1025, 3, POS,108000000, 63981, 60, NEG},
+ {1688,1280,1296,144, POS,1066,1024,1025, 3, POS,135000000, 79976, 75, NEG},
+ {1728,1280,1344,160, POS,1072,1024,1025, 3, POS,157500000, 91146, 85, NEG},
+#endif
+
+/* 1360 x 768 [16:9] */
+#if 1
+ /* GTF with C = 40, M = 600, J = 20, K = 128 */
+ //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG},
+ 
+ /* GTF with C = 30, M = 600, J = 20, K = 128 */
+ {1664,1360,1384,128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG},
+#else
+ /* Previous Calculation */
+ {1776,1360,1424,144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG},
+#endif
+ 
+/* 1366 x 768  [16:9] */
+ /* Previous Calculation  */
+ {1722,1366,1424,112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG},
+ 
+/* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore
+   temporarily disabled. */
+ //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG},
+ //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG},
+ 
+ /* Taken from the www.tinyvga.com */
+ {1880,1400,1488,152, NEG,1087,1050,1051, 3, POS,122610000, 65218, 60, NEG},
+ 
+/* 1440 x 900  [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */
+ {1904,1440,1520,152, NEG, 932, 900, 901, 3, POS,106470000, 55919, 60, NEG},
+
+/* 1440 x 960 [3:2] -- Not a popular mode */
+ {1920,1440,1528,152, POS, 994, 960, 961, 3, POS,114509000, 59640, 60, NEG},
+
+/* 1600 x 900 */
+{2128,1600,1664,192, POS,932,900,901, 3, POS,119000000, 56000, 60, NEG},
+
+
+/* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */
+ /* VESA */
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,162000000, 75000, 60, POS},
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,202500000, 93750, 75, POS},
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,229500000,106250, 85, POS},
+
+/* 
+ * The timing below is taken from the www.tinyvga.com/vga-timing.
+ * With the exception of 1920x1080.
+ */
+ 
+/* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ 
+/* The first commented timing might be used for DVI LCD Monitor timing. */
+/* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */
+ /* GTF with C = 30, M = 600, J = 20, K = 128 */
+ {2256,1680,1784,184, NEG,1087,1050,1051, 3, POS,147140000, 65222, 60, POS},
+/*
+ {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG},
+ {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG},
+*/
+ 
+/* 1792 x 1344 [4:3]. -- Not a popular mode */ 
+ {2448,1792,1920,200, NEG,1394,1344,1345, 3, POS,204800000, 83660, 60, NEG},
+ {2456,1792,1888,216, NEG,1417,1344,1345, 3, POS,261000000,106270, 75, NEG},
+ 
+/* 1856 x 1392 [4:3]. -- Not a popular mode 
+   The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency
+   where not all monitor can support it (including the developer monitor)
+ */
+ {2528,1856,1952,224, NEG,1439,1392,1393, 3, POS,218300000, 86353, 60, NEG},
+/* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/
+
+/* 1920 x 1080 [16:9]. This is a make-up value, need to be proven. 
+   The Pixel clock is calculated based on the maximum resolution of
+   "Single Link" DVI, which support a maximum 165MHz pixel clock.
+   The second values are taken from:
+   http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf
+ */
+/* {2560,1920,2048,208, NEG,1125,1080,1081, 3, POS,172800000, 67500, 60, NEG}, */
+ {2200,1920,2008, 44, NEG,1125,1080,1081, 3, POS,148500000, 67500, 60, POS},
+
+/* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */
+ {2592,1920,2048,208, NEG,1242,1200,1201, 3, POS,193160000, 74522, 60, NEG},
+
+/* 1920 x 1440 [4:3]. */
+/* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. 
+   The timing for 75 Hz is provided here if necessary to do testing. - Some underflow
+   has been noticed. */
+ {2600,1920,2048,208, NEG,1500,1440,1441, 3, POS,234000000, 90000, 60, NEG},
+/* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */
+
+/* 2560x1440 [16:9]. */
+/* 2K mode */
+ {2720,2560,2608,32, POS,1481,1440,1443, 5, NEG,241500000, 88000, 60, NEG},
+
+/* 3840 x 2160 (UHD) */
+ {4400,3840,4016,88, POS,2250,2160,2168, 10, POS,297000000, 67500, 30, NEG},
+
+
+/* End of table. */
+ { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+/*
+ *  Default Timing parameter for some popular modes.
+ *  Note that the most timings in this table is made according to standard VESA 
+ *  parameters for the popular modes.
+ */
+static mode_parameter_t gLVDSModeParamTable[] =
+{
+/* 640 x 480  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */
+/* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */
+ { 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG},
+ { 840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG},
+ { 832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG},
+
+/* 720 x 480  [3:2] */
+ { 889, 720, 738,108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG},
+
+/* 720 x 540  [4:3] -- Not a popular mode */
+ { 886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG},
+
+/*720 x 576 [5:4] -- Not a popular mode*/
+ { 912, 720, 744, 96, POS, 597, 576, 580, 1, NEG, 32670000, 35820, 60, POS}, 
+
+/* 800 x 480  [5:3] -- Not a popular mode */
+ { 973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG},
+
+/* 800 x 600  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */
+/* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */
+ {1056, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG},
+ {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG},
+ {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG},
+
+/* 960 x 720  [4:3] -- Not a popular mode */
+ {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG},
+      
+/* 1024 x 600  [16:9] 1.7 */
+ {1313,1024,1064,104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG},
+     
+/* 1024 x 768  [4:3] */
+/* The first 2 commented lines below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */
+/* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */
+ {1344,1024,1048,136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG},
+ {1312,1024,1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG},
+ {1376,1024,1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG},
+  
+/* 1152 x 864  [4:3] -- Widescreen eXtended Graphics Array */
+/* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/
+ {1475,1152,1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG},
+ {1600,1152,1216,128, POS, 900, 864, 865, 3, POS,108000000, 67500, 75, NEG},
+ 
+/* 1280 x 720  [16:9] -- HDTV (WXGA) */
+ {1664,1280,1336,136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG},
+
+/* 1280 x 768  [5:3] -- Not a popular mode */
+ {1678,1280,1350,136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG},
+
+/* 1280 x 800  [8:5] -- Not a popular mode */
+ {1650,1280,1344,136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG},
+
+/* 1280 x 960  [4:3] */
+/* The first commented line below are taken from SM502, the rest timing are
+   taken from the VESA Monitor Timing Standard */
+/* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/
+ {1800,1280,1376,112, POS,1000, 960, 961, 3, POS,108000000, 60000, 60, NEG},
+ {1728,1280,1344,160, POS,1011, 960, 961, 3, POS,148500000, 85938, 85, NEG},
+    
+/* 1280 x 1024 [5:4] */
+#if 1
+ /* GTF with C = 40, M = 600, J = 20, K = 128 */
+ {1712,1280,1360,136, NEG,1060,1024,1025, 3, POS,108883200, 63600, 60, NEG},
+ {1728,1280,1368,136, NEG,1069,1024,1025, 3, POS,138542400, 80175, 75, NEG},
+ {1744,1280,1376,136, NEG,1075,1024,1025, 3, POS,159358000, 91375, 85, NEG},
+#else
+ /* VESA Standard */
+ {1688,1280,1328,112, POS,1066,1024,1025, 3, POS,108000000, 63981, 60, NEG},
+ {1688,1280,1296,144, POS,1066,1024,1025, 3, POS,135000000, 79976, 75, NEG},
+ {1728,1280,1344,160, POS,1072,1024,1025, 3, POS,157500000, 91146, 85, NEG},
+#endif
+
+/* 1360 x 768 [16:9] */
+#if 1
+ /* GTF with C = 40, M = 600, J = 20, K = 128 */
+ //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG},
+ 
+ /* GTF with C = 30, M = 600, J = 20, K = 128 */
+ {1664,1360,1384,128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG},
+#else
+ /* Previous Calculation */
+ {1776,1360,1424,144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG},
+#endif
+ 
+/* 1366 x 768  [16:9] */
+ /* Previous Calculation  */
+ {1722,1366,1424,112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG},
+ 
+/* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore
+   temporarily disabled. */
+ //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG},
+ //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG},
+ 
+ /* Taken from the www.tinyvga.com */
+ {1880,1400,1488,152, NEG,1087,1050,1051, 3, POS,122610000, 65218, 60, NEG},
+ 
+/* 1440 x 900  [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */
+ {1904,1440,1520,152, NEG, 932, 900, 901, 3, POS,106470000, 55919, 60, NEG},
+
+/* 1440 x 960 [3:2] -- Not a popular mode */
+ {1920,1440,1528,152, POS, 994, 960, 961, 3, POS,114509000, 59640, 60, NEG},
+
+/* 1600 x 900 */
+{2128,1600,1664,192, POS,932,900,901, 3, POS,119000000, 56000, 60, NEG},
+
+
+/* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */
+ /* VESA */
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,162000000, 75000, 60, POS},
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,202500000, 93750, 75, POS},
+ {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,229500000,106250, 85, POS},
+
+/* 
+ * The timing below is taken from the www.tinyvga.com/vga-timing.
+ * With the exception of 1920x1080.
+ */
+ 
+/* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ 
+/* The first commented timing might be used for DVI LCD Monitor timing. */
+/* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */
+ /* GTF with C = 30, M = 600, J = 20, K = 128 */
+ {2256,1680,1784,184, NEG,1087,1050,1051, 3, POS,147140000, 65222, 60, POS},
+/*
+ {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG},
+ {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG},
+*/
+ 
+/* 1792 x 1344 [4:3]. -- Not a popular mode */ 
+ {2448,1792,1920,200, NEG,1394,1344,1345, 3, POS,204800000, 83660, 60, NEG},
+ {2456,1792,1888,216, NEG,1417,1344,1345, 3, POS,261000000,106270, 75, NEG},
+ 
+/* 1856 x 1392 [4:3]. -- Not a popular mode 
+   The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency
+   where not all monitor can support it (including the developer monitor)
+ */
+ {2528,1856,1952,224, NEG,1439,1392,1393, 3, POS,218300000, 86353, 60, NEG},
+/* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/
+
+/* 1920 x 1080 [16:9]. This is a make-up value, need to be proven. 
+   The Pixel clock is calculated based on the maximum resolution of
+   "Single Link" DVI, which support a maximum 165MHz pixel clock.
+   The second values are taken from:
+   http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf
+ */
+/* {2560,1920,2048,208, NEG,1125,1080,1081, 3, POS,172800000, 67500, 60, NEG}, */
+ {2200,1920,2008, 44, NEG,1125,1080,1081, 3, POS,148500000, 67500, 60, POS},
+
+/* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */
+ {2592,1920,2048,208, NEG,1242,1200,1201, 3, POS,193160000, 74522, 60, NEG},
+
+/* 1920 x 1440 [4:3]. */
+/* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. 
+   The timing for 75 Hz is provided here if necessary to do testing. - Some underflow
+   has been noticed. */
+ {2600,1920,2048,208, NEG,1500,1440,1441, 3, POS,234000000, 90000, 60, NEG},
+/* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */
+
+/* 2560x1440 [16:9]. */
+/* 2K mode */
+ {2720,2560,2608,32, POS,1481,1440,1443, 5, NEG,241500000, 88000, 60, NEG},
+
+/* 3840 x 2160 (UHD) */
+ {4400,3840,4016,88, POS,2250,2160,2168, 10, POS,297000000, 67500, 30, NEG},
+
+
+/* End of table. */
+ { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+
+static mode_parameter_t gChannel0ModeParamTable[MAX_MODE_TABLE_ENTRIES] =
+{
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+static mode_parameter_t gChannel1ModeParamTable[MAX_MODE_TABLE_ENTRIES] =
+{
+    /* End of table */
+     { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG},
+};
+
+/* Static variable to store the mode information. */
+static mode_parameter_t gChannel0CurrentModeParam;
+static mode_parameter_t gChannel1CurrentModeParam;
+
+
+void debug_mode_param(mode_parameter_t *modeParam)
+{
+    printk(KERN_INFO "%lu %lu %lu %lu %s %lu %lu %lu %lu %s %lu %lu %lu %s\n",
+        modeParam->horizontal_total, modeParam->horizontal_display_end,
+        modeParam->horizontal_sync_start, modeParam->horizontal_sync_width,
+        modeParam->horizontal_sync_polarity == POS ? "POS" : "NEG",
+        modeParam->vertical_total, modeParam->vertical_display_end,
+        modeParam->vertical_sync_start, modeParam->vertical_sync_height,
+        modeParam->vertical_sync_polarity == POS ? "POS" : "NEG",
+        modeParam->pixel_clock, modeParam->horizontal_frequency,
+        modeParam->vertical_frequency,
+        modeParam->clock_phase_polarity == POS ? "POS" : "NEG");
+}
+
+
+
+/*
+ *  ddk768_getUserDataSignature
+ *      This function gets the user data mode signature
+ *
+ *  Output:
+ *      The signature to be filled in the user_data_mode_t structure to be considered
+ *      a valid structure.
+ */
+unsigned long ddk768_getUserDataSignature()
+{
+    return MODE_USER_DATA_SIGNATURE;
+}
+
+/*
+ *  compareModeParam
+ *      This function compares two mode parameters
+ *
+ *  Input:
+ *      pModeParam1 - Pointer to the first mode parameter to be compared
+ *      pModeParam2 - Pointer to the second mode parameter to be compared
+ *
+ *  Output:
+ *      0   - Identical mode
+ *     -1   - Mode is not identical
+ */
+long compareModeParam(
+    mode_parameter_t *pModeParam1,
+    mode_parameter_t *pModeParam2
+)
+{
+    if ((pModeParam1 != (mode_parameter_t *)0) &&
+        (pModeParam2 != (mode_parameter_t *)0))
+    {
+        if (memcmp((void *)pModeParam1, (void *)pModeParam2, sizeof(mode_parameter_t)) == 0)
+            return 0;
+    }
+        
+    return (-1);
+}
+
+/*
+ *  getDuplicateModeIndex
+ *      This function retrieves the index of dupicate modes, but having different timing.
+ *
+ *  Input:
+ *      dispCtrl    - Display Control where the mode table belongs to.
+ *      pModeParam  - The mode parameters which index to be checked.
+ *
+ *  Output:
+ *      The index of the given parameters among the duplicate modes.
+ *          0 means that the mode param is the first mode encountered in the table
+ *          1 means that the mode param is the second mode encountered in the table
+ *          etc...
+ */
+unsigned short getDuplicateModeIndex(
+    disp_control_t dispCtrl,
+    mode_parameter_t *pModeParam
+)
+{
+    unsigned short index, modeIndex;
+    mode_parameter_t *pModeTable;
+    
+    /* Get the mode table */
+    pModeTable = ddk768_getStockModeParamTableEx(dispCtrl);
+    
+    /* Search the current mode */
+    modeIndex = 0;
+    index = 0;
+    while (pModeTable[modeIndex].pixel_clock != 0)
+    {
+        if ((pModeTable[modeIndex].horizontal_display_end == pModeParam->horizontal_display_end) &&
+            (pModeTable[modeIndex].vertical_display_end == pModeParam->vertical_display_end) &&
+            (pModeTable[modeIndex].vertical_frequency == pModeParam->vertical_frequency))
+        {
+            /* Check if this is the same/identical mode param. */
+            if (compareModeParam(&pModeTable[modeIndex], pModeParam) == 0)
+                break;
+                
+            /* Increment the index */
+            index++;
+        }
+        modeIndex++;
+    }
+    
+    return index;
+}
+
+/*
+ *  ddk768_findModeParamFromTable
+ *      This function locates the requested mode in the given parameter table
+ *
+ *  Input:
+ *      width           - Mode width
+ *      height          - Mode height
+ *      refresh_rate    - Mode refresh rate
+ *      index           - Index that is used for multiple search of the same mode 
+ *                        that have the same width, height, and refresh rate, 
+ *                        but have different timing parameters.
+ *
+ *  Output:
+ *      Success: return a pointer to the mode_parameter_t entry.
+ *      Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findModeParamFromTable(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index,
+    mode_parameter_t *pModeTable
+)
+{
+    unsigned short modeIndex = 0, tempIndex = 0;
+    
+    /* Walk the entire mode table. */    
+    while (pModeTable[modeIndex].pixel_clock != 0)
+    {
+        if (((width == (unsigned long)(-1)) || (pModeTable[modeIndex].horizontal_display_end == width)) &&
+            ((height == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_display_end == height)) &&
+            ((refresh_rate == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_frequency == refresh_rate)))
+        {
+            if (tempIndex < index)
+                tempIndex++;
+            else
+                return (&pModeTable[modeIndex]);
+        }
+        
+        /* Next entry */
+        modeIndex++;
+    }
+
+    /* No match, return NULL pointer */
+    return((mode_parameter_t *)0);
+}
+
+/*
+ *  Locate in-stock parameter table for the requested mode.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findModeParam(
+    disp_control_t dispCtrl,
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index
+)
+{
+    return ddk768_findModeParamFromTable(width, height, refresh_rate, index, ddk768_getStockModeParamTableEx(dispCtrl));
+}
+
+/*
+ *  Use the
+ *  Locate timing parameter for the requested mode from the default mode table.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findVesaModeParam(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate
+)
+{
+    return ddk768_findModeParamFromTable(width, height, refresh_rate, 0, gDefaultModeParamTable);
+}
+
+/*
+ * (Obsolete) 
+ * Return a point to the gDefaultModeParamTable.
+ * Function in other files used this to get the mode table pointer.
+ */
+mode_parameter_t *ddk768_getStockModeParamTable()
+{
+    return(gDefaultModeParamTable);
+}
+
+/*
+ * (Obsolete)
+ * Return the size of the Stock Mode Param Table
+ */
+unsigned long ddk768_getStockModeParamTableSize()
+{
+    return (sizeof(gDefaultModeParamTable) / sizeof(mode_parameter_t) - 1);
+}
+
+/* 
+ *  ddk768_getStockModeParamTableEx
+ *      This function gets the mode parameters table associated to the
+ *      display control (CHANNEL0_CTRL or SECONDAR_CTRL).
+ *
+ *  Input:
+ *      dispCtrl    - Display Control of the mode table that is associated to.
+ *
+ *  Output:
+ *      Pointer to the mode table
+ */
+mode_parameter_t *ddk768_getStockModeParamTableEx(
+    disp_control_t dispCtrl
+)
+{
+    mode_parameter_t *pModeTable;
+    
+    if (dispCtrl == CHANNEL0_CTRL){
+        pModeTable = (mode_parameter_t *)gChannel0ModeParamTable;
+    }else{
+        pModeTable = (mode_parameter_t *)gChannel1ModeParamTable;
+    }
+
+	if(lvds_channel)
+	{
+		pModeTable = (mode_parameter_t *)gLVDSModeParamTable;
+	}	
+
+	/* Check if the table exist by checking the first entry. 
+       If it doesn't, then use the default mode table. */
+
+    if (pModeTable->pixel_clock == 0)
+    {
+        pModeTable = ddk768_getStockModeParamTable();
+    }
+        
+    return (pModeTable);
+}
+
+/*
+ *  ddk768_getStockModeParamTableSizeEx
+ *      This function gets the size of the mode parameter table associated with
+ *      specific display control
+ *
+ *  Input:
+ *      dispCtrl    - Display control of the mode param table that is associated to.
+ *
+ *  Output:
+ *      Size of the requeted mode param table.
+ */
+unsigned long ddk768_getStockModeParamTableSizeEx(
+    disp_control_t dispCtrl
+)
+{
+    unsigned long tableSize;
+    mode_parameter_t *pModeTable;
+    
+    /* Get the mode table */
+    pModeTable = ddk768_getStockModeParamTableEx(dispCtrl);
+    
+    /* Calculate the table size by finding the end of table entry indicated by all zeroes. */    
+    tableSize = 0;
+    while (pModeTable[tableSize].pixel_clock != 0)
+        tableSize++;
+        
+    return tableSize;
+}
+
+/*
+ *  getMaximumModeEntries
+ *      This function gets the maximum entries that can be stored in the mode table.
+ *
+ *  Output:
+ *      Total number of maximum entries
+ */
+unsigned long getMaximumModeEntries()
+{
+    return MAX_MODE_TABLE_ENTRIES;
+}
+
+/* 
+ * This function returns the current mode.
+ */
+mode_parameter_t ddk768_getCurrentModeParam(
+    disp_control_t dispCtrl
+)
+{
+    if (dispCtrl == CHANNEL0_CTRL)
+        return gChannel0CurrentModeParam;
+    else
+        return gChannel1CurrentModeParam;
+}
+
+/*
+ *  addTiming
+ *      This function adds the SM750 mode parameter timing to the specified mode table
+ *
+ *  Input:
+ *      dispCtrl        - Display control where the mode will be associated to
+ *      pNewModeList    - Pointer to a list table of SM750 mode parameter to be added 
+ *                        to the current specified display control mode table.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long addTiming(
+    disp_control_t dispCtrl,
+    mode_parameter_t *pNewModeList,
+    unsigned long totalList,
+    unsigned char clearTable
+)
+{
+    mode_parameter_t *pModeParamTable;
+    unsigned char index;
+    long returnValue = 0;
+    
+    /* Get the correct table */
+    if (dispCtrl == CHANNEL0_CTRL)
+        pModeParamTable = (mode_parameter_t *)gChannel0ModeParamTable;
+    else
+        pModeParamTable = (mode_parameter_t *)gChannel1ModeParamTable;
+    
+    if (clearTable == 0)
+    {    
+        /* Find the last index where the timing will be added to */
+        index = 0;
+        while(pModeParamTable[index].pixel_clock != 0)
+            index++;
+    }
+    else
+    {
+        /* Clear and reset the mode table first */
+        for (index = 0; index < MAX_MODE_TABLE_ENTRIES; index++)
+            memset((void*)&pModeParamTable[index], 0, sizeof(mode_parameter_t));
+            
+        /* Reset index */
+        index = 0;
+    }
+        
+    /* Update the number of modes those can be added to the current table. */
+    if (totalList > (unsigned long)(MAX_MODE_TABLE_ENTRIES - index))
+        totalList = (unsigned long)(MAX_MODE_TABLE_ENTRIES - index);
+    else
+        returnValue = (-1);
+    
+    /* Check if totalList is 0, which means that the table is full. */        
+    if (totalList == 0)
+        returnValue = (-1);
+        
+    /* Add the list of modes provided by the caller */
+    while (totalList--)
+    {
+        memcpy((void *)&pModeParamTable[index], (void *)&pNewModeList[index], sizeof(mode_parameter_t));
+        index++;
+    }
+        
+    return returnValue;
+}
+
+/*
+ *	This function sets the display base address
+ *
+ *	Input:
+ *		dispControl		- display control of which base address to be set.
+ *		ulBaseAddress	- Base Address value to be set.
+ */
+void ddk768_setDisplayBaseAddress(
+	disp_control_t dispControl,
+	unsigned long ulBaseAddress
+)
+{
+    unsigned long regFB;
+
+    regFB = (dispControl == CHANNEL0_CTRL) ? FB_ADDRESS : (FB_ADDRESS+CHANNEL_OFFSET);
+
+		/* Frame buffer base for this mode */
+	pokeRegisterDWord(regFB,
+          FIELD_SET(0, FB_ADDRESS, STATUS, PENDING)
+        | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, ulBaseAddress));
+}
+
+/*
+ *    This function checks if change of "display base address" has effective.
+ *    Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change.
+ *    HW resets pending bit when it starts to use the new address.
+ *
+ *    Input:
+ *        dispControl        - display control of which display status to be retrieved.
+ *
+ *  Output:
+ *      1   - Display is pending
+ *      0   - Display is not pending
+ */
+long isDisplayBasePending(
+    disp_control_t dispControl
+)
+{
+    unsigned long regFB;
+
+    regFB = (dispControl == CHANNEL0_CTRL) ? FB_ADDRESS : (FB_ADDRESS+CHANNEL_OFFSET);
+
+    if (FIELD_GET(peekRegisterDWord(regFB), FB_ADDRESS, STATUS) == FB_ADDRESS_STATUS_PENDING)
+        return 1;
+
+    return (0);
+}
+
+
+/* 
+ * Program the hardware for a specific video mode
+ *
+ * return:
+ *         0 = success
+ *        -1 = fail.
+ */
+long ddk768_programModeRegisters(
+logicalMode_t *pLogicalMode, 
+mode_parameter_t *pModeParam,   /* mode information about pixel clock, horizontal total, etc. */
+pll_value_t *pPLL               /* Pre-calculated values for the PLL */
+)
+{
+    unsigned long ulTmpValue;
+    unsigned long paletteRam;
+    unsigned long offset, pllReg;
+    unsigned long hdmi_channel;
+	unsigned long regvalue;
+#if 0 // print UHD register setting for debug.
+    if (pLogicalMode->x == 3840)
+        return(printModeRegisters(pLogicalMode, pModeParam, pPLL));
+#endif
+
+        /*  Make sure normal display channel is used, not VGA channel */
+        pokeRegisterDWord(VGA_CONFIGURATION,
+                          FIELD_SET(0, VGA_CONFIGURATION, PLL, PANEL) | FIELD_SET(0, VGA_CONFIGURATION, MODE, GRAPHIC));
+
+    offset = (pLogicalMode->dispCtrl==CHANNEL0_CTRL)? 0 : CHANNEL_OFFSET;
+	pllReg = (pLogicalMode->dispCtrl==CHANNEL0_CTRL)? VCLK0_PLL : VCLK1_PLL;
+
+
+	/* Turn off PLL at first. */
+    regvalue = peekRegisterByte(pllReg);
+    regvalue |= (1 << 0);
+    pokeRegisterDWord(pllReg, regvalue);
+    /* Poke setting. */
+    regvalue = ddk768_formatPllReg(pPLL);
+    regvalue |= (1 << 0);
+    pokeRegisterDWord(pllReg, regvalue);
+    /* Delay 100 us and turn on PLL. */
+    udelay(100);
+    regvalue = ddk768_formatPllReg(pPLL);
+    regvalue &= ~(1 << 0);
+    pokeRegisterDWord(pllReg, regvalue);
+  
+    
+#if 0
+    /* Frame buffer base */
+    pokeRegisterDWord((FB_ADDRESS+offset),
+          FIELD_SET(0, FB_ADDRESS, STATUS, PENDING)
+        | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, pLogicalMode->baseAddress));
+
+#endif
+
+
+    /* Pitch value (Hardware people calls it Offset) */
+    pokeRegisterDWord((FB_WIDTH+offset),
+          FIELD_VALUE(0, FB_WIDTH, WIDTH, pLogicalMode->pitch));
+
+    pokeRegisterDWord((HORIZONTAL_TOTAL+offset),
+          FIELD_VALUE(0, HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
+        | FIELD_VALUE(0, HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
+
+    pokeRegisterDWord((HORIZONTAL_SYNC+offset),
+          FIELD_VALUE(0, HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
+        | FIELD_VALUE(0, HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
+
+    pokeRegisterDWord((VERTICAL_TOTAL+offset),
+          FIELD_VALUE(0, VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
+        | FIELD_VALUE(0, VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
+
+    pokeRegisterDWord((VERTICAL_SYNC+offset),
+          FIELD_VALUE(0, VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
+        | FIELD_VALUE(0, VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
+
+
+    
+    hdmi_channel = FIELD_GET(peekRegisterDWord(DISPLAY_CTRL+offset),
+                                   DISPLAY_CTRL,
+                                   HDMI_SELECT);    
+
+    /* Set control register value */
+    ulTmpValue =       
+        (pModeParam->vertical_sync_polarity == POS
+        ? FIELD_SET(0, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH)
+        : FIELD_SET(0, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW))
+      | (pModeParam->horizontal_sync_polarity == POS
+        ? FIELD_SET(0, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH)
+        : FIELD_SET(0, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW))
+      | (pModeParam->clock_phase_polarity== POS
+        ? FIELD_SET(0, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH)
+        : FIELD_SET(0, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW))
+      | FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED)
+      | FIELD_SET(0, DISPLAY_CTRL, DIRECTION, INPUT)
+      | FIELD_SET(0, DISPLAY_CTRL, TIMING, ENABLE)
+      | FIELD_SET(0, DISPLAY_CTRL, PLANE, ENABLE) 
+      | (pLogicalMode->bpp == 8
+        ? FIELD_SET(0, DISPLAY_CTRL, FORMAT, 8)
+        : (pLogicalMode->bpp == 16
+        ? FIELD_SET(0, DISPLAY_CTRL, FORMAT, 16)
+        : FIELD_SET(0, DISPLAY_CTRL, FORMAT, 32)));
+
+	if(clk_phase == 0)
+		ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW);
+	if(clk_phase == 1)
+		ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH);
+
+	
+	if( hdmi_channel == DISPLAY_CTRL_HDMI_SELECT_CHANNEL0)
+		 ulTmpValue= FIELD_SET(ulTmpValue,DISPLAY_CTRL, HDMI_SELECT, CHANNEL0);
+	else
+		 ulTmpValue= FIELD_SET(ulTmpValue,DISPLAY_CTRL, HDMI_SELECT, CHANNEL1);
+
+
+    pokeRegisterDWord((DISPLAY_CTRL+offset), ulTmpValue);
+
+    /* Palette RAM. */
+    paletteRam = PALETTE_RAM + offset;
+    
+    /* Save the current mode param */
+    if (pLogicalMode->dispCtrl == CHANNEL0_CTRL)
+        gChannel0CurrentModeParam = *pModeParam;
+    else
+        gChannel1CurrentModeParam = *pModeParam;
+
+    /* In case of 8-bpp, fill palette */
+    if (pLogicalMode->bpp==8)
+    {
+        /* Start with RGB = 0,0,0. */
+        unsigned char red = 0, green = 0, blue = 0;
+        unsigned long gray = 0;
+        for (offset = 0; offset < 256 * 4; offset += 4)
+        {
+            /* Store current RGB value. */
+            pokeRegisterDWord(paletteRam + offset, gray
+                                ? RGB((gray + 50) / 100,
+                                      (gray + 50) / 100,
+                                      (gray + 50) / 100)
+                                : RGB(red, green, blue));
+
+            if (gray)
+            {
+                /* Walk through grays (40 in total). */
+                gray += 654;
+            }
+
+            else
+            {
+                /* Walk through colors (6 per base color). */
+                if (blue != 255)
+                {
+                    blue += 51;
+                }
+                else if (green != 255)
+                {
+                    blue = 0;
+                    green += 51;
+                }
+                else if (red != 255)
+                {
+                    green = blue = 0;
+                    red += 51;
+                }
+                else
+                {
+                    gray = 1;
+                }
+            }
+        }
+    }
+    /* For 16- and 32-bpp,  fill palette with gamma values. */
+    else
+    {
+        /* Start with RGB = 0,0,0. */
+        ulTmpValue = 0x000000;
+        for (offset = 0; offset < 256 * 4; offset += 4)
+        {
+            pokeRegisterDWord(paletteRam + offset, ulTmpValue);
+
+            /* Advance RGB by 1,1,1. */
+            ulTmpValue += 0x010101;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution and bpp.
+ *     2) A user defined parameter table for the mode.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined Vesa parameter table (gDefaultModeParamTable) does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setCustomMode(
+    logicalMode_t *pLogicalMode, 
+    mode_parameter_t *pUserModeParam
+)
+{
+    //mode_parameter_t pModeParam; /* physical parameters for the mode */
+    pll_value_t pll;
+    unsigned long ulActualPixelClk;
+
+    /*
+     * Minimum check on mode base address.
+     * At least it shouldn't be bigger than the size of frame buffer.
+     */
+    if (ddk768_getFrameBufSize() <= pLogicalMode->baseAddress)
+        return -1;
+	
+    /*
+     * Set up PLL, a structure to hold the value to be set in clocks.
+     */
+	if (ddk768_getCrystalType())
+		pll.inputFreq = (24576000/2);
+	else
+		pll.inputFreq = (24000000/2);
+	
+    /* 
+     * Call calcPllValue() to fill up the other fields for PLL structure.
+     * Sometime, the chip cannot set up the exact clock required by User.
+     * Return value from calcPllValue() gives the actual possible pixel clock.
+     */
+    ulActualPixelClk = ddk768_calcPllValue(pUserModeParam->pixel_clock, &pll);
+  
+
+
+
+    /* If calling function don't have a preferred pitch value, 
+       work out a 16 byte aligned pitch value.
+    */
+    if (pLogicalMode->pitch == 0)
+    {
+        /* 
+         * Pitch value calculation in Bytes.
+         * Usually, it is (screen width) * (byte per pixel).
+         * However, there are cases that screen width is not 16 pixel aligned, which is
+         * a requirement for some OS and the hardware itself.
+         * For standard 4:3 resolutions: 320, 640, 800, 1024 and 1280, they are all
+         * 16 pixel aligned and pitch is simply (screen width) * (byte per pixel).
+         *   
+         * However, 1366 resolution, for example, has to be adjusted for 16 pixel aligned.
+         */
+        pLogicalMode->pitch = PITCH(pLogicalMode->x, pLogicalMode->bpp);
+    }
+
+    /* Program the hardware to set up the mode. */
+    return( ddk768_programModeRegisters( 
+            pLogicalMode, 
+            pUserModeParam,
+            &pll));
+}
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp 
+ * The main difference between setMode and setModeEx userData.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setModeEx(
+    logicalMode_t *pLogicalMode
+)
+{
+    mode_parameter_t *pModeParam;       /* physical parameters for the mode */
+    unsigned short index = 0;
+    userData_t *pUserData;
+
+    /*
+     * Check the validity of the userData pointer and translate the information as necessary
+     */
+    pUserData = (userData_t *)pLogicalMode->userData;
+    if ((pUserData != (userData_t *)0) &&
+        (pUserData->signature == ddk768_getUserDataSignature()) &&
+        (pUserData->size == sizeof(userData_t)))
+    {
+        /* Interpret the userData information */
+        if (pUserData->paramList.size == sizeof(userDataParam_t))
+        {
+            if (pUserData->paramList.modeInfoID == MODE_INFO_INDEX)
+                index = pUserData->paramList.paramInfo.index;
+        }
+    }
+    
+    /* 
+     * Check if we already have physical timing parameter for this mode.
+     */
+    pModeParam = ddk768_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, index);
+    if (pModeParam == (mode_parameter_t *)0)
+        return -1;
+
+    return(ddk768_setCustomMode(pLogicalMode, pModeParam));
+}
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp.
+ * If there is no special parameters, use this function.
+ * If there are special parameters, use setModeEx.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setMode(
+    logicalMode_t *pLogicalMode
+)
+{
+    pLogicalMode->userData = (void *)0;
+
+    /* Call the setModeEx to set the mode. */
+    return ddk768_setModeEx(pLogicalMode);
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.h
new file mode 100644
index 000000000000..6f9af3694084
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_mode.h
@@ -0,0 +1,381 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  MODE.H --- SMI DDK 
+*  This file contains the definitions for the mode tables.
+* 
+*******************************************************************/
+#ifndef _DDK768_MODE_H_
+#define _DDK768_MODE_H_
+
+/* Maximum parameters those can be saved in the mode table. */
+#define MAX_MODE_TABLE_ENTRIES              60
+#define PITCH(width, bpp)               (((width) * (bpp) / 8 + 15) & ~15)
+
+/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the
+   modeext to compare timing will not work. */
+#pragma pack(1)
+
+typedef enum _spolarity_t
+{
+    POS, /* positive */
+    NEG, /* negative */
+}
+spolarity_t;
+
+typedef struct _mode_parameter_t
+{
+    /* Horizontal timing. */
+    unsigned long horizontal_total;
+    unsigned long horizontal_display_end;
+    unsigned long horizontal_sync_start;
+    unsigned long horizontal_sync_width;
+    spolarity_t horizontal_sync_polarity;
+
+    /* Vertical timing. */
+    unsigned long vertical_total;
+    unsigned long vertical_display_end;
+    unsigned long vertical_sync_start;
+    unsigned long vertical_sync_height;
+    spolarity_t vertical_sync_polarity;
+
+    /* Refresh timing. */
+    unsigned long pixel_clock;
+    unsigned long horizontal_frequency;
+    unsigned long vertical_frequency;
+    
+    /* Clock Phase. This clock phase only applies to Panel. */
+    spolarity_t clock_phase_polarity;
+}
+mode_parameter_t;
+
+typedef enum _disp_control_t
+{
+    CHANNEL0_CTRL = 0,
+    CHANNEL1_CTRL = 1,
+}
+disp_control_t;
+
+typedef struct _logicalMode_t
+{
+    unsigned long x;            /* X resolution */
+    unsigned long y;            /* Y resolution */
+    unsigned long bpp;          /* Bits per pixel */
+    unsigned long hz;           /* Refresh rate */
+
+    unsigned long baseAddress;  /* Offset from beginning of frame buffer.
+                                   It is used to control the starting location of a mode.
+                                   Calling function must initialize this field.
+                                 */
+
+    unsigned long pitch;        /* Mode pitch in byte.
+                                   If initialized to 0, setMode function will set
+                                   up this field.
+                                   If not zero, setMode function will use this value.
+                                 */
+	unsigned long  valid_edid;
+    disp_control_t dispCtrl;    /* CHANNEL1 or CHANNEL0 display control channel */
+    
+    /* These two parameters are used in the setModeEx. */
+    unsigned long xLCD;         /* Panel width */
+    unsigned long yLCD;         /* Panel height */
+    
+    void *userData;             /* Not used now, set it to 0 (for future used only) */
+
+}
+logicalMode_t;
+
+/*
+ * ID of the modeInfoID used in the userDataParam_t
+ */
+#define MODE_INFO_INDEX         0x01
+
+typedef struct _userDataParam_t
+{
+    unsigned long size;         /* Size of this parameter */
+    unsigned char modeInfoID;   /* Mode information ID */
+    
+    /* As the modeInfoID might be expanded in the future to support more stuffs as necessary, 
+       the following parameter list might be expanded in the future. */
+    union
+    {
+        unsigned char index;    /* The index of the mode timing of the given resolution:
+                                        0   - The first mode timing found in the table
+                                        1   - The second mode timing found in the table
+                                        etc...
+                                 */
+        /* Add more user data information parameters here as necessary. */
+    } paramInfo;
+} userDataParam_t;
+
+/* 
+ * Structure that is used as userData pointer in the logicalMode_t 
+ */
+typedef struct _userData_t
+{
+    unsigned long signature;    /* Signature of the userData pointer. 
+                                   It has to be filled with user data Signature to be a valid
+                                   structure pointer. The signature can be obtained by
+                                   calling ddk768_getUserDataSignature function.
+                                 */
+    unsigned long size;         /* Size of this data structure. */
+    userDataParam_t paramList;  /* List of parameters those are associated with this userData 
+                                   Currently, only one modeInfoID is supported. Later on, when
+                                   the ID is expanded, then the paramList might be expanded
+                                   as an array. */
+} 
+userData_t;
+
+/* Restore alignment */
+#pragma pack()
+
+/*
+ *  ddk768_getUserDataSignature
+ *      This function gets the user data mode signature
+ *
+ *  Output:
+ *      The signature to be filled in the user_data_mode_t structure to be considered
+ *      a valid structure.
+ */
+unsigned long ddk768_getUserDataSignature(void);
+
+/*
+ *  compareModeParam
+ *      This function compares two mode parameters
+ *
+ *  Input:
+ *      pModeParam1 - Pointer to the first mode parameter to be compared
+ *      pModeParam2 - Pointer to the second mode parameter to be compared
+ *
+ *  Output:
+ *      0   - Identical mode
+ *     -1   - Mode is not identical
+ */
+long compareModeParam(
+    mode_parameter_t *pModeParam1,
+    mode_parameter_t *pModeParam2
+);
+
+/*
+ *  getDuplicateModeIndex
+ *      This function retrieves the index of dupicate modes, but having different timing.
+ *
+ *  Input:
+ *      dispCtrl    - Display Control where the mode table belongs to.
+ *      pModeParam  - The mode parameters which index to be checked.
+ *
+ *  Output:
+ *      The index of the given parameters among the duplicate modes.
+ *          0 means that the mode param is the first mode encountered in the table
+ *          1 means that the mode param is the second mode encountered in the table
+ *          etc...
+ */
+unsigned short getDuplicateModeIndex(
+    disp_control_t dispCtrl,
+    mode_parameter_t *pModeParam
+);
+
+/*
+ *  ddk768_findModeParamFromTable
+ *      This function locates the requested mode in the given parameter table
+ *
+ *  Input:
+ *      width           - Mode width
+ *      height          - Mode height
+ *      refresh_rate    - Mode refresh rate
+ *      index           - Index that is used for multiple search of the same mode 
+ *                        that have the same width, height, and refresh rate, 
+ *                        but have different timing parameters.
+ *
+ *  Output:
+ *      Success: return a pointer to the mode_parameter_t entry.
+ *      Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findModeParamFromTable(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index,
+    mode_parameter_t *pModeTable
+);
+
+/*
+ *  Locate in-stock parameter table for the requested mode.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findModeParam(
+    disp_control_t dispCtrl,
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate,
+    unsigned short index
+);
+
+/*
+ *  Use the
+ *  Locate timing parameter for the requested mode from the default mode table.
+ *  Success: return a pointer to the mode_parameter_t entry.
+ *  Fail: a NULL pointer.
+ */
+mode_parameter_t *ddk768_findVesaModeParam(
+    unsigned long width, 
+    unsigned long height, 
+    unsigned long refresh_rate
+);
+
+/*
+ * Return a point to the gDefaultModeParamTable.
+ * Function in other files used this to get the mode table pointer.
+ */
+mode_parameter_t *ddk768_getStockModeParamTable(void);
+
+/*
+ * Return the size of the Stock Mode Param Table
+ */
+unsigned long ddk768_getStockModeParamTableSize(void);
+
+/* 
+ *  ddk768_getStockModeParamTableEx
+ *      This function gets the mode parameters table associated to the
+ *      display control (CHANNEL0_CTRL or SECONDAR_CTRL).
+ *
+ *  Input:
+ *      dispCtrl    - Display Control of the mode table that is associated to.
+ *
+ *  Output:
+ *      Pointer to the mode table
+ */
+mode_parameter_t *ddk768_getStockModeParamTableEx(
+    disp_control_t dispCtrl
+);
+
+/*
+ *  ddk768_getStockModeParamTableSizeEx
+ *      This function gets the size of the mode parameter table associated with
+ *      specific display control
+ *
+ *  Input:
+ *      dispCtrl    - Display control of the mode param table that is associated to.
+ *
+ *  Output:
+ *      Size of the requeted mode param table.
+ */
+unsigned long ddk768_getStockModeParamTableSizeEx(
+    disp_control_t dispCtrl
+);
+
+/* 
+ * This function returns the current mode.
+ */
+mode_parameter_t ddk768_getCurrentModeParam(
+    disp_control_t dispCtrl
+);
+
+/*
+ *  getMaximumModeEntries
+ *      This function gets the maximum entries that can be stored in the mode table.
+ *
+ *  Output:
+ *      Total number of maximum entries
+ */
+unsigned long getMaximumModeEntries(void);
+
+/*
+ *  addTiming
+ *      This function adds the SM750 mode parameter timing to the specified mode table
+ *
+ *  Input:
+ *      dispCtrl        - Display control where the mode will be associated to
+ *      pNewModeList    - Pointer to a list table of SM750 mode parameter to be added 
+ *                        to the current specified display control mode table.
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long addTiming(
+    disp_control_t dispCtrl,
+    mode_parameter_t *pNewModeList,
+    unsigned long totalList,
+    unsigned char clearTable
+);
+
+
+
+/*
+ *    This function sets the display base address
+ *
+ *    Input:
+ *        dispControl        - display control of which base address to be set.
+ *        ulBaseAddress    - Base Address value to be set.
+ */
+void ddk768_setDisplayBaseAddress(
+    disp_control_t dispControl,
+    unsigned long ulBaseAddress
+);
+
+/*
+ *    This function checks if change of "display base address" has effective.
+ *    Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change.
+ *    HW resets pending bit when it starts to use the new address.
+ *
+ *    Input:
+ *        dispControl        - display control of which display status to be retrieved.
+ *
+ *  Output:
+ *      1   - Display is pending
+ *      0   - Display is not pending
+ */
+long isDisplayBasePending(
+    disp_control_t dispControl
+);
+
+/*
+ * Input:
+ *     1) pLogicalMode contains information such as x, y resolution and bpp.
+ *     2) A user defined parameter table for the mode.
+ *
+ * This function calculate and programs the hardware to set up the
+ * requested mode.
+ *
+ * This function allows the use of user defined parameter table if
+ * predefined Vesa parameter table (gDefaultModeParamTable) does not fit.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setCustomMode(
+    logicalMode_t *pLogicalMode, 
+    mode_parameter_t *pUserModeParam
+);
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp 
+ * The main difference between setMode and setModeEx userData.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setModeEx(
+    logicalMode_t *pLogicalMode
+);
+
+/*
+ * Input pLogicalMode contains information such as x, y resolution and bpp.
+ * If there is no special parameters, use this function.
+ * If there are special parameters, use setModeEx.
+ *
+ * Return: 0 (or NO_ERROR) if mode can be set successfully.
+ *         -1 if any set mode error.
+ */
+long ddk768_setMode(
+    logicalMode_t *pLogicalMode
+);
+
+
+#endif /* _MODE_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_power.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_power.c
new file mode 100644
index 000000000000..023022c99606
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_power.c
@@ -0,0 +1,269 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  power.c --- Voyager GX SDK 
+*  This file contains the source code for the power functions.
+* 
+*******************************************************************/
+#include "ddk768_reg.h"
+
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+
+#include "ddk768_help.h"
+
+
+
+/*
+ *  Enable/disable jpeg decoder 1.
+ */
+void ddk768_enableJPU1(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+    if (enable)
+        regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, ON);
+    else
+        regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, OFF);
+
+    pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/* 
+ * This function enable/disable the 2D engine.
+ */
+void ddk768_enable2DEngine(unsigned long enable)
+{
+	unsigned long regValue;
+	
+	regValue = peekRegisterDWord(CLOCK_ENABLE);
+	   if (enable)
+		   regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, ON);
+	   else
+		   regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, OFF);
+	
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+
+}
+
+/* 
+ * This function enable/disable the ZV Port.
+ */
+void ddk768_enableZVPort(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, ZV, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, ZV, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+
+}
+
+/* 
+ * This function enable/disable the SSP.
+ */
+void ddk768_enableSSP(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+
+}
+
+/* 
+ * This function enable/disable the DMA Engine
+ */
+void ddk768_enableDMA(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+
+}
+
+
+
+/*
+ *  This function enable/disable HDMI
+ */
+void ddk768_enableHDMI(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *  Enable/disable USB 2 Host.
+ */
+void ddk768_enableUsbHost(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBH, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBH, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *  Enable/disable USB 3 device
+ */
+void ddk768_enableUsbDevice(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *  Enable/disable jpeg decoder.
+ */
+void ddk768_enableJPU(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *	Enable/disable H264 video decoder.
+ */ 
+void ddk768_enableVPU(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+
+/*
+ *	Enable/disable UART
+ */ 
+void ddk768_enableUART(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *	Enable/disable I2S
+ */ 
+void ddk768_enableI2S(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+
+
+/*
+ *	Enable/disable ARM
+ */ 
+void ddk768_enableARM(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *	Enable/disable display control 0
+ */ 
+void ddk768_enableDC0(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
+/*
+ *	Enable/disable display control 1
+ */ 
+void ddk768_enableDC1(unsigned long enable)
+{
+    unsigned long regValue;
+
+    regValue = peekRegisterDWord(CLOCK_ENABLE);
+	if (enable)
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, ON);
+	else
+		regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, OFF);
+
+	pokeRegisterDWord(CLOCK_ENABLE, regValue);
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_power.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_power.h
new file mode 100644
index 000000000000..a37ff583fc81
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_power.h
@@ -0,0 +1,62 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  power.h --- Voyager GX SDK 
+*  This file contains the definitions for the power functions.
+* 
+*******************************************************************/
+#ifndef _DDK768_POWER_H_
+#define _DDK768_POWER_H_
+
+
+void ddk768_enableUsbHost(unsigned long enable);
+
+
+/*
+ *  Enable/disable jpeg decoder 1.
+ */
+void ddk768_enableJPU1(unsigned long enable);
+
+
+/* 
+ * This function enable/disable the 2D engine.
+ */
+void ddk768_enable2DEngine(unsigned long enable);
+
+/* 
+ * This function enable/disable the ZV Port 
+ */
+void ddk768_enableZVPort(unsigned long enable);
+
+/* 
+ * This function enable/disable the DMA Engine
+ */
+void ddk768_enableDMA(unsigned long enable);
+
+
+
+/* 
+ * This function enable/disable the PWM Engine
+ */
+void ddk768_enablePWM(unsigned long enable);
+
+/* 
+ * This function enable/disable the SSP.
+ */
+void ddk768_enableSSP(unsigned long enable);
+
+/*
+ * This function enable/disable the HDMI Clock. 
+ */
+void ddk768_enableHDMI(unsigned long enable);
+
+
+void ddk768_enableI2S(unsigned long enable);
+
+
+
+#endif /* _POWER_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.c
new file mode 100644
index 000000000000..05b756b3c52f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.c
@@ -0,0 +1,287 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  This file contains the definitions for the PWM functions.
+* 
+*******************************************************************/
+
+
+#include "ddk768_help.h"
+#include "ddk768_reg.h"
+#include "ddk768_helper.h"
+#include "ddk768_intr.h"
+#include "ddk768_pwm.h"
+
+
+static unsigned long gPwm = 0;
+
+/*
+ * This function open PWM lines in GPIO Mux
+ */
+void ddk768_pwmOpen(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{
+    unsigned long value;
+
+    /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */
+    value = peekRegisterDWord(GPIO_MUX);
+
+    switch(pwm)
+    {
+        case 0:
+            value = FIELD_SET(value, GPIO_MUX, 17, PWM0);
+            break;
+
+        case 1:
+            value = FIELD_SET(value, GPIO_MUX, 18, PWM1);
+            break;
+
+        default:
+            value = FIELD_SET(value, GPIO_MUX, 19, PWM2);
+            break;
+    }
+
+    pokeRegisterDWord(GPIO_MUX, value);
+}
+
+/*
+ * This function closes PWM lines in GPIO Mux
+ */
+void ddk768_pwmClose(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{
+    unsigned long value;
+
+    /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */
+    value = peekRegisterDWord(GPIO_MUX);
+
+    switch(pwm)
+    {
+        case 0:
+            value = FIELD_SET(value, GPIO_MUX, 17, GPIO);
+            break;
+
+        case 1:
+            value = FIELD_SET(value, GPIO_MUX, 18, GPIO);
+            break;
+
+        default:
+            value = FIELD_SET(value, GPIO_MUX, 19, GPIO);
+            break;
+    }
+
+    pokeRegisterDWord(GPIO_MUX, value);
+}
+
+/*
+ * According to input time, this function calculates values
+ * for PWM clock divide and PWM counter with 50% duty cycle.
+ */
+void ddk768_pwmCalcCounter(
+    unsigned long mSec,        /* Input time in milli second */
+    unsigned long *clkDivider, /* Output clock divider value */
+    unsigned long *counter     /* Output counter value for both high and low counter at 50% duty cycle */
+)
+{
+    /* The value of counter depends on the clock frequency the counter is running.
+       For FPGA, it is 100MHz. For ASIC, it is 180 to 200 MHz.
+     */
+
+    /* For FPGA testing purpose, just return any number for now */
+    *clkDivider = 8;  /* Divide by 256 */
+    *counter = 0xfff; /* Max 12 bit value */ 
+}
+
+/*
+ * This function starts PWM.
+ * When PWM completes a cycle, its raw interrupt pending bit will be set. 
+ *
+ * Important limitation: Since all three PWM shares one INT status and mask,
+ * only one PWM can set up ISR at any time.
+ *
+ */
+void ddk768_pwmStart(
+    unsigned long pwm,           /* which pwm: 0 to 2 */
+    unsigned long divider,
+    unsigned long highCounter,
+    unsigned long lowCounter,
+    unsigned long isrSupport     /* 1 if user wants to hook an ISR, 0 if use pulling method 
+                                    Note that only one PWM can have ISR at any time.
+                                  */
+)
+{  
+    unsigned long pwmAddr, pwmValue;
+
+    if (pwm > 2) return; /* Invalid PWM number */
+
+    if (highCounter == 0 || lowCounter == 0) return; /* Nothing to set */
+
+    /* Work out the PWM's MMIO address 
+       PWM 0 address + ( PWM x 4 )
+    */
+    pwmAddr = PWM_CONTROL + (pwm << 2);
+
+    pwmValue =
+          FIELD_VALUE(0, PWM_CONTROL, HIGH_COUNTER, highCounter)
+        | FIELD_VALUE(0, PWM_CONTROL, LOW_COUNTER, lowCounter)
+        | FIELD_VALUE(0, PWM_CONTROL, CLOCK_DIVIDE, divider)
+        | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR)   /* Reset the raw interrupt */
+        | FIELD_SET(0, PWM_CONTROL, INTERRUPT, ENABLE)         /* Enable raw interrupt to happen */
+        | FIELD_SET(0, PWM_CONTROL, STATUS, ENABLE);           /* Start PWM */
+
+    pokeRegisterDWord(pwmAddr, pwmValue);
+
+    if (isrSupport)
+        gPwm = pwm;
+}
+
+/*
+ * This function checks if a PWM's raw interrupt has been pending.
+ * When raw interrupt is detected with pending status, it indicate the
+ * a pulse cycle is completed after pwmStart().
+ * 
+ * Return:
+ *        1 = Raw interrupt status is pending.
+ *        0 = Raw int is NOT pending.
+ */
+unsigned long ddk768_pwmRawIntPending(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{  
+    unsigned long pwmAddr, rawIntStatus;
+
+    if (pwm > 2) return 0; /* Invalid PWM number */
+
+    /* Work out the PWM's MMIO address 
+       PWM 0 address + ( PWM x 4 )
+    */
+    pwmAddr = PWM_CONTROL + (pwm << 2);
+
+    rawIntStatus = FIELD_GET(peekRegisterDWord(pwmAddr), PWM_CONTROL, INTERRUPT_STATUS);
+
+    return(rawIntStatus);
+}
+
+/*
+ * This function clears the RAW interrupt status of PWM.
+ * 
+ * When PWM completes a cycle, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different cycles.
+ * 
+ */
+void ddk768_pwmClearRawInt(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{  
+    unsigned long pwmAddr, pwmValue;
+
+    if (pwm > 2) return; /* Invalid PWM number */
+
+    /* Work out the PWM's MMIO address 
+       PWM 0 address + ( PWM x 4 )
+    */
+    pwmAddr = PWM_CONTROL + (pwm << 2);
+
+    pwmValue = peekRegisterDWord(pwmAddr);
+
+    pokeRegisterDWord(pwmAddr,
+            pwmValue
+          | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR));    /* Reset the raw interrupt */
+}
+
+/*
+ * This function stop PWM
+ *
+ */
+void ddk768_pwmStop(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{  
+    unsigned long pwmAddr, pwmValue;
+
+    if (pwm > 2) return; /* Invalid PWM number */
+
+    /* Work out the PWM's MMIO address 
+       PWM 0 address + ( PWM x 4 )
+    */
+    pwmAddr = PWM_CONTROL + (pwm << 2);
+
+    pwmValue =
+          FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR)    /* Reset the raw interrupt */
+        | FIELD_SET(0, PWM_CONTROL, STATUS, DISABLE);        /* Stop the PWM */
+
+    pokeRegisterDWord(pwmAddr, pwmValue);
+}
+
+/* 
+ * This funciton uses PWM to wait a specific amount of time.
+ *
+ * Input: millisecond unit.
+ */
+void ddk768_pwmWait(
+    unsigned long pwm,
+    unsigned long milliSeconds
+)
+{
+    unsigned long divider, highCounter, lowCounter;
+
+    if (pwm > 2) return; /* Invalid PWM number */
+
+    /* Calculate how many ticks are needed for the amount of time.*/
+    ddk768_pwmCalcCounter(milliSeconds, &divider, &highCounter);
+    lowCounter = highCounter;
+
+    ddk768_pwmStart(pwm, divider, highCounter, lowCounter, 0);
+
+    while (!ddk768_pwmRawIntPending(pwm)); /* Danger, put a timeout here later */
+
+    ddk768_pwmStop(pwm);
+}
+
+/* 
+ * This function returns the INT mask for a specific PWM
+ *
+ */
+unsigned long ddk768_pwmIntMask(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+)
+{
+    unsigned long mask = 0;
+
+    /* Note: In falcon, all PWM shares one INT mask */
+    mask |= FIELD_SET(0, INT_MASK, PWM, ENABLE);
+
+    return mask;
+}
+
+/*
+ * This is a reference sample showing how to implement ISR for PWM
+ * It works together with libsrc\intr.c
+ * 
+ * Refer to Apps\timer\tstpwm.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+void ddk768_pwmIsrTemplate(unsigned long status)
+{
+    /* Check if it's PWM interrupt. */
+
+    if (FIELD_GET(status, INT_STATUS, PWM))
+    {
+        /* Perform ISR action for timer 0 here */
+        incTestCounter();    /* Dummy example action */
+
+        /* In Falcon, sicne all 3 PWM shares one PWM mask,
+           There is no way to tell which PWM generates the interrupt.
+           Just Clear the one marked down by pwmStart.
+         */
+        ddk768_pwmClearRawInt(gPwm);
+    }            
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.h
new file mode 100644
index 000000000000..0bc92a00ae5b
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_pwm.h
@@ -0,0 +1,117 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  This file contains the definitions for the timer functions.
+* 
+*******************************************************************/
+#ifndef _PWM_H_
+#define _PWM_H_
+
+/*
+ * This function open PWM lines in GPIO Mux
+ */
+void ddk768_pwmOpen(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/*
+ * This function closes PWM lines in GPIO Mux
+ */
+void ddk768_pwmClose(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/*
+ * According to input time, this function calculates values
+ * for PWM clock divide and PWM counter with 50% duty cycle.
+ */
+void ddk768_pwmCalcCounter(
+    unsigned long mSec,        /* Input time in milli second */
+    unsigned long *clkDivider, /* Output clock divider value */
+    unsigned long *counter     /* Output counter value for both high and low counter at 50% duty cycle */
+);
+
+/*
+ * This function starts PWM.
+ * When PWM completes a cycle, its raw interrupt pending bit will be set. 
+ *
+ * Important limitation: Since all three PWM shares one INT status and mask,
+ * only one PWM can set up ISR at any time.
+ *
+ */
+void ddk768_pwmStart(
+    unsigned long pwm,           /* which pwm: 0 to 2 */
+    unsigned long divider,
+    unsigned long highCounter,
+    unsigned long lowCounter,
+    unsigned long isrSupport     /* 1 if user wants to hook an ISR, 0 if use pulling method 
+                                    Note that only one PWM can have ISR at any time.
+                                  */
+);
+
+/*
+ * This function checks if a PWM's raw interrupt has been pending.
+ * When raw interrupt is detected with pending status, it indicate the
+ * a pulse cycle is completed after pwmStart().
+ * 
+ * Return:
+ *        1 = Raw interrupt status is pending.
+ *        0 = Raw int is NOT pending.
+ */
+unsigned long ddk768_pwmRawIntPending(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/*
+ * This function clears the RAW interrupt status of PWM.
+ * 
+ * When PWM completes a cycle, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different cycles.
+ * 
+ */
+void ddk768_pwmClearRawInt(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/*
+ * This function stop PWM
+ *
+ */
+void ddk768_pwmStop(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/* 
+ * This funciton uses PWM to wait a specific amount of time.
+ *
+ * Input: millisecond unit.
+ */
+void ddk768_pwmWait(
+    unsigned long pwm,
+    unsigned long milliSeconds
+);
+
+/* 
+ * This function returns the INT mask for a specific PWM
+ *
+ */
+unsigned long ddk768_pwmIntMask(
+    unsigned long pwm           /* which pwm: 0 to 2 */
+);
+
+/*
+ * This is a reference sample showing how to implement ISR for PWM
+ * It works together with libsrc\intr.c
+ * 
+ * Refer to Apps\timer\tstpwm.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+void ddk768_pwmIsrTemplate(unsigned long status);
+
+#endif /* _PWM_H_ */
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_reg.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_reg.h
new file mode 100644
index 000000000000..6335d2f6766c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_reg.h
@@ -0,0 +1,2813 @@
+
+//#include "regsc.h"
+
+#define SCRATCH_PAD0                                0x000060
+
+#define SCRATCH_PAD1                                0x000064
+
+#define CLOCK_ENABLE                                0x000068
+#define CLOCK_ENABLE_JPU1R                          30:30
+#define CLOCK_ENABLE_JPU1R_NORMAL                   0
+#define CLOCK_ENABLE_JPU1R_RESET                    1
+#define CLOCK_ENABLE_HDMIR                          29:29
+#define CLOCK_ENABLE_HDMIR_NORMAL                   0
+#define CLOCK_ENABLE_HDMIR_RESET                    1
+#define CLOCK_ENABLE_USBHR                          28:28
+#define CLOCK_ENABLE_USBHR_NORMAL                   0
+#define CLOCK_ENABLE_USBHR_RESET                    1
+#define CLOCK_ENABLE_USBSR                          27:27
+#define CLOCK_ENABLE_USBSR_NORMAL                   0
+#define CLOCK_ENABLE_USBSR_RESET                    1
+#define CLOCK_ENABLE_ZVR                            26:26
+#define CLOCK_ENABLE_ZVR_NORMAL                     0
+#define CLOCK_ENABLE_ZVR_RESET                      1
+#define CLOCK_ENABLE_JPUR                           25:25
+#define CLOCK_ENABLE_JPUR_NORMAL                    0
+#define CLOCK_ENABLE_JPUR_RESET                     1
+#define CLOCK_ENABLE_VPUR                           24:24
+#define CLOCK_ENABLE_VPUR_NORMAL                    0
+#define CLOCK_ENABLE_VPUR_RESET                     1
+#define CLOCK_ENABLE_DER                            23:23
+#define CLOCK_ENABLE_DER_NORMAL                     0
+#define CLOCK_ENABLE_DER_RESET                      1
+#define CLOCK_ENABLE_DMAR                           22:22
+#define CLOCK_ENABLE_DMAR_NORMAL                    0
+#define CLOCK_ENABLE_DMAR_RESET                     1
+#define CLOCK_ENABLE_DC1R                           18:18
+#define CLOCK_ENABLE_DC1R_NORMAL                    0
+#define CLOCK_ENABLE_DC1R_RESET                     1
+#define CLOCK_ENABLE_DC0R                           17:17
+#define CLOCK_ENABLE_DC0R_NORMAL                    0
+#define CLOCK_ENABLE_DC0R_RESET                     1
+#define CLOCK_ENABLE_ARMR                           16:16
+#define CLOCK_ENABLE_ARMR_NORMAL                    0
+#define CLOCK_ENABLE_ARMR_RESET                     1
+#define CLOCK_ENABLE_JPU1                           14:14
+#define CLOCK_ENABLE_JPU1_OFF                       0
+#define CLOCK_ENABLE_JPU1_ON                        1
+#define CLOCK_ENABLE_HDMI                           13:13
+#define CLOCK_ENABLE_HDMI_OFF                       0 
+#define CLOCK_ENABLE_HDMI_ON                        1
+#define CLOCK_ENABLE_USBH                           12:12
+#define CLOCK_ENABLE_USBH_OFF                       0
+#define CLOCK_ENABLE_USBH_ON                        1
+#define CLOCK_ENABLE_USBS                           11:11
+#define CLOCK_ENABLE_USBS_OFF                       0
+#define CLOCK_ENABLE_USBS_ON                        1
+#define CLOCK_ENABLE_ZV                             10:10
+#define CLOCK_ENABLE_ZV_OFF                         0
+#define CLOCK_ENABLE_ZV_ON                          1
+#define CLOCK_ENABLE_JPU                            9:9
+#define CLOCK_ENABLE_JPU_OFF                        0
+#define CLOCK_ENABLE_JPU_ON                         1
+#define CLOCK_ENABLE_VPU                            8:8
+#define CLOCK_ENABLE_VPU_OFF                        0
+#define CLOCK_ENABLE_VPU_ON                         1
+#define CLOCK_ENABLE_DE                             7:7
+#define CLOCK_ENABLE_DE_OFF                         0
+#define CLOCK_ENABLE_DE_ON                          1
+#define CLOCK_ENABLE_DMA                            6:6
+#define CLOCK_ENABLE_DMA_OFF                        0
+#define CLOCK_ENABLE_DMA_ON                         1
+#define CLOCK_ENABLE_UART                           5:5
+#define CLOCK_ENABLE_UART_OFF                       0
+#define CLOCK_ENABLE_UART_ON                        1
+#define CLOCK_ENABLE_I2S                            4:4
+#define CLOCK_ENABLE_I2S_OFF                        0
+#define CLOCK_ENABLE_I2S_ON                         1
+#define CLOCK_ENABLE_SSP                            3:3
+#define CLOCK_ENABLE_SSP_OFF                        0
+#define CLOCK_ENABLE_SSP_ON                         1
+#define CLOCK_ENABLE_DC1                            2:2
+#define CLOCK_ENABLE_DC1_OFF                        0
+#define CLOCK_ENABLE_DC1_ON                         1
+#define CLOCK_ENABLE_DC0                            1:1
+#define CLOCK_ENABLE_DC0_OFF                        0
+#define CLOCK_ENABLE_DC0_ON                         1
+#define CLOCK_ENABLE_ARM                            0:0
+#define CLOCK_ENABLE_ARM_OFF                        0
+#define CLOCK_ENABLE_ARM_ON                         1
+
+/* No bit fields for VGA PLL since DDK don't use it */
+#define VGA25PLL                                    0x00006C
+#define VGA28PLL                                    0x000070
+
+
+/* Master clock for DDR and core */
+#define MCLK_PLL                                     0x000074
+#define MCLK_PLL_VCO                                23:22
+#define MCLK_PLL_INT                                21:16
+#define MCLK_PLL_POWER                                0:0
+#define MCLK_PLL_POWER_NORMAL                        0
+#define MCLK_PLL_POWER_DOWN                            1
+
+/* Video clock 0  */
+#define VCLK0_PLL                                      0x000078
+/* VCLK Definition for FPGA */
+#define VCLK0_PLL_FREQ                                 4:0
+#define VCLK0_PLL_FREQ_25MHZ                           0
+#define VCLK0_PLL_FREQ_40MHZ                           1
+#define VCLK0_PLL_FREQ_65MHZ                           3
+#define VCLK0_PLL_FREQ_74MHZ                           4
+#define VCLK0_PLL_FREQ_80MHZ                           5
+#define VCLK0_PLL_FREQ_108MHZ                          6
+
+/* VCLK Definition for ASIC */
+#define VCLK_PLL_SSCG                                30:30
+#define VCLK_PLL_SSC                                29:28
+#define VCLK_PLL_FN                                    27:27
+#define VCLK_PLL_FN_INT_MODE                            0
+#define VCLK_PLL_FN_FRAC_MODE                            1
+#define VCLK_PLL_BS                                    26:25
+#define VCLK_PLL_VCO                                24:22
+#define VCLK_PLL_INT                                21:16
+#define VCLK_PLL_FRAC                                15:1
+#define VCLK_PLL_POWER                                0:0
+#define VCLK_PLL_POWER_NORMAL                        0
+#define VCLK_PLL_POWER_DOWN                            1
+
+/* Video clock 1. Bit field definiton is same as VCLK0 */
+#define VCLK1_PLL                                      0x00007C
+
+#define PROTOCOL_SEMAPHORE0                            0x000080
+#define PROTOCOL_SEMAPHORE1                            0x000084
+
+
+#define VGA_CONFIGURATION                          	0x000088
+#define VGA_CONFIGURATION_PLL                      	2:2
+#define VGA_CONFIGURATION_PLL_VGA                  	0
+#define VGA_CONFIGURATION_PLL_PANEL                	1
+#define VGA_CONFIGURATION_MODE                     	1:1
+#define VGA_CONFIGURATION_MODE_TEXT                	0
+#define VGA_CONFIGURATION_MODE_GRAPHIC             	1
+#define VGA_CONFIGURATION_PREFETCH                 	0:0
+#define VGA_CONFIGURATION_PREFETCH_DISABLE         	0
+#define VGA_CONFIGURATION_PREFETCH_ENABLE          	1
+
+/* Lock or unlock PCIE bar 2 to 5 */
+#define PCIE_BAR									0x00008C
+#define PCIE_BAR_LOCK								0:0
+#define PCIE_BAR_LOCK_UNLOCK						0
+#define PCIE_BAR_LOCK_LOCK							1
+
+
+#define RAW_INT                                    0x000090
+#define RAW_INT_CSC                                5:5
+#define RAW_INT_CSC_INACTIVE                       0
+#define RAW_INT_CSC_ACTIVE                         1
+#define RAW_INT_CSC_CLEAR                          1
+#define RAW_INT_DE                                 4:4
+#define RAW_INT_DE_INACTIVE                        0
+#define RAW_INT_DE_ACTIVE                          1
+#define RAW_INT_DE_CLEAR                           1
+#define RAW_INT_ZVPORT_VSYNC                       3:3
+#define RAW_INT_ZVPORT_VSYNC_INACTIVE              0
+#define RAW_INT_ZVPORT_VSYNC_ACTIVE                1
+#define RAW_INT_ZVPORT_VSYNC_CLEAR                 1
+#define RAW_INT_CHANNEL1_VSYNC                     2:2
+#define RAW_INT_CHANNEL1_VSYNC_INACTIVE            0
+#define RAW_INT_CHANNEL1_VSYNC_ACTIVE              1
+#define RAW_INT_CHANNEL1_VSYNC_CLEAR               1
+#define RAW_INT_CHANNEL0_VSYNC                     1:1
+#define RAW_INT_CHANNEL0_VSYNC_INACTIVE            0
+#define RAW_INT_CHANNEL0_VSYNC_ACTIVE              1
+#define RAW_INT_CHANNEL0_VSYNC_CLEAR               1
+#define RAW_INT_VGA_VSYNC                          0:0
+#define RAW_INT_VGA_VSYNC_INACTIVE                 0
+#define RAW_INT_VGA_VSYNC_ACTIVE                   1
+#define RAW_INT_VGA_VSYNC_CLEAR                    1
+
+#ifdef SMI_ARM
+#define INT_STATUS                                 0x0000A8
+#else
+#define INT_STATUS                                 0x000094
+#endif
+#define INT_STATUS_TIMER3                          31:31
+#define INT_STATUS_TIMER3_INACTIVE                 0
+#define INT_STATUS_TIMER3_ACTIVE                   1
+#define INT_STATUS_TIMER2                          30:30
+#define INT_STATUS_TIMER2_INACTIVE                 0
+#define INT_STATUS_TIMER2_ACTIVE                   1
+#define INT_STATUS_TIMER1                          29:29
+#define INT_STATUS_TIMER1_INACTIVE                 0
+#define INT_STATUS_TIMER1_ACTIVE                   1
+#define INT_STATUS_TIMER0                          28:28
+#define INT_STATUS_TIMER0_INACTIVE                 0
+#define INT_STATUS_TIMER0_ACTIVE                   1
+#define INT_STATUS_VPU                             27:27
+#define INT_STATUS_VPU_INACTIVE                    0
+#define INT_STATUS_VPU_ACTIVE                      1
+#define INT_STATUS_JPU                             26:26
+#define INT_STATUS_JPU_INACTIVE                    0
+#define INT_STATUS_JPU_ACTIVE                      1
+#define INT_STATUS_USBH                            25:25
+#define INT_STATUS_USBH_INACTIVE                   0
+#define INT_STATUS_USBH_ACTIVE                     1
+#define INT_STATUS_USBS                            24:24
+#define INT_STATUS_USBS_INACTIVE                   0
+#define INT_STATUS_USBS_ACTIVE                     1
+#define INT_STATUS_I2S                             23:23
+#define INT_STATUS_I2S_INACTIVE                    0
+#define INT_STATUS_I2S_ACTIVE                      1
+#define INT_STATUS_UART1                           22:22
+#define INT_STATUS_UART1_INACTIVE                  0
+#define INT_STATUS_UART1_ACTIVE                    1
+#define INT_STATUS_UART0                           21:21
+#define INT_STATUS_UART0_INACTIVE                  0
+#define INT_STATUS_UART0_ACTIVE                    1 
+#define INT_STATUS_SSP1                            20:20
+#define INT_STATUS_SSP1_INACTIVE                   0
+#define INT_STATUS_SSP1_ACTIVE                     1
+#define INT_STATUS_SSP0                            19:19
+#define INT_STATUS_SSP0_INACTIVE                   0
+#define INT_STATUS_SSP0_ACTIVE                     1
+#define INT_STATUS_I2C1                            18:18
+#define INT_STATUS_I2C1_INACTIVE                   0
+#define INT_STATUS_I2C1_ACTIVE                     1
+#define INT_STATUS_I2C0                            17:17
+#define INT_STATUS_I2C0_INACTIVE                   0
+#define INT_STATUS_I2C0_ACTIVE                     1
+#define INT_STATUS_PWM                             16:16
+#define INT_STATUS_PWM_INACTIVE                    0
+#define INT_STATUS_PWM_ACTIVE                      1 
+#define INT_STATUS_GPIO6                           15:15
+#define INT_STATUS_GPIO6_INACTIVE                  0
+#define INT_STATUS_GPIO6_ACTIVE                    1
+#define INT_STATUS_GPIO5                           14:14
+#define INT_STATUS_GPIO5_INACTIVE                  0
+#define INT_STATUS_GPIO5_ACTIVE                    1
+#define INT_STATUS_GPIO4                           13:13
+#define INT_STATUS_GPIO4_INACTIVE                  0
+#define INT_STATUS_GPIO4_ACTIVE                    1
+#define INT_STATUS_GPIO3                           12:12
+#define INT_STATUS_GPIO3_INACTIVE                  0
+#define INT_STATUS_GPIO3_ACTIVE                    1
+#define INT_STATUS_GPIO2                           11:11
+#define INT_STATUS_GPIO2_INACTIVE                  0
+#define INT_STATUS_GPIO2_ACTIVE                    1
+#define INT_STATUS_GPIO1                           10:10
+#define INT_STATUS_GPIO1_INACTIVE                  0
+#define INT_STATUS_GPIO1_ACTIVE                    1
+#define INT_STATUS_GPIO0                           9:9
+#define INT_STATUS_GPIO0_INACTIVE                  0
+#define INT_STATUS_GPIO0_ACTIVE                    1
+#define INT_STATUS_DMA                             8:8
+#define INT_STATUS_DMA_INACTIVE                    0
+#define INT_STATUS_DMA_ACTIVE                      1
+#define INT_STATUS_PCI                             7:7
+#define INT_STATUS_PCI_INACTIVE                    0
+#define INT_STATUS_PCI_ACTIVE                      1
+#define INT_STATUS_HDMI							   6:6
+#define INT_STATUS_HDMI_INACTIVE				   0
+#define INT_STATUS_HDMI_ACTIVE					   1
+#define INT_STATUS_CSC                             5:5
+#define INT_STATUS_CSC_INACTIVE                    0
+#define INT_STATUS_CSC_ACTIVE                      1
+#define INT_STATUS_DE                              4:4
+#define INT_STATUS_DE_INACTIVE                     0
+#define INT_STATUS_DE_ACTIVE                       1
+#define INT_STATUS_ZVPORT_VSYNC                    3:3
+#define INT_STATUS_ZVPORT_VSYNC_INACTIVE           0
+#define INT_STATUS_ZVPORT_VSYNC_ACTIVE             1
+#define INT_STATUS_CHANNEL1_VSYNC                  2:2
+#define INT_STATUS_CHANNEL1_VSYNC_INACTIVE         0
+#define INT_STATUS_CHANNEL1_VSYNC_ACTIVE           1
+#define INT_STATUS_CHANNEL0_VSYNC                  1:1
+#define INT_STATUS_CHANNEL0_VSYNC_INACTIVE         0
+#define INT_STATUS_CHANNEL0_VSYNC_ACTIVE           1
+#define INT_STATUS_VGA_VSYNC                       0:0
+#define INT_STATUS_VGA_VSYNC_INACTIVE              0
+#define INT_STATUS_VGA_VSYNC_ACTIVE                1
+
+#ifdef SMI_ARM
+#define INT_MASK                                   0x00009C
+#else
+#define INT_MASK                                   0x000098
+#endif
+
+#define INT_MASK_TIMER3                            31:31
+#define INT_MASK_TIMER3_DISABLE                    0
+#define INT_MASK_TIMER3_ENABLE                     1
+#define INT_MASK_TIMER2                            30:30
+#define INT_MASK_TIMER2_DISABLE                    0
+#define INT_MASK_TIMER2_ENABLE                     1
+#define INT_MASK_TIMER1                            29:29
+#define INT_MASK_TIMER1_DISABLE                    0
+#define INT_MASK_TIMER1_ENABLE                     1
+#define INT_MASK_TIMER0                            28:28
+#define INT_MASK_TIMER0_DISABLE                    0
+#define INT_MASK_TIMER0_ENABLE                     1
+#define INT_MASK_VPU                                27:27
+#define INT_MASK_VPU_DISABLE                        0
+#define INT_MASK_VPU_ENABLE                            1
+#define INT_MASK_JPU                                26:26
+#define INT_MASK_JPU_DISABLE                        0
+#define INT_MASK_JPU_ENABLE                            1
+#define INT_MASK_USBH                              25:25
+#define INT_MASK_USBH_DISABLE                      0
+#define INT_MASK_USBH_ENABLE                       1
+#define INT_MASK_USBS                              24:24
+#define INT_MASK_USBS_DISABLE                      0
+#define INT_MASK_USBS_ENABLE                       1
+#define INT_MASK_I2S                               23:23
+#define INT_MASK_I2S_DISABLE                       0
+#define INT_MASK_I2S_ENABLE                        1
+#define INT_MASK_UART1                             22:22
+#define INT_MASK_UART1_DISABLE                     0
+#define INT_MASK_UART1_ENABLE                      1
+#define INT_MASK_UART0                             21:21
+#define INT_MASK_UART0_DISABLE                     0
+#define INT_MASK_UART0_ENABLE                      1 
+#define INT_MASK_SSP1                              20:20
+#define INT_MASK_SSP1_DISABLE                      0
+#define INT_MASK_SSP1_ENABLE                       1
+#define INT_MASK_SSP0                              19:19
+#define INT_MASK_SSP0_DISABLE                      0
+#define INT_MASK_SSP0_ENABLE                       1
+#define INT_MASK_I2C1                              18:18
+#define INT_MASK_I2C1_DISABLE                      0
+#define INT_MASK_I2C1_ENABLE                       1
+#define INT_MASK_I2C0                              17:17
+#define INT_MASK_I2C0_DISABLE                      0
+#define INT_MASK_I2C0_ENABLE                       1
+#define INT_MASK_PWM                               16:16
+#define INT_MASK_PWM_DISABLE                       0
+#define INT_MASK_PWM_ENABLE                        1 
+#define INT_MASK_GPIO6                             15:15
+#define INT_MASK_GPIO6_DISABLE                     0
+#define INT_MASK_GPIO6_ENABLE                      1
+#define INT_MASK_GPIO5                             14:14
+#define INT_MASK_GPIO5_DISABLE                     0
+#define INT_MASK_GPIO5_ENABLE                      1
+#define INT_MASK_GPIO4                             13:13
+#define INT_MASK_GPIO4_DISABLE                     0
+#define INT_MASK_GPIO4_ENABLE                      1
+#define INT_MASK_GPIO3                             12:12
+#define INT_MASK_GPIO3_DISABLE                     0
+#define INT_MASK_GPIO3_ENABLE                      1
+#define INT_MASK_GPIO2                             11:11
+#define INT_MASK_GPIO2_DISABLE                     0
+#define INT_MASK_GPIO2_ENABLE                      1
+#define INT_MASK_GPIO1                             10:10
+#define INT_MASK_GPIO1_DISABLE                     0
+#define INT_MASK_GPIO1_ENABLE                      1
+#define INT_MASK_GPIO0                             9:9
+#define INT_MASK_GPIO0_DISABLE                     0
+#define INT_MASK_GPIO0_ENABLE                      1
+#define INT_MASK_DMA                               8:8
+#define INT_MASK_DMA_DISABLE                       0
+#define INT_MASK_DMA_ENABLE                        1
+#define INT_MASK_CPU                               7:7
+#define INT_MASK_CPU_DISABLE                       0
+#define INT_MASK_CPU_ENABLE                        1
+#define INT_MASK_HDMI							   6:6
+#define INT_MASK_HDMI_DISABLE					   0
+#define INT_MASK_HDMI_ENABLE					   1
+#define INT_MASK_CSC                               5:5
+#define INT_MASK_CSC_DISABLE                       0
+#define INT_MASK_CSC_ENABLE                        1
+#define INT_MASK_DE                                4:4
+#define INT_MASK_DE_DISABLE                        0
+#define INT_MASK_DE_ENABLE                         1
+#define INT_MASK_ZVPORT_VSYNC                      3:3
+#define INT_MASK_ZVPORT_VSYNC_DISABLE              0
+#define INT_MASK_ZVPORT_VSYNC_ENABLE               1
+#define INT_MASK_CHANNEL1_VSYNC                    2:2
+#define INT_MASK_CHANNEL1_VSYNC_DISABLE            0
+#define INT_MASK_CHANNEL1_VSYNC_ENABLE             1
+#define INT_MASK_CHANNEL0_VSYNC                    1:1
+#define INT_MASK_CHANNEL0_VSYNC_DISABLE            0
+#define INT_MASK_CHANNEL0_VSYNC_ENABLE             1
+#define INT_MASK_VGA_VSYNC                         0:0
+#define INT_MASK_VGA_VSYNC_DISABLE                 0
+#define INT_MASK_VGA_VSYNC_ENABLE                  1
+
+#define ARM_PROTOCOL_INT                           	0x0000A0
+#define ARM_PROTOCOL_INT_TOKEN						31:1
+#define ARM_PROTOCOL_INT_ENABLE						0:0
+#define ARM_PROTOCOL_INT_ENABLE_CLEAR				0
+#define ARM_PROTOCOL_INT_ENABLE_ENABLE				1
+
+#define PCIE_PROTOCOL_INT                          	0x0000A4
+#define PCIE_PROTOCOL_INT_TOKEN						31:1
+#define PCIE_PROTOCOL_INT_ENABLE					0:0
+#define PCIE_PROTOCOL_INT_ENABLE_CLEAR				0
+#define PCIE_PROTOCOL_INT_ENABLE_ENABLE				1
+
+#define ARM_STARTUP_CONFIG	                        0x000100
+#define ARM_STARTUP_CONFIG_USBH						30:30
+#define ARM_STARTUP_CONFIG_USBH_NORMAL				0
+#define ARM_STARTUP_CONFIG_USBH_RESET				1
+#define ARM_STARTUP_CONFIG_USBHPHY					29:29
+#define ARM_STARTUP_CONFIG_USBHPHY_NORMAL			0
+#define ARM_STARTUP_CONFIG_USBHPHY_RESET			1
+#define ARM_STARTUP_CONFIG_USBSPHY					28:28
+#define ARM_STARTUP_CONFIG_USBSPHY_NORMAL			0
+#define ARM_STARTUP_CONFIG_USBSPHY_RESET			1
+#define ARM_STARTUP_CONFIG_USBS						27:27
+#define ARM_STARTUP_CONFIG_USBS_NORMAL				0
+#define ARM_STARTUP_CONFIG_USBS_RESET				1
+#define ARM_STARTUP_CONFIG_ARM						0:0
+#define ARM_STARTUP_CONFIG_ARM_STOP					0
+#define ARM_STARTUP_CONFIG_ARM_START				1
+
+#define ARM_CONTROL                          		0x000110
+#define ARM_CONTROL_RESET							0:0
+#define ARM_CONTROL_RESET_RESET						0
+#define ARM_CONTROL_RESET_NORMAL					1
+
+/* DDK shoudn't need to program this register */
+#define USBH_CLOCK                                0x00114
+#define USBH_CLOCK_31_13                    31:13
+#define USBH_CLOCK_FS_IIS                   12:8
+#define USBH_CLOCK_7_6                        7:6
+#define USBH_CLOCK_PD                          5:5
+#define USBH_CLOCK_PD_NORMAL           			0
+#define USBH_CLOCK_PD_PDPLL               		1
+#define USBH_CLOCK_HS                          4:0 
+
+
+#define TEST_CONTROL                                0x00011C
+#define TEST_CONTROL_I2C                            11:11
+#define TEST_CONTROL_I2C_I2C1                        0
+#define TEST_CONTROL_I2C_HDMI                        1
+#define TEST_CONTROL_SSP1                            10:10
+#define TEST_CONTROL_SSP1_GPIO                        0
+#define TEST_CONTROL_SSP1_USBSPHY                    1
+
+
+#define STRAP_PINS                                    0x00012C
+#define STRAP_PINS_DEV_ID                                15:14
+#define STRAP_PINS_DEV_ID_SM768                     0
+#define STRAP_PINS_DEV_ID_SM765                     1
+#define STRAP_PINS_DEV_ID_SM766                     2
+#define STRAP_PINS_AUDIO                                13:13
+#define STRAP_PINS_AUDIO_ENABLE                   0
+#define STRAP_PINS_AUDIO_DISABLE                  1
+#define STRAP_PINS_CRYSTAL_CONFIG                           12:12
+#define STRAP_PINS_CRYSTAL_CONFIG_24000                   0
+#define STRAP_PINS_CRYSTAL_CONFIG_24576                  1
+#define STRAP_PINS_PIXEL_CONFIG                           10:10
+#define STRAP_PINS_PIXEL_CONFIG_FULL                  0
+#define STRAP_PINS_PIXEL_CONFIG_HALF                  1
+
+
+#define STRAP_PINS_MEM_SIZE                         1:0
+#define STRAP_PINS_MEM_SIZE_128M                    0
+#define STRAP_PINS_MEM_SIZE_256M                    1
+#define STRAP_PINS_MEM_SIZE_512M                    2
+#define STRAP_PINS_MEM_SIZE_1024M                   3
+
+
+#define DDR_CONTROL                                  0x000130
+#define DDR_CONTROL_COL                              3:2
+#define DDR_CONTROL_COL_1024                         0   
+#define DDR_CONTROL_COL_2048                         1
+#define DDR_CONTROL_COL_256                          2
+#define DDR_CONTROL_COL_512                          3
+#define DDR_CONTROL_SIZE                             1:0   
+#define DDR_CONTROL_SIZE_256M                        0
+#define DDR_CONTROL_SIZE_512M                        1
+#define DDR_CONTROL_SIZE_1024M                       2   
+#define DDR_CONTROL_SIZE_128M                        3
+
+#define JPU_PERFORMANCE_MODE                         0x000134
+#define JPU_PERFORMANCE_MODE_JPU1                    3:2
+#define JPU_PERFORMANCE_MODE_JPU1_DISABLE            0
+#define JPU_PERFORMANCE_MODE_JPU1_HD                 1
+#define JPU_PERFORMANCE_MODE_JPU1_UHD                2
+#define JPU_PERFORMANCE_MODE_JPU0                    1:0
+#define JPU_PERFORMANCE_MODE_JPU0_DISABLE	           0
+#define JPU_PERFORMANCE_MODE_JPU0_HD                 1
+#define JPU_PERFORMANCE_MODE_JPU0_UHD                2
+
+#define DDR_PRIORITY1                                0x000138
+
+#define DDR_PRIORITY2                                0x00013C
+
+
+//#include "reggpio.h"
+
+
+
+#define GPIO_DATA                                       0x010000
+#define GPIO_DATA_IIC0_DATA_DVI_SHIFT                     31
+#define GPIO_DATA_IIC0_CLK_DVI_SHIFT                        30
+#define GPIO_DATA_SSP1_CLK_OUT_SHIFT                      29
+#define GPIO_DATA_GPIO_CODEC_DATA_SHIFT               29
+#define GPIO_DATA_SSP1_FRAMEINPUT_SHIFT                          28
+#define GPIO_DATA_IIS_RX_SHIFT                                   28
+#define GPIO_DATA_SSP1_FRAMEOUT_SHIFT                   27
+#define GPIO_DATA_GPIO_IIS_TX_SHIFT                         27
+#define GPIO_DATA_SSP1_RX_SHIFT                          26
+#define GPIO_DATA_GPIO_IIS_WS_SHIFT                        26
+#define GPIO_DATA_SSP1_TX_SHIFT                   25
+#define GPIO_DATA_GPIO_IIS_CLK_SHIFT                       25
+#define GPIO_DATA_SSP0_CLK_OUT_SHIFT                     24
+#define GPIO_DATA_GPIO_SWSSP_CLK_OUT_SHIFT                     24
+#define GPIO_DATA_SSP0_FRAMINPUT_SHIFT                 23
+#define GPIO_DATA_GPIO_SWSSP_FRAMINPUT_SHIFT                 23
+#define GPIO_DATA_SSP0_FRAMEOUT_SHIFT                  22
+#define GPIO_DATA_GPIO_SWSSP_FRAMEOUT_SHIFT                  22
+#define GPIO_DATA_SSP0_RX_SHIFT                               21
+#define GPIO_DATA_GPIO_SWSSP_RX_SHIFT                               21
+#define GPIO_DATA_SSP0_TX_SHIFT                               20
+#define GPIO_DATA_GPIO_SWSSP_TX_SHIFT                               20
+#define GPIO_DATA_PWM2_SHIFT                                   19
+#define GPIO_DATA_GPIO_UART1_EXT_CLK_SHIFT        19
+#define GPIO_DATA_GPIO_UART0_EXT_CLK_SHIFT        19
+#define GPIO_DATA_PWM1_SHIFT                                   18
+#define GPIO_DATA_PWM0_SHIFT                                   17
+#define GPIO_DATA_PCIE_SHIFT                                     16
+#define GPIO_DATA_UART0_SIN_SHIFT                          15
+#define GPIO_DATA_UART0_NCTSIN_SHIFT                   14
+#define GPIO_DATA_UART0_TXD_SHIFT                         13
+#define GPIO_DATA_UART0_NRTS_SHIFT                       12
+#define GPIO_DATA_UART1_SIN_SHIFT                         11
+#define GPIO_DATA_GPIO_CODEC_CLK_SHIFT               11
+#define GPIO_DATA_UART1_NCTSIN_SHIFT                   10
+#define GPIO_DATA_GPIO_CODEC_MODE_SHIFT            10
+#define GPIO_DATA_UART1_TXD_SHIFT                         9
+#define GPIO_DATA_GPIO_IIC_DATA_HDMI_SHIFT       9
+#define GPIO_DATA_GPIO_IIC_CLK_HDMI_SHIFT          8
+#define GPIO_DATA_UART1_NRTS_SHIFT                       8
+#define GPIO_DATA_IIC1_DATA_CRT_SHIFT                  7
+#define GPIO_DATA_IIC1_CLK_CRT_SHIFT                     6
+#define GPIO_DATA_GPIO_VBUS_SHIFT                         5
+#define GPIO_DATA_IIS_TX_SELECT_SHIFT                   4
+#define GPIO_DATA_GPIO_DVI_PNP_SHIFT                   4
+#define GPIO_DATA_IIS_WS_SELECT_SHIFT                 3
+#define GPIO_DATA_GPIO_AUDIO_PNP_SHIFT              3
+#define GPIO_DATA_IIS_CLK_SELECT_SHIFT                2
+#define GPIO_DATA_UART1_EXT_CLK_SELECT_SHIFT   1
+#define GPIO_DATA_GPIO_HDMI_PNP_SHIFT                1
+#define GPIO_DATA_UART0_EXT_CLK_SELECT_SHIFT   0
+
+#define GPIO_DATA_DIRECTION                             0x010004
+#define GPIO_DATA_DIRECTION_IIC0_DATA_DVI_SHIFT                     31
+#define GPIO_DATA_DIRECTION_IIC0_CLK_DVI_SHIFT                        30
+#define GPIO_DATA_DIRECTION_SSP1_CLK_OUT_SHIFT                      29
+#define GPIO_DATA_DIRECTION_GPIO_CODEC_DATA_SHIFT               29
+#define GPIO_DATA_DIRECTION_SSP1_FRAMEINPUT_SHIFT                          28
+#define GPIO_DATA_DIRECTION_IIS_RX_SHIFT                                   28
+#define GPIO_DATA_DIRECTION_SSP1_FRAMEOUT_SHIFT                   27
+#define GPIO_DATA_DIRECTION_GPIO_IIS_TX_SHIFT                         27
+#define GPIO_DATA_DIRECTION_SSP1_RX_SHIFT                          26
+#define GPIO_DATA_DIRECTION_GPIO_IIS_WS_SHIFT                        26
+#define GPIO_DATA_DIRECTION_SSP1_TX_SHIFT                   25
+#define GPIO_DATA_DIRECTION_GPIO_IIS_CLK_SHIFT                       25
+#define GPIO_DATA_DIRECTION_SSP0_CLK_OUT_SHIFT                     24
+#define GPIO_DATA_DIRECTION_GPIO_SWSSP_CLK_OUT_SHIFT                     24
+#define GPIO_DATA_DIRECTION_SSP0_FRAMEINPUT_SHIFT                         23
+#define GPIO_DATA_DIRECTION_GPIO_SWSSP_FRAMEINPUT_SHIFT                         23
+#define GPIO_DATA_DIRECTION_SSP0_FRAMEOUT_SHIFT                  22
+#define GPIO_DATA_DIRECTION_GPIO_SWSSP_FRAMEOUT_SHIFT                  22
+#define GPIO_DATA_DIRECTION_SSP0_RX_SHIFT                         21
+#define GPIO_DATA_DIRECTION_GPIO_SWSSP_RX_SHIFT                         21
+#define GPIO_DATA_DIRECTION_SSP0_TX_SHIFT                  20
+#define GPIO_DATA_DIRECTION_GPIO_SWSSP_TX_SHIFT                  20
+#define GPIO_DATA_DIRECTION_PWM2_SHIFT                                   19
+#define GPIO_DATA_DIRECTION_GPIO_UART1_EXT_CLK_SHIFT        19
+#define GPIO_DATA_DIRECTION_GPIO_UART0_EXT_CLK_SHIFT        19
+#define GPIO_DATA_DIRECTION_PWM1_SHIFT                                   18
+#define GPIO_DATA_DIRECTION_PWM0_SHIFT                                   17
+#define GPIO_DATA_DIRECTION_PCIE_SHIFT                                     16
+#define GPIO_DATA_DIRECTION_UART0_SIN_SHIFT                          15
+#define GPIO_DATA_DIRECTION_UART0_NCTSIN_SHIFT                   14
+#define GPIO_DATA_DIRECTION_UART0_TXD_SHIFT                         13
+#define GPIO_DATA_DIRECTION_UART0_NRTS_SHIFT                       12
+#define GPIO_DATA_DIRECTION_UART1_SIN_SHIFT                         11
+#define GPIO_DATA_DIRECTION_GPIO_CODEC_CLK_SHIFT               11
+#define GPIO_DATA_DIRECTION_UART1_NCTSIN_SHIFT                   10
+#define GPIO_DATA_DIRECTION_GPIO_CODEC_MODE_SHIFT            10
+#define GPIO_DATA_DIRECTION_UART1_TXD_SHIFT                         9
+#define GPIO_DATA_DIRECTION_GPIO_IIC_DATA_HDMI_SHIFT       9
+#define GPIO_DATA_DIRECTION_GPIO_IIC_CLK_HDMI_SHIFT          8
+#define GPIO_DATA_DIRECTION_UART1_NRTS_SHIFT                       8
+#define GPIO_DATA_DIRECTION_IIC1_DATA_CRT_SHIFT                  7
+#define GPIO_DATA_DIRECTION_IIC1_CLK_CRT_SHIFT                     6
+#define GPIO_DATA_DIRECTION_GPIO_VBUS_SHIFT                         5
+#define GPIO_DATA_DIRECTION_IIS_TX_SELECT_SHIFT                   4
+#define GPIO_DATA_DIRECTION_GPIO_DVI_PNP_SHIFT                   4
+#define GPIO_DATA_DIRECTION_IIS_WS_SELECT_SHIFT                 3
+#define GPIO_DATA_DIRECTION_GPIO_AUDIO_PNP_SHIFT              3
+#define GPIO_DATA_DIRECTION_IIS_CLK_SELECT_SHIFT                2
+#define GPIO_DATA_DIRECTION_UART1_EXT_CLK_SELECT_SHIFT   1
+#define GPIO_DATA_DIRECTION_GPIO_HDMI_PNP_SHIFT                1
+#define GPIO_DATA_DIRECTION_UART0_EXT_CLK_SELECT_SHIFT   0
+
+
+#define GPIO_INTERRUPT_SETUP                            0x010008
+#define GPIO_INTERRUPT_SETUP_VBUS_TRIGGER_EDGE_SHIFT    21
+#define GPIO_INTERRUPT_SETUP_VBUS_TRIGGER_LEVEL_SHIFT   21
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_TRIGGER_EDGE_SHIFT    20
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_TRIGGER_LEVEL_SHIFT   20
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_TRIGGER_EDGE_SHIFT    19
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_TRIGGER_LEVEL_SHIFT   19
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_TRIGGER_EDGE_SHIFT    17
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_TRIGGER_LEVEL_SHIFT   17
+
+
+#define GPIO_INTERRUPT_SETUP_VBUS_ACTIVE_LOW_SHIFT    13
+#define GPIO_INTERRUPT_SETUP_VBUS_ACTIVE_HIGH_SHIFT  13
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_ACTIVE_LOW_SHIFT    12
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_ACTIVE_HIGH_SHIFT   12
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ACTIVE_LOW_SHIFT    11
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ACTIVE_HIGH_SHIFT   11
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ACTIVE_LOW_SHIFT    9
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ACTIVE_HIGH_SHIFT   9
+
+
+#define GPIO_INTERRUPT_SETUP_VBUS_ENABLE_SHIFT             5
+#define GPIO_INTERRUPT_SETUP_VBUS_GPIO_ENABLE_SHIFT             5
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_ENABLE_SHIFT            4
+#define GPIO_INTERRUPT_SETUP_DVI_PNP_GPIO_ENABLE_SHIFT        4
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ENABLE_SHIFT             3
+#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_GPIO_ENABLE_SHIFT        3
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ENABLE_SHIFT             1
+#define GPIO_INTERRUPT_SETUP_HDMI_PNP_GPIO_ENABLE_SHIFT        1
+
+#define GPIO_INTERRUPT_STATUS                          0x01000C
+#define GPIO_INTERRUPT_STATUS_VBUS_INACTIVE               5
+#define GPIO_INTERRUPT_STATUS_VBUS_ACTIVE                 5
+#define GPIO_INTERRUPT_STATUS_VBUS_RESET                  5
+#define GPIO_INTERRUPT_STATUS_DVI_PNP_INACTIVE               4
+#define GPIO_INTERRUPT_STATUS_DVI_PNP_ACTIVE                 4
+#define GPIO_INTERRUPT_STATUS_DVI_PNP_RESET                  4
+#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_INACTIVE              3
+#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_ACTIVE                 3
+#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_RESET                  3
+#define GPIO_INTERRUPT_STATUS_HDMI_PNP_INACTIVE             1
+#define GPIO_INTERRUPT_STATUS_HDMI_PNP_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_HDMI_PNP_RESET                  1
+
+/*xxx_GPIO_xxxx means 0 is valid*/
+#define GPIO_MUX                                                     0x010010
+#define GPIO_MUX_IIC0_DATA_DVI_SHIFT                     31
+#define GPIO_MUX_IIC0_CLK_DVI_SHIFT                        30
+#define GPIO_MUX_SSP1_CLK_OUT_SHIFT                      29
+#define GPIO_MUX_GPIO_CODEC_DATA_SHIFT               29
+#define GPIO_MUX_SSP1_FRAMEINPUT_SHIFT                28
+#define GPIO_MUX_IIS_RX_SHIFT                                   28
+#define GPIO_MUX_SSP1_FRAMEOUT_SHIFT                   27
+#define GPIO_MUX_GPIO_IIS_TX_SHIFT                         27
+#define GPIO_MUX_SSP1_RX_SHIFT                                26
+#define GPIO_MUX_GPIO_IIS_WS_SHIFT                        26
+#define GPIO_MUX_SSP1_TX_SHIFT                               25
+#define GPIO_MUX_GPIO_IIS_CLK_SHIFT                       25
+#define GPIO_MUX_SSP0_CLK_OUT_SHIFT                     24
+#define GPIO_MUX_GPIO_SWSSP_CLK_OUT_SHIFT                  24
+#define GPIO_MUX_SSP0_FRAMEINPUT_SHIFT              23
+#define GPIO_MUX_GPIO_SWSSP_FRAMEINPUT_SHIFT           23
+#define GPIO_MUX_SSP0_FRAMEOUT_SHIFT                  22
+#define GPIO_MUX_GPIO_SWSSP_FRAMEOUT_SHIFT               22
+#define GPIO_MUX_SSP0_RX_SHIFT                               21
+#define GPIO_MUX_GPIO_SWSSP_RX_SHIFT                            21
+#define GPIO_MUX_SSP0_TX_SHIFT                               20
+#define GPIO_MUX_GPIO_SWSSP_TX_SHIFT                            20
+#define GPIO_MUX_PWM2_SHIFT                                   19
+#define GPIO_MUX_GPIO_UART1_EXT_CLK_SHIFT        19
+#define GPIO_MUX_GPIO_UART0_EXT_CLK_SHIFT        19
+#define GPIO_MUX_PWM1_SHIFT                                   18
+#define GPIO_MUX_PWM0_SHIFT                                   17
+#define GPIO_MUX_PCIE_SHIFT                                     16
+#define GPIO_MUX_UART0_SIN_SHIFT                          15
+#define GPIO_MUX_UART0_NCTSIN_SHIFT                   14
+#define GPIO_MUX_UART0_TXD_SHIFT                         13
+#define GPIO_MUX_UART0_NRTS_SHIFT                       12
+#define GPIO_MUX_UART1_SIN_SHIFT                         11
+#define GPIO_MUX_GPIO_CODEC_CLK_SHIFT               11
+#define GPIO_MUX_UART1_NCTSIN_SHIFT                   10
+#define GPIO_MUX_GPIO_CODEC_MODE_SHIFT            10
+#define GPIO_MUX_UART1_TXD_SHIFT                         9
+#define GPIO_MUX_GPIO_IIC_DATA_HDMI_SHIFT       9
+#define GPIO_MUX_GPIO_IIC_CLK_HDMI_SHIFT          8
+#define GPIO_MUX_UART1_NRTS_SHIFT                       8
+#define GPIO_MUX_IIC1_DATA_CRT_SHIFT                  7
+#define GPIO_MUX_IIC1_CLK_CRT_SHIFT                     6
+#define GPIO_MUX_GPIO_VBUS_SHIFT                         5
+#define GPIO_MUX_IIS_TX_SELECT_SHIFT                   4
+#define GPIO_MUX_GPIO_DVI_PNP_SHIFT                   4
+#define GPIO_MUX_IIS_WS_SELECT_SHIFT                 3
+#define GPIO_MUX_GPIO_AUDIO_PNP_SHIFT              3
+#define GPIO_MUX_IIS_CLK_SELECT_SHIFT                2
+#define GPIO_MUX_UART1_EXT_CLK_SELECT_SHIFT   1
+#define GPIO_MUX_GPIO_HDMI_PNP_SHIFT                1
+#define GPIO_MUX_UART0_EXT_CLK_SELECT_SHIFT   0
+
+
+
+#define GPIO_DATA_31                                    31:31
+#define GPIO_DATA_30                                    30:30
+#define GPIO_DATA_29                                    29:29
+#define GPIO_DATA_28                                    28:28
+#define GPIO_DATA_27                                    27:27
+#define GPIO_DATA_26                                    26:26
+#define GPIO_DATA_25                                    25:25
+#define GPIO_DATA_24                                    24:24
+#define GPIO_DATA_23                                    23:23
+#define GPIO_DATA_22                                    22:22
+#define GPIO_DATA_21                                    21:21
+#define GPIO_DATA_20                                    20:20
+#define GPIO_DATA_19                                    19:19
+#define GPIO_DATA_18                                    18:18
+#define GPIO_DATA_17                                    17:17
+#define GPIO_DATA_16                                    16:16
+#define GPIO_DATA_15                                    15:15
+#define GPIO_DATA_14                                    14:14
+#define GPIO_DATA_13                                    13:13
+#define GPIO_DATA_12                                    12:12
+#define GPIO_DATA_11                                    11:11
+#define GPIO_DATA_10                                    10:10
+#define GPIO_DATA_9                                     9:9
+#define GPIO_DATA_8                                     8:8
+#define GPIO_DATA_7                                     7:7
+#define GPIO_DATA_6                                     6:6
+#define GPIO_DATA_5                                     5:5
+#define GPIO_DATA_4                                     4:4
+#define GPIO_DATA_3                                     3:3
+#define GPIO_DATA_2                                     2:2
+#define GPIO_DATA_1                                     1:1
+#define GPIO_DATA_0                                     0:0
+
+
+#define GPIO_DATA_DIRECTION_31                          31:31
+#define GPIO_DATA_DIRECTION_31_INPUT                    0
+#define GPIO_DATA_DIRECTION_31_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_30                          30:30
+#define GPIO_DATA_DIRECTION_30_INPUT                    0
+#define GPIO_DATA_DIRECTION_30_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_29                          29:29
+#define GPIO_DATA_DIRECTION_29_INPUT                    0
+#define GPIO_DATA_DIRECTION_29_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_28                          28:28
+#define GPIO_DATA_DIRECTION_28_INPUT                    0
+#define GPIO_DATA_DIRECTION_28_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_27                          27:27
+#define GPIO_DATA_DIRECTION_27_INPUT                    0
+#define GPIO_DATA_DIRECTION_27_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_26                          26:26
+#define GPIO_DATA_DIRECTION_26_INPUT                    0
+#define GPIO_DATA_DIRECTION_26_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_25                          25:25
+#define GPIO_DATA_DIRECTION_25_INPUT                    0
+#define GPIO_DATA_DIRECTION_25_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_24                          24:24
+#define GPIO_DATA_DIRECTION_24_INPUT                    0
+#define GPIO_DATA_DIRECTION_24_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_23                          23:23
+#define GPIO_DATA_DIRECTION_23_INPUT                    0
+#define GPIO_DATA_DIRECTION_23_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_22                          22:22
+#define GPIO_DATA_DIRECTION_22_INPUT                    0
+#define GPIO_DATA_DIRECTION_22_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_21                          21:21
+#define GPIO_DATA_DIRECTION_21_INPUT                    0
+#define GPIO_DATA_DIRECTION_21_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_20                          20:20
+#define GPIO_DATA_DIRECTION_20_INPUT                    0
+#define GPIO_DATA_DIRECTION_20_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_19                          19:19
+#define GPIO_DATA_DIRECTION_19_INPUT                    0
+#define GPIO_DATA_DIRECTION_19_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_18                          18:18
+#define GPIO_DATA_DIRECTION_18_INPUT                    0
+#define GPIO_DATA_DIRECTION_18_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_17                          17:17
+#define GPIO_DATA_DIRECTION_17_INPUT                    0
+#define GPIO_DATA_DIRECTION_17_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_16                          16:16
+#define GPIO_DATA_DIRECTION_16_INPUT                    0
+#define GPIO_DATA_DIRECTION_16_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_15                          15:15
+#define GPIO_DATA_DIRECTION_15_INPUT                    0
+#define GPIO_DATA_DIRECTION_15_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_14                          14:14
+#define GPIO_DATA_DIRECTION_14_INPUT                    0
+#define GPIO_DATA_DIRECTION_14_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_13                          13:13
+#define GPIO_DATA_DIRECTION_13_INPUT                    0
+#define GPIO_DATA_DIRECTION_13_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_12                          12:12
+#define GPIO_DATA_DIRECTION_12_INPUT                    0
+#define GPIO_DATA_DIRECTION_12_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_11                          11:11
+#define GPIO_DATA_DIRECTION_11_INPUT                    0
+#define GPIO_DATA_DIRECTION_11_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_10                          10:10
+#define GPIO_DATA_DIRECTION_10_INPUT                    0
+#define GPIO_DATA_DIRECTION_10_OUTPUT                   1
+#define GPIO_DATA_DIRECTION_9                           9:9
+#define GPIO_DATA_DIRECTION_9_INPUT                     0
+#define GPIO_DATA_DIRECTION_9_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_8                           8:8
+#define GPIO_DATA_DIRECTION_8_INPUT                     0
+#define GPIO_DATA_DIRECTION_8_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_7                           7:7
+#define GPIO_DATA_DIRECTION_7_INPUT                     0
+#define GPIO_DATA_DIRECTION_7_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_6                           6:6
+#define GPIO_DATA_DIRECTION_6_INPUT                     0
+#define GPIO_DATA_DIRECTION_6_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_5                           5:5
+#define GPIO_DATA_DIRECTION_5_INPUT                     0
+#define GPIO_DATA_DIRECTION_5_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_4                           4:4
+#define GPIO_DATA_DIRECTION_4_INPUT                     0
+#define GPIO_DATA_DIRECTION_4_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_3                           3:3
+#define GPIO_DATA_DIRECTION_3_INPUT                     0
+#define GPIO_DATA_DIRECTION_3_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_2                           2:2
+#define GPIO_DATA_DIRECTION_2_INPUT                     0
+#define GPIO_DATA_DIRECTION_2_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_1                           1:1
+#define GPIO_DATA_DIRECTION_1_INPUT                     0
+#define GPIO_DATA_DIRECTION_1_OUTPUT                    1
+#define GPIO_DATA_DIRECTION_0                           0:0
+#define GPIO_DATA_DIRECTION_0_INPUT                     0
+#define GPIO_DATA_DIRECTION_0_OUTPUT                    1
+
+
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31                 22:22
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_31_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30                 21:21
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_30_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29                 20:20
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_29_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28                 19:19
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_28_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27                 18:18
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_27_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26                 17:17
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_26_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25                 16:16
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25_EDGE            0
+#define GPIO_INTERRUPT_SETUP_TRIGGER_25_LEVEL           1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31                  14:14
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_31_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30                  13:13
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_30_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29                  12:12
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_29_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28                  11:11
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_28_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27                  10:10
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_27_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26                  9:9
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_26_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25                  8:8
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25_LOW              0
+#define GPIO_INTERRUPT_SETUP_ACTIVE_25_HIGH             1
+#define GPIO_INTERRUPT_SETUP_ENABLE_31                  6:6
+#define GPIO_INTERRUPT_SETUP_ENABLE_31_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_31_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_30                  5:5
+#define GPIO_INTERRUPT_SETUP_ENABLE_30_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_30_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_29                  4:4
+#define GPIO_INTERRUPT_SETUP_ENABLE_29_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_29_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_28                  3:3
+#define GPIO_INTERRUPT_SETUP_ENABLE_28_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_28_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_27                  2:2
+#define GPIO_INTERRUPT_SETUP_ENABLE_27_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_27_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_26                  1:1
+#define GPIO_INTERRUPT_SETUP_ENABLE_26_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_26_INTERRUPT        1
+#define GPIO_INTERRUPT_SETUP_ENABLE_25                  0:0
+#define GPIO_INTERRUPT_SETUP_ENABLE_25_GPIO             0
+#define GPIO_INTERRUPT_SETUP_ENABLE_25_INTERRUPT        1
+
+
+#define GPIO_INTERRUPT_STATUS_31                        22:22
+#define GPIO_INTERRUPT_STATUS_31_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_31_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_31_RESET                  1
+#define GPIO_INTERRUPT_STATUS_30                        21:21
+#define GPIO_INTERRUPT_STATUS_30_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_30_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_30_RESET                  1
+#define GPIO_INTERRUPT_STATUS_29                        20:20
+#define GPIO_INTERRUPT_STATUS_29_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_29_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_29_RESET                  1
+#define GPIO_INTERRUPT_STATUS_28                        19:19
+#define GPIO_INTERRUPT_STATUS_28_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_28_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_28_RESET                  1
+#define GPIO_INTERRUPT_STATUS_27                        18:18
+#define GPIO_INTERRUPT_STATUS_27_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_27_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_27_RESET                  1
+#define GPIO_INTERRUPT_STATUS_26                        17:17
+#define GPIO_INTERRUPT_STATUS_26_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_26_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_26_RESET                  1
+#define GPIO_INTERRUPT_STATUS_25                        16:16
+#define GPIO_INTERRUPT_STATUS_25_INACTIVE               0
+#define GPIO_INTERRUPT_STATUS_25_ACTIVE                 1
+#define GPIO_INTERRUPT_STATUS_25_RESET                  1
+
+
+#define GPIO_MUX_I2C0                                 31:30
+#define GPIO_MUX_I2C0_DISABLE                         0
+#define GPIO_MUX_I2C0_ENABLE                          3
+#define GPIO_MUX_31                                   31:31
+#define GPIO_MUX_31_GPIO                              0
+#define GPIO_MUX_31_I2C0                              1
+#define GPIO_MUX_30                                   30:30
+#define GPIO_MUX_30_GPIO                              0
+#define GPIO_MUX_30_I2C0                              1
+#define GPIO_MUX_29                                   29:29
+#define GPIO_MUX_29_GPIO                              0
+#define GPIO_MUX_29_SSP1                              1
+#define GPIO_MUX_28                                   28:28
+#define GPIO_MUX_28_GPIO                              0
+#define GPIO_MUX_28_SSP1                              1
+#define GPIO_MUX_28_I2S_RX                            1
+#define GPIO_MUX_27                                   27:27
+#define GPIO_MUX_27_GPIO                              0
+#define GPIO_MUX_27_I2S_TX                            0
+#define GPIO_MUX_27_SSP1                              1
+#define GPIO_MUX_26                                   26:26
+#define GPIO_MUX_26_GPIO                              0
+#define GPIO_MUX_26_I2S_WS                            0
+#define GPIO_MUX_26_SSP1                              1
+#define GPIO_MUX_25                                   25:25
+#define GPIO_MUX_25_GPIO                              0
+#define GPIO_MUX_25_I2S_CK                            0
+#define GPIO_MUX_25_SSP1                              1
+#define GPIO_MUX_24                                   24:24
+#define GPIO_MUX_24_GPIO                              0
+#define GPIO_MUX_24_SSP0                              1
+#define GPIO_MUX_23                                   23:23
+#define GPIO_MUX_23_GPIO                              0
+#define GPIO_MUX_23_SSP0                              1
+#define GPIO_MUX_22                                   22:22
+#define GPIO_MUX_22_GPIO                              0
+#define GPIO_MUX_22_SSP0                              1
+#define GPIO_MUX_21                                   21:21
+#define GPIO_MUX_21_GPIO                              0
+#define GPIO_MUX_21_SSP0                              1
+#define GPIO_MUX_20                                   20:20
+#define GPIO_MUX_20_GPIO                              0
+#define GPIO_MUX_20_SSP0                              1
+#define GPIO_MUX_19                                   19:19
+#define GPIO_MUX_19_GPIO                              0
+#define GPIO_MUX_19_PWM2                              1
+#define GPIO_MUX_18                                   18:18
+#define GPIO_MUX_18_GPIO                              0
+#define GPIO_MUX_18_PWM1                              1
+#define GPIO_MUX_17                                   17:17
+#define GPIO_MUX_17_GPIO                              0
+#define GPIO_MUX_17_PWM0                              1
+#define GPIO_MUX_16                                   16:16
+#define GPIO_MUX_16_GPIO                              0
+#define GPIO_MUX_16_UNUSED                            1
+#define GPIO_MUX_UART0                                15:12
+#define GPIO_MUX_UART0_DISABLE                        0
+#define GPIO_MUX_UART0_ENABLE                         15
+#define GPIO_MUX_15                                   15:15
+#define GPIO_MUX_15_GPIO                              0
+#define GPIO_MUX_15_UART0                             1
+#define GPIO_MUX_14                                   14:14
+#define GPIO_MUX_14_GPIO		                      0
+#define GPIO_MUX_14_UART0	                          1
+#define GPIO_MUX_13                                   13:13
+#define GPIO_MUX_13_GPIO		                      0
+#define GPIO_MUX_13_UART0                             1
+#define GPIO_MUX_12                                   12:12
+#define GPIO_MUX_12_GPIO		                      0
+#define GPIO_MUX_12_UART0                             1
+#define GPIO_MUX_UART1                                11:8
+#define GPIO_MUX_UART1_DISABLE                        0
+#define GPIO_MUX_UART1_ENABLE                         15
+#define GPIO_MUX_11                                   11:11
+#define GPIO_MUX_11_GPIO                              0
+#define GPIO_MUX_11_UART1                             1
+#define GPIO_MUX_10                                   10:10
+#define GPIO_MUX_10_GPIO		                      0
+#define GPIO_MUX_10_UART1	                          1
+#define GPIO_MUX_9                                    9:9
+#define GPIO_MUX_9_GPIO			                      0
+#define GPIO_MUX_9_UART1                              1
+#define GPIO_MUX_8                                    8:8
+#define GPIO_MUX_8_GPIO			                      0
+#define GPIO_MUX_8_UART1                              1
+#define GPIO_MUX_I2C1                                 7:6
+#define GPIO_MUX_I2C1_DISABLE                         0
+#define GPIO_MUX_I2C1_ENABLE                          3
+#define GPIO_MUX_7                                    7:7
+#define GPIO_MUX_7_GPIO			                      0
+#define GPIO_MUX_7_I2C1                               1
+#define GPIO_MUX_6                                    6:6
+#define GPIO_MUX_6_GPIO			                      0
+#define GPIO_MUX_6_I2C1                               1
+#define GPIO_MUX_5                                    5:5
+#define GPIO_MUX_5_GPIO			                      0
+#define GPIO_MUX_5_RESERVE                            1
+#define GPIO_MUX_4                                    4:4
+#define GPIO_MUX_4_GPIO27		                      0
+#define GPIO_MUX_4_I2S_TX                             1
+#define GPIO_MUX_3                                    3:3
+#define GPIO_MUX_3_GPIO26		                      0
+#define GPIO_MUX_3_I2S_WS                             1
+#define GPIO_MUX_2                                    2:2
+#define GPIO_MUX_2_GPIO25		                      0
+#define GPIO_MUX_2_I2S_CK                             1
+#define GPIO_MUX_1                                    1:1
+#define GPIO_MUX_1_UART1_INT_CLK                      0
+#define GPIO_MUX_1_UART1_EXT_CLK                      1
+#define GPIO_MUX_0                                    0:0
+#define GPIO_MUX_0_UART0_INT_CLK                      0
+#define GPIO_MUX_0_UART0_EXT_CLK                      1
+
+
+//#include "regpwm.h"
+
+#define PWM_CONTROL                                               0x010020
+#define PWM_CONTROL_HIGH_COUNTER                                  31:20
+#define PWM_CONTROL_LOW_COUNTER                                   19:8
+#define PWM_CONTROL_CLOCK_DIVIDE                                  7:4
+#define PWM_CONTROL_CLOCK_DIVIDE_1                                0
+#define PWM_CONTROL_CLOCK_DIVIDE_2                                1
+#define PWM_CONTROL_CLOCK_DIVIDE_4                                2
+#define PWM_CONTROL_CLOCK_DIVIDE_8                                3
+#define PWM_CONTROL_CLOCK_DIVIDE_16                               4
+#define PWM_CONTROL_CLOCK_DIVIDE_32                               5
+#define PWM_CONTROL_CLOCK_DIVIDE_64                               6
+#define PWM_CONTROL_CLOCK_DIVIDE_128                              7
+#define PWM_CONTROL_CLOCK_DIVIDE_256                              8
+#define PWM_CONTROL_CLOCK_DIVIDE_512                              9
+#define PWM_CONTROL_CLOCK_DIVIDE_1024                             10
+#define PWM_CONTROL_CLOCK_DIVIDE_2048                             11
+#define PWM_CONTROL_CLOCK_DIVIDE_4096                             12
+#define PWM_CONTROL_CLOCK_DIVIDE_8192                             13
+#define PWM_CONTROL_CLOCK_DIVIDE_16384                            14
+#define PWM_CONTROL_CLOCK_DIVIDE_32768                            15
+#define PWM_CONTROL_INTERRUPT_STATUS                              3:3
+#define PWM_CONTROL_INTERRUPT_STATUS_NOT_PENDING                  0
+#define PWM_CONTROL_INTERRUPT_STATUS_PENDING                      1
+#define PWM_CONTROL_INTERRUPT_STATUS_CLEAR                        1
+#define PWM_CONTROL_INTERRUPT                                     2:2
+#define PWM_CONTROL_INTERRUPT_DISABLE                             0
+#define PWM_CONTROL_INTERRUPT_ENABLE                              1
+#define PWM_CONTROL_STATUS                                        0:0
+#define PWM_CONTROL_STATUS_DISABLE                                0
+#define PWM_CONTROL_STATUS_ENABLE                                 1
+
+
+//#include "regssp.h"
+
+#define SSP_0_CONTROL_0                                 0x020000
+#define SSP_0_CONTROL_0_CLOCK_RATE                      15:8
+#define SSP_0_CONTROL_0_SCLKOUT_PHASE                   7:7
+#define SSP_0_CONTROL_0_SCLKOUT_PHASE_0                 0
+#define SSP_0_CONTROL_0_SCLKOUT_PHASE_1                 1
+#define SSP_0_CONTROL_0_SCLKOUT_POLARITY                6:6
+#define SSP_0_CONTROL_0_SCLKOUT_POLARITY_RISING         0
+#define SSP_0_CONTROL_0_SCLKOUT_POLARITY_FALLING        1
+#define SSP_0_CONTROL_0_FRAME_FORMAT                    5:4
+#define SSP_0_CONTROL_0_FRAME_FORMAT_MOTOROLA           0
+#define SSP_0_CONTROL_0_FRAME_FORMAT_TI                 1
+#define SSP_0_CONTROL_0_FRAME_FORMAT_NATIONAL           2
+#define SSP_0_CONTROL_0_DATA_SIZE                       3:0
+#define SSP_0_CONTROL_0_DATA_SIZE_4                     3
+#define SSP_0_CONTROL_0_DATA_SIZE_5                     4
+#define SSP_0_CONTROL_0_DATA_SIZE_6                     5
+#define SSP_0_CONTROL_0_DATA_SIZE_7                     6
+#define SSP_0_CONTROL_0_DATA_SIZE_8                     7
+#define SSP_0_CONTROL_0_DATA_SIZE_9                     8
+#define SSP_0_CONTROL_0_DATA_SIZE_10                    9
+#define SSP_0_CONTROL_0_DATA_SIZE_11                    10
+#define SSP_0_CONTROL_0_DATA_SIZE_12                    11
+#define SSP_0_CONTROL_0_DATA_SIZE_13                    12
+#define SSP_0_CONTROL_0_DATA_SIZE_14                    13
+#define SSP_0_CONTROL_0_DATA_SIZE_15                    14
+#define SSP_0_CONTROL_0_DATA_SIZE_16                    15
+
+#define SSP_0_CONTROL_1                                 0x020004
+#define SSP_0_CONTROL_1_SLAVE_OUTPUT                    6:6
+#define SSP_0_CONTROL_1_SLAVE_OUTPUT_ENABLE             0
+#define SSP_0_CONTROL_1_SLAVE_OUTPUT_DISABLE            1
+#define SSP_0_CONTROL_1_MODE_SELECT                     5:5
+#define SSP_0_CONTROL_1_MODE_SELECT_MASTER              0
+#define SSP_0_CONTROL_1_MODE_SELECT_SLAVE               1
+#define SSP_0_CONTROL_1_STATUS                          4:4
+#define SSP_0_CONTROL_1_STATUS_DISABLE                  0
+#define SSP_0_CONTROL_1_STATUS_ENABLE                   1
+#define SSP_0_CONTROL_1_LOOP_BACK                       3:3
+#define SSP_0_CONTROL_1_LOOP_BACK_DISABLE               0
+#define SSP_0_CONTROL_1_LOOP_BACK_ENABLE                1
+#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT               2:2
+#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT_DISABLE       0
+#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT_ENABLE        1
+#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT              1:1
+#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT_DISABLE      0
+#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT_ENABLE       1
+#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT               0:0
+#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT_DISABLE       0
+#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT_ENABLE        1
+
+#define SSP_0_DATA                                      0x020008
+#define SSP_0_DATA_DATA                                 15:0
+
+#define SSP_0_STATUS                                    0x02000C
+#define SSP_0_STATUS_STATUS                             4:4
+#define SSP_0_STATUS_STATUS_IDLE                        0
+#define SSP_0_STATUS_STATUS_BUSY                        1
+#define SSP_0_STATUS_RECEIVE_FIFO                       3:2
+#define SSP_0_STATUS_RECEIVE_FIFO_EMPTY                 0
+#define SSP_0_STATUS_RECEIVE_FIFO_NOT_EMPTY             1
+#define SSP_0_STATUS_RECEIVE_FIFO_FULL                  3
+#define SSP_0_STATUS_TRANSMIT_FIFO                      1:0
+#define SSP_0_STATUS_TRANSMIT_FIFO_FULL                 0
+#define SSP_0_STATUS_TRANSMIT_FIFO_NOT_FULL             2
+#define SSP_0_STATUS_TRANSMIT_FIFO_EMPTY                3
+
+#define SSP_0_CLOCK_PRESCALE                            0x020010
+#define SSP_0_CLOCK_PRESCALE_DIVISOR                    7:0
+
+#define SSP_0_INTERRUPT_STATUS                          0x020014
+#define SSP_0_INTERRUPT_STATUS_OVERRUN                  2:2
+#define SSP_0_INTERRUPT_STATUS_OVERRUN_NOT_ACTIVE       0
+#define SSP_0_INTERRUPT_STATUS_OVERRUN_ACTIVE           1
+#define SSP_0_INTERRUPT_STATUS_OVERRUN_CLEAR            1
+#define SSP_0_INTERRUPT_STATUS_TRANSMIT                 1:1
+#define SSP_0_INTERRUPT_STATUS_TRANSMIT_NOT_ACTIVE      0
+#define SSP_0_INTERRUPT_STATUS_TRANSMIT_ACTIVE          1
+#define SSP_0_INTERRUPT_STATUS_RECEIVE                  0:0
+#define SSP_0_INTERRUPT_STATUS_RECEIVE_NOT_ACTIVE       0
+#define SSP_0_INTERRUPT_STATUS_RECEIVE_ACTIVE           1
+
+/* SSP 1 */
+
+#define SSP_1_CONTROL_0                                 0x020100
+#define SSP_1_CONTROL_0_CLOCK_RATE                      15:8
+#define SSP_1_CONTROL_0_SCLKOUT_PHASE                   7:7
+#define SSP_1_CONTROL_0_SCLKOUT_PHASE_0                 0
+#define SSP_1_CONTROL_0_SCLKOUT_PHASE_1                 1
+#define SSP_1_CONTROL_0_SCLKOUT_POLARITY                6:6
+#define SSP_1_CONTROL_0_SCLKOUT_POLARITY_RISING         0
+#define SSP_1_CONTROL_0_SCLKOUT_POLARITY_FALLING        1
+#define SSP_1_CONTROL_0_FRAME_FORMAT                    5:4
+#define SSP_1_CONTROL_0_FRAME_FORMAT_MOTOROLA           0
+#define SSP_1_CONTROL_0_FRAME_FORMAT_TI                 1
+#define SSP_1_CONTROL_0_FRAME_FORMAT_NATIONAL           2
+#define SSP_1_CONTROL_0_DATA_SIZE                       3:0
+#define SSP_1_CONTROL_0_DATA_SIZE_4                     3
+#define SSP_1_CONTROL_0_DATA_SIZE_5                     4
+#define SSP_1_CONTROL_0_DATA_SIZE_6                     5
+#define SSP_1_CONTROL_0_DATA_SIZE_7                     6
+#define SSP_1_CONTROL_0_DATA_SIZE_8                     7
+#define SSP_1_CONTROL_0_DATA_SIZE_9                     8
+#define SSP_1_CONTROL_0_DATA_SIZE_10                    9
+#define SSP_1_CONTROL_0_DATA_SIZE_11                    10
+#define SSP_1_CONTROL_0_DATA_SIZE_12                    11
+#define SSP_1_CONTROL_0_DATA_SIZE_13                    12
+#define SSP_1_CONTROL_0_DATA_SIZE_14                    13
+#define SSP_1_CONTROL_0_DATA_SIZE_15                    14
+#define SSP_1_CONTROL_0_DATA_SIZE_16                    15
+
+#define SSP_1_CONTROL_1                                 0x020104
+#define SSP_1_CONTROL_1_SLAVE_OUTPUT                    6:6
+#define SSP_1_CONTROL_1_SLAVE_OUTPUT_ENABLE             0
+#define SSP_1_CONTROL_1_SLAVE_OUTPUT_DISABLE            1
+#define SSP_1_CONTROL_1_MODE_SELECT                     5:5
+#define SSP_1_CONTROL_1_MODE_SELECT_MASTER              0
+#define SSP_1_CONTROL_1_MODE_SELECT_SLAVE               1
+#define SSP_1_CONTROL_1_STATUS                          4:4
+#define SSP_1_CONTROL_1_STATUS_DISABLE                  0
+#define SSP_1_CONTROL_1_STATUS_ENABLE                   1
+#define SSP_1_CONTROL_1_LOOP_BACK                       3:3
+#define SSP_1_CONTROL_1_LOOP_BACK_DISABLE               0
+#define SSP_1_CONTROL_1_LOOP_BACK_ENABLE                1
+#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT               2:2
+#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT_DISABLE       0
+#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT_ENABLE        1
+#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT              1:1
+#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT_DISABLE      0
+#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT_ENABLE       1
+#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT               0:0
+#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT_DISABLE       0
+#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT_ENABLE        1
+
+#define SSP_1_DATA                                      0x020108
+#define SSP_1_DATA_DATA                                 15:0
+
+#define SSP_1_STATUS                                    0x02010C
+#define SSP_1_STATUS_STATUS                             4:4
+#define SSP_1_STATUS_STATUS_IDLE                        0
+#define SSP_1_STATUS_STATUS_BUSY                        1
+#define SSP_1_STATUS_RECEIVE_FIFO                       3:2
+#define SSP_1_STATUS_RECEIVE_FIFO_EMPTY                 0
+#define SSP_1_STATUS_RECEIVE_FIFO_NOT_EMPTY             1
+#define SSP_1_STATUS_RECEIVE_FIFO_FULL                  3
+#define SSP_1_STATUS_TRANSMIT_FIFO                      1:0
+#define SSP_1_STATUS_TRANSMIT_FIFO_FULL                 0
+#define SSP_1_STATUS_TRANSMIT_FIFO_NOT_FULL             2
+#define SSP_1_STATUS_TRANSMIT_FIFO_EMPTY                3
+
+#define SSP_1_CLOCK_PRESCALE                            0x020110
+#define SSP_1_CLOCK_PRESCALE_DIVISOR                    7:0
+
+#define SSP_1_INTERRUPT_STATUS                          0x020114
+#define SSP_1_INTERRUPT_STATUS_OVERRUN                  2:2
+#define SSP_1_INTERRUPT_STATUS_OVERRUN_NOT_ACTIVE       0
+#define SSP_1_INTERRUPT_STATUS_OVERRUN_ACTIVE           1
+#define SSP_1_INTERRUPT_STATUS_OVERRUN_CLEAR            1
+#define SSP_1_INTERRUPT_STATUS_TRANSMIT                 1:1
+#define SSP_1_INTERRUPT_STATUS_TRANSMIT_NOT_ACTIVE      0
+#define SSP_1_INTERRUPT_STATUS_TRANSMIT_ACTIVE          1
+#define SSP_1_INTERRUPT_STATUS_RECEIVE                  0:0
+#define SSP_1_INTERRUPT_STATUS_RECEIVE_NOT_ACTIVE       0
+#define SSP_1_INTERRUPT_STATUS_RECEIVE_ACTIVE           1
+
+//#include "regdc.h"
+
+
+#define HDMI_CONTROL									0x0800C4
+#define HDMI_CONTROL_MODE_SELECT						7:4
+#define HDMI_CONTROL_MODE_SELECT_A						1
+#define HDMI_CONTROL_MODE_SELECT_B						2
+#define HDMI_CONTROL_MODE_SELECT_D						4
+#define HDMI_CONTROL_MODE_SELECT_E						8
+#define HDMI_CONTROL_PLLB								3:3
+#define HDMI_CONTROL_PLLB_NORMAL						0
+#define HDMI_CONTROL_PLLB_RESET							1
+#define HDMI_CONTROL_PLLA								2:2
+#define HDMI_CONTROL_PLLA_NORMAL						0
+#define HDMI_CONTROL_PLLA_RESET							1
+#define HDMI_CONTROL_INTMODE							1:1
+#define HDMI_CONTROL_INT_MODE_OPEN						0
+#define HDMI_CONTROL_INT_MODE_PULL						1
+#define HDMI_CONTROL_INT_POLARITY						0:0
+#define HDMI_CONTROL_INT_POLARITY_LOW					0
+#define HDMI_CONTROL_INT_POLARITY_HIGH					1
+
+#define HDMI_CONFIG										0x0800C0
+#define HDMI_CONFIG_READ								17:17
+#define HDMI_CONFIG_READ_LATCH							0
+#define HDMI_CONFIG_READ_ENABLE							1
+#define HDMI_CONFIG_WRITE								16:16
+#define HDMI_CONFIG_WRITE_LATCH							0
+#define HDMI_CONFIG_WRITE_ENABLE						1
+#define HDMI_CONFIG_DATA								15:8
+#define HDMI_CONFIG_ADDRESS								7:0
+
+
+
+
+#define DISPLAY_CTRL                            0x080000
+#define DISPLAY_CTRL_DPMS                         31:30
+#define DISPLAY_CTRL_DPMS_VPHP                       0
+#define DISPLAY_CTRL_DPMS_VPHN                       1
+#define DISPLAY_CTRL_DPMS_VNHP                       2
+#define DISPLAY_CTRL_DPMS_VNHN                       3
+#define DISPLAY_CTRL_DATA_PATH                 29:29
+#define DISPLAY_CTRL_DATA_PATH_VGA    	         0
+#define DISPLAY_CTRL_DATA_PATH_EXTENDED         1
+#define DISPLAY_CTRL_DIRECTION                   28:28
+#define DISPLAY_CTRL_DIRECTION_INPUT             	 0
+#define DISPLAY_CTRL_DIRECTION_OUTPUT                1
+#define DISPLAY_CTRL_FPEN                       27:27
+#define DISPLAY_CTRL_FPEN_LOW                   0
+#define DISPLAY_CTRL_FPEN_HIGH                  1
+#define DISPLAY_CTRL_VBIASEN                    26:26
+#define DISPLAY_CTRL_VBIASEN_LOW                0
+#define DISPLAY_CTRL_VBIASEN_HIGH               1
+#define DISPLAY_CTRL_DATA                       25:25
+#define DISPLAY_CTRL_DATA_DISABLE               0
+#define DISPLAY_CTRL_DATA_ENABLE                1
+#define DISPLAY_CTRL_FPVDDEN                    24:24
+#define DISPLAY_CTRL_FPVDDEN_LOW                0
+#define DISPLAY_CTRL_FPVDDEN_HIGH               1
+#define DISPLAY_CTRL_CAPTURE_DATA_SELECT	                    23:23
+#define DISPLAY_CTRL_CAPTURE_DATA_SELECT_CHANNEL0              0
+#define DISPLAY_CTRL_CAPTURE_DATA_SELECT_CHANNEL1              1
+#define DISPLAY_CTRL_LOOP_BACK_SELECT              			22:22
+#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL0        			0
+#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL1        			1
+#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT         			21:20
+#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL0_24BIT      0
+#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL1_24BIT      1
+#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL0_48BIT      2
+#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL1_48BIT      3
+#define DISPLAY_CTRL_HDMI_CLK                   19:19
+#define DISPLAY_CTRL_HDMI_CLK_NEG               0
+#define DISPLAY_CTRL_HDMI_CLK_POS               1
+#define DISPLAY_CTRL_HDMI_SELECT				18:18
+#define DISPLAY_CTRL_HDMI_SELECT_CHANNEL0		0
+#define DISPLAY_CTRL_HDMI_SELECT_CHANNEL1		1
+#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT						17:16
+#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL0_24BIT		0
+#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL1_24BIT		1
+#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL0_48BIT		2
+#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL1_48BIT		3
+#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT         15:15
+#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT_SINGLE  0
+#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT_HALF    1
+#define DISPLAY_CTRL_CLOCK_PHASE                14:14
+#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH    0
+#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW     1
+#define DISPLAY_CTRL_VSYNC_PHASE                13:13
+#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH    0
+#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW     1
+#define DISPLAY_CTRL_HSYNC_PHASE                12:12
+#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH    0
+#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW     1
+#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK         11:11
+#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_DISABLE 0
+#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_ENABLE  1
+#define DISPLAY_CTRL_VSYNC						11:11
+#define DISPLAY_CTRL_VSYNC_INACTIVE				0
+#define DISPLAY_CTRL_VSYNC_ACTIVE				1
+#define DISPLAY_CTRL_DAC_FORMAT	             10:10
+#define DISPLAY_CTRL_DAC_FORMAT_6BIT		     0
+#define DISPLAY_CTRL_DAC_FORMAT_8BIT		     1
+#define DISPLAY_CTRL_COLOR_KEY                  9:9
+#define DISPLAY_CTRL_COLOR_KEY_DISABLE          0
+#define DISPLAY_CTRL_COLOR_KEY_ENABLE           1
+#define DISPLAY_CTRL_TIMING                     8:8
+#define DISPLAY_CTRL_TIMING_DISABLE             0
+#define DISPLAY_CTRL_TIMING_ENABLE              1
+#define DISPLAY_CTRL_PIXEL                      7:4
+#define DISPLAY_CTRL_GAMMA                      3:3
+#define DISPLAY_CTRL_GAMMA_DISABLE              0
+#define DISPLAY_CTRL_GAMMA_ENABLE               1
+#define DISPLAY_CTRL_PLANE                      2:2
+#define DISPLAY_CTRL_PLANE_DISABLE              0
+#define DISPLAY_CTRL_PLANE_ENABLE               1
+#define DISPLAY_CTRL_FORMAT                     1:0
+#define DISPLAY_CTRL_FORMAT_8                   0
+#define DISPLAY_CTRL_FORMAT_16                  1
+#define DISPLAY_CTRL_FORMAT_32                  2
+
+#define FB_ADDRESS                              0x080004
+#define FB_ADDRESS_STATUS                       31:31
+#define FB_ADDRESS_STATUS_CURRENT               0
+#define FB_ADDRESS_STATUS_PENDING               1
+#define FB_ADDRESS_ADDRESS                      29:0
+
+#define CHANNEL1_FB_ADDRESS   					0x088004
+#define CHANNEL1_FB_ADDRESS_STATUS                       31:31
+#define CHANNEL1_FB_ADDRESS_STATUS_CURRENT               0
+#define CHANNEL1_FB_ADDRESS_STATUS_PENDING               1
+#define CHANNEL1_FB_ADDRESS_ADDRESS                      29:0
+
+
+
+#define FB_WIDTH                                0x080008
+#define FB_WIDTH_WIDTH                          29:16
+#define FB_WIDTH_OFFSET                         13:0
+
+#define HORIZONTAL_TOTAL                        0x08000C
+#define HORIZONTAL_TOTAL_TOTAL                  28:16
+#define HORIZONTAL_TOTAL_DISPLAY_END            11:0
+
+#define HORIZONTAL_SYNC                         0x080010
+#define HORIZONTAL_SYNC_WIDTH                   25:16
+#define HORIZONTAL_SYNC_START                   12:0
+
+#define VERTICAL_TOTAL                          0x080014
+#define VERTICAL_TOTAL_TOTAL                    27:16
+#define VERTICAL_TOTAL_DISPLAY_END              11:0
+
+#define VERTICAL_SYNC                           0x080018
+#define VERTICAL_SYNC_HEIGHT                    21:16
+#define VERTICAL_SYNC_START                     11:0
+
+#define CURRENT_LINE                            0x080020
+#define CURRENT_LINE_LINE                       11:0
+
+
+#define LVDS_CTRL1						0x80020
+#define LVDS_CTRL1_CLKSEL_PLL2			31:31
+#define LVDS_CTRL1_CLKSEL_PLL2_RE		0
+#define LVDS_CTRL1_CLKSEL_PLL2_FE		1
+#define LVDS_CTRL1_CLKSEL_PLL1			30:30
+#define LVDS_CTRL1_CLKSEL_PLL1_RE		0
+#define LVDS_CTRL1_CLKSEL_PLL1_FE		1
+#define LVDS_CTRL1_DCLK2				29:23
+#define LVDS_CTRL1_DCLK2_DEFAULT		0x63
+#define LVDS_CTRL1_DCLK1				22:16
+#define LVDS_CTRL1_DCLK1_DEFAULT		0x63
+#define LVDS_CTRL1_PLL2_LOCK			15:15
+#define LVDS_CTRL1_PLL1_LOCK			14:14
+#define LVDS_CTRL1_POR25				13:13
+#define LVDS_CTRL1_POR12				12:12
+
+
+
+#define CRT_DETECT                     0x080024
+#define CRT_DETECT_DAC				   31:31
+#define CRT_DETECT_DAC_ENABLE		   0
+#define CRT_DETECT_DAC_DOWN			   1
+#define CRT_DETECT_CRT_CLK             27:27
+#define CRT_DETECT_CRT_CLK_POS         0
+#define CRT_DETECT_CRT_CLK_NEG         1   
+#define CRT_DETECT_LVDS_CLK            26:26
+#define CRT_DETECT_LVDS_CLK_POS		   0
+#define CRT_DETECT_LVDS_CLK_NEG		   1
+#define CRT_DETECT_CRT                 25:25
+#define CRT_DETECT_CRT_ABSENT          0
+#define CRT_DETECT_CRT_PRESENT         1
+#define CRT_DETECT_ENABLE              24:24
+#define CRT_DETECT_ENABLE_DISABLE      0
+#define CRT_DETECT_ENABLE_ENABLE       1
+#define CRT_DETECT_DATA_RED            23:16
+#define CRT_DETECT_DATA_GREEN          15:8
+#define CRT_DETECT_DATA_BLUE           7:0
+
+#define COLOR_KEY                               0x080028
+#define COLOR_KEY_MASK                          31:16
+#define COLOR_KEY_VALUE                         15:0
+
+#define LVDS_CTRL2							0x08002C
+#define LVDS_CTRL2_SHTDNB2					30:30
+#define LVDS_CTRL2_SHTDNB2_RESET			0
+#define LVDS_CTRL2_SHTDNB2_NORMAL			1
+#define LVDS_CTRL2_SHTDNB1					29:29
+#define LVDS_CTRL2_SHTDNB1_RESET			0
+#define LVDS_CTRL2_SHTDNB1_NORMAL			1
+#define LVDS_CTRL2_CLK2_DS 				    28:27
+#define LVDS_CTRL2_CLK2_DS_3MA				0
+#define LVDS_CTRL2_CLK2_DS_1MA				1
+#define LVDS_CTRL2_CLK2_DS_5MA				2
+#define LVDS_CTRL2_CLK2_DS_2MA				3
+#define LVDS_CTRL2_CLK1_DS 					26:25
+#define LVDS_CTRL2_CLK1_DS_3MA				0
+#define LVDS_CTRL2_CLK1_DS_1MA				1
+#define LVDS_CTRL2_CLK1_DS_5MA				2
+#define LVDS_CTRL2_CLK1_DS_2MA				3
+#define LVDS_CTRL2_DS						24:23
+#define LVDS_CTRL2_DS_3MA					0
+#define LVDS_CTRL2_DS_1MA					1
+#define LVDS_CTRL2_DS_5MA					2
+#define LVDS_CTRL2_DS_2MA					3
+#define LVDS_CTRL2_CLK2_TR					22:22
+#define LVDS_CTRL2_CLK2_TR_0				0
+#define LVDS_CTRL2_CLK2_TR_100				1
+#define LVDS_CTRL2_CLK1_TR					21:21
+#define LVDS_CTRL2_CLK1_TR_0				0
+#define LVDS_CTRL2_CLK1_TR_100				1
+#define LVDS_CTRL2_TR						20:20
+#define LVDS_CTRL2_TR_0						0
+#define LVDS_CTRL2_TR_100					1
+#define LVDS_CTRL2_CLK2_COMP				19:18
+#define LVDS_CTRL2_CLK2_COMP_0				0
+#define LVDS_CTRL2_CLK2_COMP_1				1
+#define LVDS_CTRL2_CLK2_COMP_2				2
+#define LVDS_CTRL2_CLK2_COMP_3				3
+#define LVDS_CTRL2_CLK1_COMP				17:16
+#define LVDS_CTRL2_CLK1_COMP_0				0
+#define LVDS_CTRL2_CLK1_COMP_1				1
+#define LVDS_CTRL2_CLK1_COMP_2				2
+#define LVDS_CTRL2_CLK1_COMP_3				3
+#define LVDS_CTRL2_PRE_COMP					15:14
+#define LVDS_CTRL2_PRE_COMP_0				0
+#define LVDS_CTRL2_PRE_COMP_1				1
+#define LVDS_CTRL2_PRE_COMP_2				2
+#define LVDS_CTRL2_PRE_COMP_3				3
+#define LVDS_CTRL2_VCOS_PLL2				13:11
+#define LVDS_CTRL2_VCOS_PLL2_10M			0
+#define LVDS_CTRL2_VCOS_PLL2_20M			1
+#define LVDS_CTRL2_VCOS_PLL2_40M			2
+#define LVDS_CTRL2_VCOS_PLL2_80M			3
+#define LVDS_CTRL2_VCOS_PLL2_160M			4
+#define LVDS_CTRL2_VCOS_PLL2_350M			5
+#define LVDS_CTRL2_VCOS_PLL1				10:8
+#define LVDS_CTRL2_VCOS_PLL1_10M			0
+#define LVDS_CTRL2_VCOS_PLL1_20M			1
+#define LVDS_CTRL2_VCOS_PLL1_40M			2
+#define LVDS_CTRL2_VCOS_PLL1_80M			3
+#define LVDS_CTRL2_VCOS_PLL1_160M			4
+#define LVDS_CTRL2_VCOS_PLL1_350M			5
+#define LVDS_CTRL2_SHORTS_PLL2				7:6
+#define LVDS_CTRL2_SHORTS_PLL2_2048			0
+#define LVDS_CTRL2_SHORTS_PLL2_1024			1
+#define LVDS_CTRL2_SHORTS_PLL2_512			2
+#define LVDS_CTRL2_SHORTS_PLL2_256			3
+#define LVDS_CTRL2_SHORTS_PLL1				5:4
+#define LVDS_CTRL2_SHORTS_PLL1_2048			0
+#define LVDS_CTRL2_SHORTS_PLL1_1024			1
+#define LVDS_CTRL2_SHORTS_PLL1_512			2
+#define LVDS_CTRL2_SHORTS_PLL1_256			3
+#define LVDS_CTRL2_PD_PLL2					3:3
+#define LVDS_CTRL2_PD_PLL2_NORMAL			0
+#define LVDS_CTRL2_PD_PLL2_DOWN				1
+#define LVDS_CTRL2_PD_PLL1					2:2
+#define LVDS_CTRL2_PD_PLL1_NORMAL			0
+#define LVDS_CTRL2_PD_PLL1_DOWN				1
+#define LVDS_CTRL2_MODESEL2					1:1
+#define LVDS_CTRL2_MODESEL2_DC0				0
+#define LVDS_CTRL2_MODESEL2_DC1				1
+#define LVDS_CTRL2_MODESEL1					0:0
+#define LVDS_CTRL2_MODESEL1_DC0				0
+#define LVDS_CTRL2_MODESEL1_DC1				1
+
+
+
+
+
+/* Cursor Control */
+#define HWC_CONTROL                             0x080030
+#define HWC_CONTROL_MODE                        31:30
+#define HWC_CONTROL_MODE_DISABLE                0
+#define HWC_CONTROL_MODE_MASK                   1
+#define HWC_CONTROL_MODE_MONO                   2
+#define HWC_CONTROL_MODE_ALPHA                  3
+#define HWC_CONTROL_ADDRESS                     29:0
+
+#define HWC_LOCATION                            0x080034
+#define HWC_LOCATION_TOP                        31:31
+#define HWC_LOCATION_TOP_INSIDE                 0
+#define HWC_LOCATION_TOP_OUTSIDE                1
+#define HWC_LOCATION_Y                          27:16
+#define HWC_LOCATION_LEFT                       15:15
+#define HWC_LOCATION_LEFT_INSIDE                0
+#define HWC_LOCATION_LEFT_OUTSIDE               1
+#define HWC_LOCATION_X                          11:0
+
+#define HWC_COLOR0                              0x080038
+#define HWC_COLOR0_RGB888                       23:0
+
+#define HWC_COLOR1                              0x08003C
+#define HWC_COLOR1_RGB888                       23:0
+
+
+/* Channel0 Cursor Control */
+#define CHANNEL0_HWC_ADDRESS                             0x080030
+#define CHANNEL0_HWC_ADDRESS_ENABLE                      31:30
+#define CHANNEL0_HWC_ADDRESS_ENABLE_DISABLE              0
+#define CHANNEL0_HWC_ADDRESS_ENABLE_MASK	             1
+#define CHANNEL0_HWC_ADDRESS_ENABLE_MONO	             2
+#define CHANNEL0_HWC_ADDRESS_ENABLE_ALPHA	             3
+#define CHANNEL0_HWC_ADDRESS_ADDRESS                     29:0
+
+#define CHANNEL0_HWC_LOCATION                            0x080034
+#define CHANNEL0_HWC_LOCATION_TOP                        31:31
+#define CHANNEL0_HWC_LOCATION_TOP_INSIDE                 0
+#define CHANNEL0_HWC_LOCATION_TOP_OUTSIDE                1
+#define CHANNEL0_HWC_LOCATION_Y                          27:16
+#define CHANNEL0_HWC_LOCATION_LEFT                       15:15
+#define CHANNEL0_HWC_LOCATION_LEFT_INSIDE                0
+#define CHANNEL0_HWC_LOCATION_LEFT_OUTSIDE               1
+#define CHANNEL0_HWC_LOCATION_X                          11:0
+
+#define CHANNEL0_HWC_COLOR_0                            0x080038
+#define CHANNEL0_HWC_COLOR_0_RGB888		                23:0
+
+#define CHANNEL0_HWC_COLOR_1                            0x08003C
+#define CHANNEL0_HWC_COLOR_1_RGB888                   	23:0
+
+/* Channel1 Cursor Control */
+#define CHANNEL1_HWC_ADDRESS                             0x088030
+#define CHANNEL1_HWC_ADDRESS_ENABLE                      31:30
+#define CHANNEL1_HWC_ADDRESS_ENABLE_DISABLE              0
+#define CHANNEL1_HWC_ADDRESS_ENABLE_MASK	             1
+#define CHANNEL1_HWC_ADDRESS_ENABLE_MONO	             2
+#define CHANNEL1_HWC_ADDRESS_ENABLE_ALPHA	             3
+#define CHANNEL1_HWC_ADDRESS_ADDRESS                     29:0
+
+#define CHANNEL1_HWC_LOCATION                            0x088034
+#define CHANNEL1_HWC_LOCATION_TOP                        31:31
+#define CHANNEL1_HWC_LOCATION_TOP_INSIDE                 0
+#define CHANNEL1_HWC_LOCATION_TOP_OUTSIDE                1
+#define CHANNEL1_HWC_LOCATION_Y                          27:16
+#define CHANNEL1_HWC_LOCATION_LEFT                       15:15
+#define CHANNEL1_HWC_LOCATION_LEFT_INSIDE                0
+#define CHANNEL1_HWC_LOCATION_LEFT_OUTSIDE               1
+#define CHANNEL1_HWC_LOCATION_X                          11:0
+
+#define CHANNEL1_HWC_COLOR_0                            0x088038
+#define CHANNEL1_HWC_COLOR_0_RGB888		                23:0
+
+#define CHANNEL1_HWC_COLOR_1                            0x08803C
+#define CHANNEL1_HWC_COLOR_1_RGB888                   	23:0
+
+
+/* Video Control */
+#define VIDEO_DISPLAY_CTRL                              0x080040
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP                    12:12
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_DISABLE            0
+#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_ENABLE             1
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE                9:9
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE      0
+#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE    1
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE              8:8
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE    0
+#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE  1
+#define VIDEO_DISPLAY_CTRL_PIXEL                        7:4
+#define VIDEO_DISPLAY_CTRL_GAMMA                        3:3
+#define VIDEO_DISPLAY_CTRL_GAMMA_DISABLE                0
+#define VIDEO_DISPLAY_CTRL_GAMMA_ENABLE                 1
+#define VIDEO_DISPLAY_CTRL_PLANE                        2:2
+#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE                0
+#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE                 1
+#define VIDEO_DISPLAY_CTRL_FORMAT                       1:0
+#define VIDEO_DISPLAY_CTRL_FORMAT_16                    0
+#define VIDEO_DISPLAY_CTRL_FORMAT_32                    1
+#define VIDEO_DISPLAY_CTRL_FORMAT_YUV422                2
+#define VIDEO_DISPLAY_CTRL_FORMAT_YUV420                3
+
+#define VIDEO_FB_ADDRESS                              0x080044
+#define VIDEO_FB_ADDRESS_STATUS                       31:31
+#define VIDEO_FB_ADDRESS_STATUS_CURRENT               0
+#define VIDEO_FB_ADDRESS_STATUS_PENDING               1
+#define VIDEO_FB_ADDRESS_ADDRESS                      29:0
+
+#define VIDEO_FB_WIDTH                                0x080048
+#define VIDEO_FB_WIDTH_WIDTH                          29:16
+#define VIDEO_FB_WIDTH_OFFSET                         13:0
+
+#define VIDEO_FB_ADDRESS_Y                            0x080044
+#define VIDEO_FB_ADDRESS_Y_ADDRESS                    29:0
+
+#define VIDEO_FB_WIDTH_Y                              0x080048
+#define VIDEO_FB_WIDTH_Y_WIDTH                        29:16
+#define VIDEO_FB_WIDTH_Y_OFFSET                       13:0
+
+
+#define VIDEO_FB_ADDRESS_U                            0x08004C
+#define VIDEO_FB_ADDRESS_U_ADDRESS                    29:0
+
+#define VIDEO_FB_WIDTH_U                              0x080050
+#define VIDEO_FB_WIDTH_U_WIDTH                        29:16
+#define VIDEO_FB_WIDTH_U_OFFSET                       13:0
+
+#define VIDEO_FB_ADDRESS_V                            0x080054
+#define VIDEO_FB_ADDRESS_V_ADDRESS                    29:0
+
+#define VIDEO_FB_WIDTH_V                              0x080058
+#define VIDEO_FB_WIDTH_V_WIDTH                        29:16
+#define VIDEO_FB_WIDTH_V_OFFSET                       13:0
+
+#define VIDEO_YUV_CONSTANTS                           0x08005C
+#define VIDEO_YUV_CONSTANTS_Y                         31:24
+#define VIDEO_YUV_CONSTANTS_R                         23:16
+#define VIDEO_YUV_CONSTANTS_G                         15:8
+#define VIDEO_YUV_CONSTANTS_B                         7:0
+
+#define VIDEO_PLANE_TL                                  0x080060
+#define VIDEO_PLANE_TL_TOP                              26:16
+#define VIDEO_PLANE_TL_LEFT                             11:0
+
+#define VIDEO_PLANE_BR                                  0x080064
+#define VIDEO_PLANE_BR_BOTTOM                           26:16
+#define VIDEO_PLANE_BR_RIGHT                            11:0
+
+#define VIDEO_SCALE                                     0x080068
+#define VIDEO_SCALE_VERTICAL_SCALE                      27:16
+#define VIDEO_SCALE_HORIZONTAL_SCALE                    11:0
+
+#define VIDEO_INITIAL_SCALE                             0x08006C
+#define VIDEO_INITIAL_SCALE_VERTICAL                    27:16
+#define VIDEO_INITIAL_SCALE_HORIZONTAL                     11:0
+
+/* Video Alpha Control */
+#if 1
+#define VIDEO_ALPHA_DISPLAY_CTRL                        0x080080
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT                 28:28
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL       0
+#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_ALPHA           1
+#define VIDEO_ALPHA_DISPLAY_CTRL_ALPHA                  27:24
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO                   17:16
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_1                 0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_3                 1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_7                 2
+#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_11                3
+#define VIDEO_ALPHA_DISPLAY_CTRL_PIXEL                  7:4
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY             3:3
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE     0
+#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE      1
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE                  2:2
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_DISABLE          0
+#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_ENABLE           1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT                 1:0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_8               0
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_16              1
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4       2
+#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4   3
+
+#define VIDEO_ALPHA_FB_ADDRESS                          0x080084
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS                   31:31
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS_CURRENT           0
+#define VIDEO_ALPHA_FB_ADDRESS_STATUS_PENDING           1
+#define VIDEO_ALPHA_FB_ADDRESS_ADDRESS                  29:0
+
+#define VIDEO_ALPHA_FB_WIDTH                            0x080088
+#define VIDEO_ALPHA_FB_WIDTH_WIDTH                      29:16
+#define VIDEO_ALPHA_FB_WIDTH_OFFSET                     13:0
+
+#define VIDEO_ALPHA_PLANE_TL                            0x08008C
+#define VIDEO_ALPHA_PLANE_TL_TOP                        26:16
+#define VIDEO_ALPHA_PLANE_TL_LEFT                       11:0
+
+#define VIDEO_ALPHA_PLANE_BR                            0x080090
+#define VIDEO_ALPHA_PLANE_BR_BOTTOM                     26:16
+#define VIDEO_ALPHA_PLANE_BR_RIGHT                      11:0
+
+#define VIDEO_ALPHA_CHROMA_KEY                          0x080094
+#define VIDEO_ALPHA_CHROMA_KEY_MASK                     31:16
+#define VIDEO_ALPHA_CHROMA_KEY_VALUE                    15:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_01                     0x080098
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_23                     0x08009C
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_45                     0x0800A0
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_67                     0x0800A4
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_89                     0x0800A8
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB                     0x0800AC
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD                     0x0800B0
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_BLUE              4:0
+
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF                     0x0800B4
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F                   31:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_RED               31:27
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_GREEN             26:21
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_BLUE              20:16
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E                   15:0
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_RED               15:11
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_GREEN             10:5
+#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_BLUE              4:0
+#endif
+
+/* Alpha Control */
+
+#define ALPHA_DISPLAY_CTRL                              0x080080
+#define ALPHA_DISPLAY_CTRL_SELECT                       28:28
+#define ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL             0
+#define ALPHA_DISPLAY_CTRL_SELECT_ALPHA                 1
+#define ALPHA_DISPLAY_CTRL_ALPHA                        27:24
+#define ALPHA_DISPLAY_CTRL_FIFO                         17:16
+#define ALPHA_DISPLAY_CTRL_FIFO_1                       0
+#define ALPHA_DISPLAY_CTRL_FIFO_3                       1
+#define ALPHA_DISPLAY_CTRL_FIFO_7                       2
+#define ALPHA_DISPLAY_CTRL_FIFO_11                      3
+#define ALPHA_DISPLAY_CTRL_PIXEL                        7:4
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY                   3:3
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE           0
+#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE            1
+#define ALPHA_DISPLAY_CTRL_PLANE                        2:2
+#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE                0
+#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE                 1
+#define ALPHA_DISPLAY_CTRL_FORMAT                       1:0
+#define ALPHA_DISPLAY_CTRL_FORMAT_16                    1
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4             2
+#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4         3
+
+#define ALPHA_FB_ADDRESS                                0x080084
+#define ALPHA_FB_ADDRESS_STATUS                         31:31
+#define ALPHA_FB_ADDRESS_STATUS_CURRENT                 0
+#define ALPHA_FB_ADDRESS_STATUS_PENDING                 1
+#define ALPHA_FB_ADDRESS_ADDRESS                        29:0
+
+#define ALPHA_FB_WIDTH                                  0x080088
+#define ALPHA_FB_WIDTH_WIDTH                            29:16
+#define ALPHA_FB_WIDTH_OFFSET                           13:0
+
+#define ALPHA_PLANE_TL                                  0x08008C
+#define ALPHA_PLANE_TL_TOP                              26:16
+#define ALPHA_PLANE_TL_LEFT                             10:0
+
+#define ALPHA_PLANE_BR                                  0x080090
+#define ALPHA_PLANE_BR_BOTTOM                           26:16
+#define ALPHA_PLANE_BR_RIGHT                            10:0
+
+#define ALPHA_CHROMA_KEY                                0x080094
+#define ALPHA_CHROMA_KEY_MASK                           31:16
+#define ALPHA_CHROMA_KEY_VALUE                          15:0
+
+#define ALPHA_COLOR_LOOKUP_01                           0x080098
+#define ALPHA_COLOR_LOOKUP_01_1                         31:16
+#define ALPHA_COLOR_LOOKUP_01_1_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_01_1_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_01_1_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_01_0                         15:0
+#define ALPHA_COLOR_LOOKUP_01_0_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_01_0_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_01_0_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_23                           0x08009C
+#define ALPHA_COLOR_LOOKUP_23_3                         31:16
+#define ALPHA_COLOR_LOOKUP_23_3_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_23_3_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_23_3_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_23_2                         15:0
+#define ALPHA_COLOR_LOOKUP_23_2_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_23_2_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_23_2_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_45                           0x0800a0
+#define ALPHA_COLOR_LOOKUP_45_5                         31:16
+#define ALPHA_COLOR_LOOKUP_45_5_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_45_5_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_45_5_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_45_4                         15:0
+#define ALPHA_COLOR_LOOKUP_45_4_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_45_4_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_45_4_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_67                           0x0800a4
+#define ALPHA_COLOR_LOOKUP_67_7                         31:16
+#define ALPHA_COLOR_LOOKUP_67_7_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_67_7_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_67_7_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_67_6                         15:0
+#define ALPHA_COLOR_LOOKUP_67_6_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_67_6_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_67_6_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_89                           0x0800a8
+#define ALPHA_COLOR_LOOKUP_89_9                         31:16
+#define ALPHA_COLOR_LOOKUP_89_9_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_89_9_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_89_9_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_89_8                         15:0
+#define ALPHA_COLOR_LOOKUP_89_8_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_89_8_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_89_8_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_AB                           0x0800AC
+#define ALPHA_COLOR_LOOKUP_AB_B                         31:16
+#define ALPHA_COLOR_LOOKUP_AB_B_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_AB_B_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_AB_B_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_AB_A                         15:0
+#define ALPHA_COLOR_LOOKUP_AB_A_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_AB_A_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_AB_A_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_CD                           0x0800B0
+#define ALPHA_COLOR_LOOKUP_CD_D                         31:16
+#define ALPHA_COLOR_LOOKUP_CD_D_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_CD_D_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_CD_D_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_CD_C                         15:0
+#define ALPHA_COLOR_LOOKUP_CD_C_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_CD_C_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_CD_C_BLUE                    4:0
+
+#define ALPHA_COLOR_LOOKUP_EF                           0x0800B4
+#define ALPHA_COLOR_LOOKUP_EF_F                         31:16
+#define ALPHA_COLOR_LOOKUP_EF_F_RED                     31:27
+#define ALPHA_COLOR_LOOKUP_EF_F_GREEN                   26:21
+#define ALPHA_COLOR_LOOKUP_EF_F_BLUE                    20:16
+#define ALPHA_COLOR_LOOKUP_EF_E                         15:0
+#define ALPHA_COLOR_LOOKUP_EF_E_RED                     15:11
+#define ALPHA_COLOR_LOOKUP_EF_E_GREEN                   10:5
+#define ALPHA_COLOR_LOOKUP_EF_E_BLUE                    4:0
+
+/* Distance between channel 1 and channel 2 display control */
+#define CHANNEL_OFFSET 0x8000
+
+#define DC_OFFSET 0x8000
+
+
+/* Palette RAM */
+/* Panel Pallete register starts at 0x080400 ~ 0x0807FC */
+#define CHANNEL0_PALETTE_RAM                            0x080C00
+#define PALETTE_RAM                             	    0x080C00
+
+/* Panel Pallete register starts at 0x080C00 ~ 0x080FFC */
+#define CHANNEL1_PALETTE_RAM                            0x088C00
+
+//#include "regdma.h"
+
+/* New DMA engine definition for Falcon */
+/* DMA 0 is uni-directional from Serial ROM to local DDR only */
+#define DMA0_DESTINATION                                0x0D0000
+#define DMA0_DESTINATION_ADDRESS                        29:0
+
+#define DMA0_SOURCE                                     0x0D0004
+#define DMA0_SOURCE_ADDRESS                             23:0
+
+#define DMA0_CONTROL                                    0x0D0008
+#define DMA0_CONTROL_STATUS                             31:31
+#define DMA0_CONTROL_STATUS_IDLE                        0
+#define DMA0_CONTROL_STATUS_ENABLE                      1
+#define DMA0_CONTROL_SIZE                               23:0
+
+/* DMA 1 can transfer from:
+   System to local DDR.
+   local DDR to system.
+   local DDR to local DDR.
+
+   The source is alwasy linear and the destination is always tiled.
+*/
+#define DMA1_SOURCE0                                    0x0D0010
+#define DMA1_SOURCE0_SEL                                31:31 
+#define DMA1_SOURCE0_SEL_LOCAL                          0
+#define DMA1_SOURCE0_SEL_SYSTEM                         1  
+#define DMA1_SOURCE0_DECODE                             30:30
+#define DMA1_SOURCE0_DECODE_DISABLE                     0
+#define DMA1_SOURCE0_DECODE_ENABLE                      1
+#define DMA1_SOURCE0_ADDRESS                            29:0
+
+#define DMA1_SOURCE0_SIZE                               0x0D0014
+#define DMA1_SOURCE0_SIZE_NSC_CSS                       27:27
+#define DMA1_SOURCE0_SIZE_NSC_CSS_DISABLE               0
+#define DMA1_SOURCE0_SIZE_NSC_CSS_ENABLE                1
+#define DMA1_SOURCE0_SIZE_NSC_CLL                       26:24
+#define DMA1_SOURCE0_SIZE_SIZE                          23:0
+
+#define DMA1_DESTINATION                                0x0D0018
+#define DMA1_DESTINATION_SEL                            31:31
+#define DMA1_DESTINATION_SEL_LOCAL                      0
+#define DMA1_DESTINATION_SEL_SYSTEM                     1 
+#define DMA1_DESTINATION_ADDRESS                        29:0
+
+#define DMA1_CONTROL                                    0x0D001C
+#define DMA1_CONTROL_STATUS                             31:31
+#define DMA1_CONTROL_STATUS_IDLE                        0 
+#define DMA1_CONTROL_STATUS_ENABLE                      1 
+#define DMA1_CONTROL_TRI_STREAM                         30:30
+#define DMA1_CONTROL_TRI_STREAM_DISABLE                 0
+#define DMA1_CONTROL_TRI_STREAM_ENABLE                  1
+#define DMA1_CONTROL_FORMAT                             29:28
+#define DMA1_CONTROL_FORMAT_8BPP                        0
+#define DMA1_CONTROL_FORMAT_16BPP                       1
+#define DMA1_CONTROL_FORMAT_32BPP                       2
+#define DMA1_CONTROL_TILE_HEIGHT                        27:16
+#define DMA1_CONTROL_TILE_WIDTH                         12:0
+
+#define DMA1_DESTINATION_PITCH                          0x0D0020
+#define DMA1_DESTINATION_PITCH_PITCH                    14:0
+
+#define DMA_CONTROL                                     0x0D0024
+#define DMA_CONTROL_NSC_RB_SWAP                         11:11
+#define DMA_CONTROL_NSC_RB_SWAP_DISABLE                 0
+#define DMA_CONTROL_NSC_RB_SWAP_ENABLE                  1
+#define DMA_CONTROL_CSC                                 10:10
+#define DMA_CONTROL_CSC_DISABLE                         0
+#define DMA_CONTROL_CSC_ENABLE                          1
+#define DMA_CONTROL_DECOMP                              9:8
+#define DMA_CONTROL_DECOMP_TEXT                         0
+#define DMA_CONTROL_DECOMP_NSC                          1
+#define DMA_CONTROL_DECOMP_GOLOMB                       2
+#define DMA_CONTROL_DMA1_STATUS                         5:5
+#define DMA_CONTROL_DMA1_STATUS_NORMAL                  0
+#define DMA_CONTROL_DMA1_STATUS_ABORT                   1
+#define DMA_CONTROL_DMA0_STATUS                         4:4
+#define DMA_CONTROL_DMA0_STATUS_NORMAL                  0
+#define DMA_CONTROL_DMA0_STATUS_ABORT                   1
+#define DMA_CONTROL_DMA1_RAWINT                         1:1
+#define DMA_CONTROL_DMA1_RAWINT_CLEAR                   0
+#define DMA_CONTROL_DMA1_RAWINT_SET                     1
+#define DMA_CONTROL_DMA0_RAWINT                         0:0
+#define DMA_CONTROL_DMA0_RAWINT_CLEAR                   0
+#define DMA_CONTROL_DMA0_RAWINT_SET                     1
+
+/* DMA 1 source 1 and source 2 are only used when RGB is in 3 separate planes.*/
+#define DMA1_SOURCE1                                    0x0D0028
+#define DMA1_SOURCE1_ADDRESS                            29:0
+
+#define DMA1_SOURCE1_SIZE                               0x0D002c
+#define DMA1_SOURCE1_SIZE_NSC_CSS                       27:27
+#define DMA1_SOURCE1_SIZE_NSC_CSS_DISABLE               0
+#define DMA1_SOURCE1_SIZE_NSC_CSS_ENABLE                1
+#define DMA1_SOURCE1_SIZE_NSC_CLL                       26:24
+#define DMA1_SOURCE1_SIZE_SIZE                          23:0
+
+#define DMA1_SOURCE2                                    0x0D0030
+#define DMA1_SOURCE2_ADDRESS                            29:0
+
+#define DMA1_SOURCE2_SIZE                               0x0D0034
+#define DMA1_SOURCE2_SIZE_NSC_CSS                       27:27
+#define DMA1_SOURCE2_SIZE_NSC_CSS_DISABLE               0
+#define DMA1_SOURCE2_SIZE_NSC_CSS_ENABLE                1
+#define DMA1_SOURCE2_SIZE_NSC_CLL                       26:24
+#define DMA1_SOURCE2_SIZE_SIZE                          23:0
+
+
+//#include "regde.h"
+/* 2D registers. */
+
+#define DE_SOURCE                                       0x100000
+#define DE_SOURCE_WRAP                                  31:31
+#define DE_SOURCE_WRAP_DISABLE                          0
+#define DE_SOURCE_WRAP_ENABLE                           1
+
+/* 
+ * The following definitions are used in different setting 
+ */
+
+/* Use these definitions in XY addressing mode or linear addressing mode. */
+#define DE_SOURCE_X_K1                                  27:16
+#define DE_SOURCE_Y_K2                                  11:0
+
+/* Use this definition in host write mode for mono. The Y_K2 is not used
+   in host write mode. */
+#define DE_SOURCE_X_K1_MONO                             20:16
+
+/* Use these definitions in Bresenham line drawing mode. */
+#define DE_SOURCE_X_K1_LINE                             29:16
+#define DE_SOURCE_Y_K2_LINE                             13:0
+
+#define DE_DESTINATION                                  0x100004
+#define DE_DESTINATION_WRAP                             31:31
+#define DE_DESTINATION_WRAP_DISABLE                     0
+#define DE_DESTINATION_WRAP_ENABLE                      1
+#if 1
+    #define DE_DESTINATION_X                            27:16
+    #define DE_DESTINATION_Y                            11:0
+#else
+    #define DE_DESTINATION_X                            28:16
+    #define DE_DESTINATION_Y                            15:0
+#endif
+
+#define DE_DIMENSION                                    0x100008
+#define DE_DIMENSION_X                                  28:16
+#define DE_DIMENSION_Y_ET                               15:0
+
+#define DE_CONTROL                                      0x10000C
+#define DE_CONTROL_STATUS                               31:31
+#define DE_CONTROL_STATUS_STOP                          0
+#define DE_CONTROL_STATUS_START                         1
+#define DE_CONTROL_PATTERN                              30:30
+#define DE_CONTROL_PATTERN_MONO                         0
+#define DE_CONTROL_PATTERN_COLOR                        1
+#define DE_CONTROL_UPDATE_DESTINATION_X                 29:29
+#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE         0
+#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE          1
+#define DE_CONTROL_QUICK_START                          28:28
+#define DE_CONTROL_QUICK_START_DISABLE                  0
+#define DE_CONTROL_QUICK_START_ENABLE                   1
+#define DE_CONTROL_DIRECTION                            27:27
+#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT              0
+#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT              1
+#define DE_CONTROL_MAJOR                                26:26
+#define DE_CONTROL_MAJOR_X                              0
+#define DE_CONTROL_MAJOR_Y                              1
+#define DE_CONTROL_STEP_X                               25:25
+#define DE_CONTROL_STEP_X_POSITIVE                      0
+#define DE_CONTROL_STEP_X_NEGATIVE                      1
+#define DE_CONTROL_STEP_Y                               24:24
+#define DE_CONTROL_STEP_Y_POSITIVE                      0
+#define DE_CONTROL_STEP_Y_NEGATIVE                      1
+#define DE_CONTROL_STRETCH                              23:23
+#define DE_CONTROL_STRETCH_DISABLE                      0
+#define DE_CONTROL_STRETCH_ENABLE                       1
+#define DE_CONTROL_HOST                                 22:22
+#define DE_CONTROL_HOST_COLOR                           0
+#define DE_CONTROL_HOST_MONO                            1
+#define DE_CONTROL_LAST_PIXEL                           21:21
+#define DE_CONTROL_LAST_PIXEL_OFF                       0
+#define DE_CONTROL_LAST_PIXEL_ON                        1
+#define DE_CONTROL_COMMAND                              20:16
+#define DE_CONTROL_COMMAND_BITBLT                       0
+#define DE_CONTROL_COMMAND_RECTANGLE_FILL               1
+#define DE_CONTROL_COMMAND_DE_TILE                      2
+#define DE_CONTROL_COMMAND_TRAPEZOID_FILL               3
+#define DE_CONTROL_COMMAND_ALPHA_BLEND                  4
+#define DE_CONTROL_COMMAND_RLE_STRIP                    5
+#define DE_CONTROL_COMMAND_SHORT_STROKE                 6
+#define DE_CONTROL_COMMAND_LINE_DRAW                    7
+#define DE_CONTROL_COMMAND_HOST_WRITE                   8
+#define DE_CONTROL_COMMAND_HOST_READ                    9
+#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP         10
+#define DE_CONTROL_COMMAND_ROTATE                       11
+#define DE_CONTROL_COMMAND_FONT                         12
+#define DE_CONTROL_COMMAND_TEXTURE_LOAD                 15
+#define DE_CONTROL_ROP_SELECT                           15:15
+#define DE_CONTROL_ROP_SELECT_ROP3                      0
+#define DE_CONTROL_ROP_SELECT_ROP2                      1
+#define DE_CONTROL_ROP2_SOURCE                          14:14
+#define DE_CONTROL_ROP2_SOURCE_BITMAP                   0
+#define DE_CONTROL_ROP2_SOURCE_PATTERN                  1
+#define DE_CONTROL_MONO_DATA                            13:12
+#define DE_CONTROL_MONO_DATA_NOT_PACKED                 0
+#define DE_CONTROL_MONO_DATA_8_PACKED                   1
+#define DE_CONTROL_MONO_DATA_16_PACKED                  2
+#define DE_CONTROL_MONO_DATA_32_PACKED                  3
+#define DE_CONTROL_REPEAT_ROTATE                        11:11
+#define DE_CONTROL_REPEAT_ROTATE_DISABLE                0
+#define DE_CONTROL_REPEAT_ROTATE_ENABLE                 1
+#define DE_CONTROL_TRANSPARENCY_MATCH                   10:10
+#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE            0
+#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT       1
+#define DE_CONTROL_TRANSPARENCY_SELECT                  9:9
+#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE           0
+#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION      1
+#define DE_CONTROL_TRANSPARENCY                         8:8
+#define DE_CONTROL_TRANSPARENCY_DISABLE                 0
+#define DE_CONTROL_TRANSPARENCY_ENABLE                  1
+#define DE_CONTROL_ROP                                  7:0
+
+/* Pseudo fields. */
+
+#define DE_CONTROL_SHORT_STROKE_DIR                     27:24
+#define DE_CONTROL_SHORT_STROKE_DIR_225                 0
+#define DE_CONTROL_SHORT_STROKE_DIR_135                 1
+#define DE_CONTROL_SHORT_STROKE_DIR_315                 2
+#define DE_CONTROL_SHORT_STROKE_DIR_45                  3
+#define DE_CONTROL_SHORT_STROKE_DIR_270                 4
+#define DE_CONTROL_SHORT_STROKE_DIR_90                  5
+#define DE_CONTROL_SHORT_STROKE_DIR_180                 8
+#define DE_CONTROL_SHORT_STROKE_DIR_0                   10
+#define DE_CONTROL_ROTATION                             25:24
+#define DE_CONTROL_ROTATION_0                           0
+#define DE_CONTROL_ROTATION_270                         1
+#define DE_CONTROL_ROTATION_90                          2
+#define DE_CONTROL_ROTATION_180                         3
+
+#define DE_PITCH                                        0x100010
+#define DE_PITCH_DESTINATION                            28:16
+#define DE_PITCH_SOURCE                                 12:0
+
+#define DE_FOREGROUND                                   0x100014
+#define DE_FOREGROUND_COLOR                             31:0
+
+#define DE_BACKGROUND                                   0x100018
+#define DE_BACKGROUND_COLOR                             31:0
+
+#define DE_STRETCH_FORMAT                               0x10001C
+#define DE_STRETCH_FORMAT_PATTERN_XY                    30:30
+#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL             0
+#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE          1
+#define DE_STRETCH_FORMAT_PATTERN_Y                     29:27
+#define DE_STRETCH_FORMAT_PATTERN_X                     25:23
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT                  21:20
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8                0
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16               1
+#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32               2
+#define DE_STRETCH_FORMAT_ADDRESSING                    19:16
+#define DE_STRETCH_FORMAT_ADDRESSING_XY                 0
+#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR             15
+#define DE_STRETCH_FORMAT_SOURCE_HEIGHT                 11:0
+
+#define DE_COLOR_COMPARE                                0x100020
+#define DE_COLOR_COMPARE_COLOR                          23:0
+
+#define DE_COLOR_COMPARE_MASK                           0x100024
+#define DE_COLOR_COMPARE_MASK_MASKS                     23:0
+
+#define DE_MASKS                                        0x100028
+#define DE_MASKS_BYTE_MASK                              31:16
+#define DE_MASKS_BIT_MASK                               15:0
+
+#define DE_CLIP_TL                                      0x10002C
+#define DE_CLIP_TL_TOP                                  31:16
+#define DE_CLIP_TL_STATUS                               13:13
+#define DE_CLIP_TL_STATUS_DISABLE                       0
+#define DE_CLIP_TL_STATUS_ENABLE                        1
+#define DE_CLIP_TL_INHIBIT                              12:12
+#define DE_CLIP_TL_INHIBIT_OUTSIDE                      0
+#define DE_CLIP_TL_INHIBIT_INSIDE                       1
+#define DE_CLIP_TL_LEFT                                 11:0
+
+#define DE_CLIP_BR                                      0x100030
+#define DE_CLIP_BR_BOTTOM                               31:16
+#define DE_CLIP_BR_RIGHT                                12:0
+
+#define DE_MONO_PATTERN_LOW                             0x100034
+#define DE_MONO_PATTERN_LOW_PATTERN                     31:0
+
+#define DE_MONO_PATTERN_HIGH                            0x100038
+#define DE_MONO_PATTERN_HIGH_PATTERN                    31:0
+
+#define DE_WINDOW_WIDTH                                 0x10003C
+#define DE_WINDOW_WIDTH_DESTINATION                     28:16
+#define DE_WINDOW_WIDTH_SOURCE                          12:0
+
+#define DE_WINDOW_SOURCE_BASE                           0x100040
+#define DE_WINDOW_SOURCE_BASE_ADDRESS                   29:0
+
+#define DE_WINDOW_DESTINATION_BASE                      0x100044
+#define DE_WINDOW_DESTINATION_BASE_ADDRESS              29:0
+
+#define DE_ALPHA                                        0x100048
+#define DE_ALPHA_VALUE                                  7:0
+
+#define DE_WRAP                                         0x10004C
+#define DE_WRAP_X                                       31:16
+#define DE_WRAP_Y                                       15:0
+
+#define DE_STATE2                                        0x100054
+#define DE_STATE2_DE_FIFO                                3:3
+#define DE_STATE2_DE_FIFO_NOTEMPTY                       1
+#define DE_STATE2_DE_FIFO_EMPTY                          0
+#define DE_STATE2_DE_STATUS                              2:2
+#define DE_STATE2_DE_STATUS_IDLE                         0
+#define DE_STATE2_DE_STATUS_BUSY                         1
+#define DE_STATE2_DE_MEM_FIFO                            1:1
+#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY                   0
+#define DE_STATE2_DE_MEM_FIFO_EMPTY                      1
+#define DE_STATE2_DE_ABORT                               0:0
+#define DE_STATE2_DE_ABORT_OFF                           0
+#define DE_STATE2_DE_ABORT_ON                            1
+
+/* Color Space Conversion registers. */
+
+#define CSC_Y_SOURCE_BASE                               0x1000C8
+#define CSC_Y_SOURCE_BASE_ADDRESS                       29:0
+
+#define CSC_CONSTANTS                                   0x1000CC
+#define CSC_CONSTANTS_Y                                 31:24
+#define CSC_CONSTANTS_R                                 23:16
+#define CSC_CONSTANTS_G                                 15:8
+#define CSC_CONSTANTS_B                                 7:0
+
+#define CSC_Y_SOURCE_X                                  0x1000D0
+#define CSC_Y_SOURCE_X_INTEGER                          26:16
+#define CSC_Y_SOURCE_X_FRACTION                         15:3
+
+#define CSC_Y_SOURCE_Y                                  0x1000D4
+#define CSC_Y_SOURCE_Y_INTEGER                          27:16
+#define CSC_Y_SOURCE_Y_FRACTION                         15:3
+
+#define CSC_U_SOURCE_BASE                               0x1000D8
+#define CSC_U_SOURCE_BASE_ADDRESS                       29:0
+
+#define CSC_V_SOURCE_BASE                               0x1000DC
+#define CSC_V_SOURCE_BASE_ADDRESS                       29:0
+
+#define CSC_SOURCE_DIMENSION                            0x1000E0
+#define CSC_SOURCE_DIMENSION_X                          31:16
+#define CSC_SOURCE_DIMENSION_Y                          15:0
+
+#define CSC_SOURCE_PITCH                                0x1000E4
+#define CSC_SOURCE_PITCH_Y                              31:16
+#define CSC_SOURCE_PITCH_UV                             15:0
+
+#define CSC_DESTINATION                                 0x1000E8
+#define CSC_DESTINATION_WRAP                            31:31
+#define CSC_DESTINATION_WRAP_DISABLE                    0
+#define CSC_DESTINATION_WRAP_ENABLE                     1
+#define CSC_DESTINATION_X                               27:16
+#define CSC_DESTINATION_Y                               11:0
+
+#define CSC_DESTINATION_DIMENSION                       0x1000EC
+#define CSC_DESTINATION_DIMENSION_X                     31:16
+#define CSC_DESTINATION_DIMENSION_Y                     15:0
+
+#define CSC_DESTINATION_PITCH                           0x1000F0
+#define CSC_DESTINATION_PITCH_X                         31:16
+#define CSC_DESTINATION_PITCH_Y                         15:0
+
+#define CSC_SCALE_FACTOR                                0x1000F4
+#define CSC_SCALE_FACTOR_HORIZONTAL                     31:16
+#define CSC_SCALE_FACTOR_VERTICAL                       15:0
+
+#define CSC_DESTINATION_BASE                            0x1000F8
+#define CSC_DESTINATION_BASE_ADDRESS                    29:0
+
+#define CSC_CONTROL                                     0x1000FC
+#define CSC_CONTROL_STATUS                              31:31
+#define CSC_CONTROL_STATUS_STOP                         0
+#define CSC_CONTROL_STATUS_START                        1
+#define CSC_CONTROL_SOURCE_FORMAT                       30:28
+#define CSC_CONTROL_SOURCE_FORMAT_YUV422                0
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420I               1
+#define CSC_CONTROL_SOURCE_FORMAT_YUV420                2
+#define CSC_CONTROL_SOURCE_FORMAT_YVU9                  3
+#define CSC_CONTROL_SOURCE_FORMAT_IYU1                  4
+#define CSC_CONTROL_SOURCE_FORMAT_IYU2                  5
+#define CSC_CONTROL_SOURCE_FORMAT_RGB565                6
+#define CSC_CONTROL_SOURCE_FORMAT_RGB8888               7
+#define CSC_CONTROL_DESTINATION_FORMAT                  27:26
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB565           0
+#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888          1
+#define CSC_CONTROL_HORIZONTAL_FILTER                   25:25
+#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE           0
+#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE            1
+#define CSC_CONTROL_VERTICAL_FILTER                     24:24
+#define CSC_CONTROL_VERTICAL_FILTER_DISABLE             0
+#define CSC_CONTROL_VERTICAL_FILTER_ENABLE              1
+#define CSC_CONTROL_BYTE_ORDER                          23:23
+#define CSC_CONTROL_BYTE_ORDER_YUYV                     0
+#define CSC_CONTROL_BYTE_ORDER_UYVY                     1
+
+#define DE_DATA_PORT                                    0x110000
+
+//#include "regzv.h"
+
+/* ZV0 */
+
+#define ZV0_CAPTURE_CTRL                                0x090000
+#define ZV0_CAPTURE_CTRL_FIELD_INPUT                    27:27
+#define ZV0_CAPTURE_CTRL_FIELD_INPUT_EVEN_FIELD         0
+#define ZV0_CAPTURE_CTRL_FIELD_INPUT_ODD_FIELD          1
+#define ZV0_CAPTURE_CTRL_SCAN                           26:26
+#define ZV0_CAPTURE_CTRL_SCAN_PROGRESSIVE               0
+#define ZV0_CAPTURE_CTRL_SCAN_INTERLACE                 1
+#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER                 25:25
+#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_0               0
+#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_1               1
+#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC                  24:24
+#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_INACTIVE         0
+#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_ACTIVE           1
+#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT                  22:22
+#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_16               0
+#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_32               1
+#define ZV0_CAPTURE_CTRL_INCOME_DATA                  	21:21
+#define ZV0_CAPTURE_CTRL_INCOME_DATA_16                 0
+#define ZV0_CAPTURE_CTRL_INCOME_DATA_32	                1
+#define ZV0_CAPTURE_CTRL_ADJ                            19:19
+#define ZV0_CAPTURE_CTRL_ADJ_NORMAL                     0
+#define ZV0_CAPTURE_CTRL_ADJ_DELAY                      1
+#define ZV0_CAPTURE_CTRL_HA                             18:18
+#define ZV0_CAPTURE_CTRL_HA_DISABLE                     0
+#define ZV0_CAPTURE_CTRL_HA_ENABLE                      1
+#define ZV0_CAPTURE_CTRL_VSK                            17:17
+#define ZV0_CAPTURE_CTRL_VSK_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_VSK_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_HSK                            16:16
+#define ZV0_CAPTURE_CTRL_HSK_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_HSK_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_FD                             15:15
+#define ZV0_CAPTURE_CTRL_FD_RISING                      0
+#define ZV0_CAPTURE_CTRL_FD_FALLING                     1
+#define ZV0_CAPTURE_CTRL_VP                             14:14
+#define ZV0_CAPTURE_CTRL_VP_HIGH                        0
+#define ZV0_CAPTURE_CTRL_VP_LOW                         1
+#define ZV0_CAPTURE_CTRL_HP                             13:13
+#define ZV0_CAPTURE_CTRL_HP_HIGH                        0
+#define ZV0_CAPTURE_CTRL_HP_LOW                         1
+#define ZV0_CAPTURE_CTRL_CP                             12:12
+#define ZV0_CAPTURE_CTRL_CP_HIGH                        0
+#define ZV0_CAPTURE_CTRL_CP_LOW                         1
+#define ZV0_CAPTURE_CTRL_UVS                            11:11
+#define ZV0_CAPTURE_CTRL_UVS_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_UVS_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_BS                             10:10
+#define ZV0_CAPTURE_CTRL_BS_DISABLE                     0
+#define ZV0_CAPTURE_CTRL_BS_ENABLE                      1
+#define ZV0_CAPTURE_CTRL_CS                             9:9
+#define ZV0_CAPTURE_CTRL_CS_16                          0
+#define ZV0_CAPTURE_CTRL_CS_8                           1
+#define ZV0_CAPTURE_CTRL_CF                             8:8
+#define ZV0_CAPTURE_CTRL_CF_YUV                         0
+#define ZV0_CAPTURE_CTRL_CF_RGB                         1
+#define ZV0_CAPTURE_CTRL_FS                             7:7
+#define ZV0_CAPTURE_CTRL_FS_DISABLE                     0
+#define ZV0_CAPTURE_CTRL_FS_ENABLE                      1
+#define ZV0_CAPTURE_CTRL_WEAVE                          6:6
+#define ZV0_CAPTURE_CTRL_WEAVE_DISABLE                  0
+#define ZV0_CAPTURE_CTRL_WEAVE_ENABLE                   1
+#define ZV0_CAPTURE_CTRL_BOB                            5:5
+#define ZV0_CAPTURE_CTRL_BOB_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_BOB_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_DB                             4:4
+#define ZV0_CAPTURE_CTRL_DB_DISABLE                     0
+#define ZV0_CAPTURE_CTRL_DB_ENABLE                      1
+#define ZV0_CAPTURE_CTRL_CC                             3:3
+#define ZV0_CAPTURE_CTRL_CC_CONTINUE                    0
+#define ZV0_CAPTURE_CTRL_CC_CONDITION                   1
+#define ZV0_CAPTURE_CTRL_RGB                            2:2
+#define ZV0_CAPTURE_CTRL_RGB_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_RGB_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_656                            1:1
+#define ZV0_CAPTURE_CTRL_656_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_656_ENABLE                     1
+#define ZV0_CAPTURE_CTRL_CAP                            0:0
+#define ZV0_CAPTURE_CTRL_CAP_DISABLE                    0
+#define ZV0_CAPTURE_CTRL_CAP_ENABLE                     1
+
+#define ZV0_CAPTURE_CLIP                                0x090004
+#define ZV0_CAPTURE_CLIP_YCLIP_EVEN_FIELD                25:16
+#define ZV0_CAPTURE_CLIP_YCLIP                          25:16
+#define ZV0_CAPTURE_CLIP_XCLIP                          9:0
+
+#define ZV0_CAPTURE_SIZE                                0x090008
+#define ZV0_CAPTURE_SIZE_HEIGHT                         26:16
+#define ZV0_CAPTURE_SIZE_WIDTH                          10:0   
+
+#define ZV0_CAPTURE_BUF0_ADDRESS                        0x09000C
+#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS                 31:31
+#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_CURRENT         0
+#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_PENDING         1
+#define ZV0_CAPTURE_BUF0_ADDRESS_ADDRESS                29:0
+
+#define ZV0_CAPTURE_BUF1_ADDRESS                        0x090010
+#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS                 31:31
+#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_CURRENT         0
+#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_PENDING         1
+#define ZV0_CAPTURE_BUF1_ADDRESS_ADDRESS                29:0
+
+#define ZV0_CAPTURE_BUF_OFFSET                          0x090014
+#define ZV0_CAPTURE_BUF_OFFSET_YCLIP_ODD_FIELD          25:16
+#define ZV0_CAPTURE_BUF_OFFSET_OFFSET                   15:0
+
+#define ZV0_CAPTURE_FIFO_CTRL                           0x090018
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO                      2:0
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_0                    0
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_1                    1
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_2                    2
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_3                    3
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_4                    4
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_5                    5
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_6                    6
+#define ZV0_CAPTURE_FIFO_CTRL_FIFO_7                    7
+
+#define ZV0_CAPTURE_YRGB_CONST                          0x09001C
+#define ZV0_CAPTURE_YRGB_CONST_Y                        31:24
+#define ZV0_CAPTURE_YRGB_CONST_R                        23:16
+#define ZV0_CAPTURE_YRGB_CONST_G                        15:8
+#define ZV0_CAPTURE_YRGB_CONST_B                        7:0
+
+#define ZV0_CAPTURE_LINE_COMP                           0x090020
+#define ZV0_CAPTURE_LINE_COMP_LC                        10:0
+
+/* ZV1 */
+
+#define ZV1_CAPTURE_CTRL                                0x098000
+#define ZV1_CAPTURE_CTRL_FIELD_INPUT                    27:27
+#define ZV1_CAPTURE_CTRL_FIELD_INPUT_EVEN_FIELD         0
+#define ZV1_CAPTURE_CTRL_FIELD_INPUT_ODD_FIELD          0
+#define ZV1_CAPTURE_CTRL_SCAN                           26:26
+#define ZV1_CAPTURE_CTRL_SCAN_PROGRESSIVE               0
+#define ZV1_CAPTURE_CTRL_SCAN_INTERLACE                 1
+#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER                 25:25
+#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER_0               0
+#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER_1               1
+#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC                  24:24
+#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC_INACTIVE         0
+#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC_ACTIVE           1
+#define ZV1_CAPTURE_CTRL_CHANNEL0                        20:20
+#define ZV1_CAPTURE_CTRL_CHANNEL0_DISABLE                0
+#define ZV1_CAPTURE_CTRL_CHANNEL0_ENABLE                 1
+#define ZV1_CAPTURE_CTRL_ADJ                            19:19
+#define ZV1_CAPTURE_CTRL_ADJ_NORMAL                     0
+#define ZV1_CAPTURE_CTRL_ADJ_DELAY                      1
+#define ZV1_CAPTURE_CTRL_HA                             18:18
+#define ZV1_CAPTURE_CTRL_HA_DISABLE                     0
+#define ZV1_CAPTURE_CTRL_HA_ENABLE                      1
+#define ZV1_CAPTURE_CTRL_VSK                            17:17
+#define ZV1_CAPTURE_CTRL_VSK_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_VSK_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_HSK                            16:16
+#define ZV1_CAPTURE_CTRL_HSK_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_HSK_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_FD                             15:15
+#define ZV1_CAPTURE_CTRL_FD_RISING                      0
+#define ZV1_CAPTURE_CTRL_FD_FALLING                     1
+#define ZV1_CAPTURE_CTRL_VP                             14:14
+#define ZV1_CAPTURE_CTRL_VP_HIGH                        0
+#define ZV1_CAPTURE_CTRL_VP_LOW                         1
+#define ZV1_CAPTURE_CTRL_HP                             13:13
+#define ZV1_CAPTURE_CTRL_HP_HIGH                        0
+#define ZV1_CAPTURE_CTRL_HP_LOW                         1
+#define ZV1_CAPTURE_CTRL_CP                             12:12
+#define ZV1_CAPTURE_CTRL_CP_HIGH                        0
+#define ZV1_CAPTURE_CTRL_CP_LOW                         1
+#define ZV1_CAPTURE_CTRL_UVS                            11:11
+#define ZV1_CAPTURE_CTRL_UVS_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_UVS_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_BS                             10:10
+#define ZV1_CAPTURE_CTRL_BS_DISABLE                     0
+#define ZV1_CAPTURE_CTRL_BS_ENABLE                      1
+#define ZV1_CAPTURE_CTRL_CS                             9:9
+#define ZV1_CAPTURE_CTRL_CS_16                          0
+#define ZV1_CAPTURE_CTRL_CS_8                           1
+#define ZV1_CAPTURE_CTRL_CF                             8:8
+#define ZV1_CAPTURE_CTRL_CF_YUV                         0
+#define ZV1_CAPTURE_CTRL_CF_RGB                         1
+#define ZV1_CAPTURE_CTRL_FS                             7:7
+#define ZV1_CAPTURE_CTRL_FS_DISABLE                     0
+#define ZV1_CAPTURE_CTRL_FS_ENABLE                      1
+#define ZV1_CAPTURE_CTRL_WEAVE                          6:6
+#define ZV1_CAPTURE_CTRL_WEAVE_DISABLE                  0
+#define ZV1_CAPTURE_CTRL_WEAVE_ENABLE                   1
+#define ZV1_CAPTURE_CTRL_BOB                            5:5
+#define ZV1_CAPTURE_CTRL_BOB_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_BOB_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_DB                             4:4
+#define ZV1_CAPTURE_CTRL_DB_DISABLE                     0
+#define ZV1_CAPTURE_CTRL_DB_ENABLE                      1
+#define ZV1_CAPTURE_CTRL_CC                             3:3
+#define ZV1_CAPTURE_CTRL_CC_CONTINUE                    0
+#define ZV1_CAPTURE_CTRL_CC_CONDITION                   1
+#define ZV1_CAPTURE_CTRL_RGB                            2:2
+#define ZV1_CAPTURE_CTRL_RGB_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_RGB_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_656                            1:1
+#define ZV1_CAPTURE_CTRL_656_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_656_ENABLE                     1
+#define ZV1_CAPTURE_CTRL_CAP                            0:0
+#define ZV1_CAPTURE_CTRL_CAP_DISABLE                    0
+#define ZV1_CAPTURE_CTRL_CAP_ENABLE                     1
+
+#define ZV1_CAPTURE_CLIP                                0x098004
+#define ZV1_CAPTURE_CLIP_YCLIP                          25:16
+#define ZV1_CAPTURE_CLIP_XCLIP                          9:0
+
+#define ZV1_CAPTURE_SIZE                                0x098008
+#define ZV1_CAPTURE_SIZE_HEIGHT                         26:16   
+#define ZV1_CAPTURE_SIZE_WIDTH                          10:0   
+
+#define ZV1_CAPTURE_BUF0_ADDRESS                        0x09800C
+#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS                 31:31
+#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS_CURRENT         0
+#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS_PENDING         1
+#define ZV1_CAPTURE_BUF0_ADDRESS_ADDRESS                29:0
+
+#define ZV1_CAPTURE_BUF1_ADDRESS                        0x098010
+#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS                 31:31
+#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS_CURRENT         0
+#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS_PENDING         1
+#define ZV1_CAPTURE_BUF1_ADDRESS_ADDRESS                29:0
+
+#define ZV1_CAPTURE_BUF_OFFSET                          0x098014
+#define ZV1_CAPTURE_BUF_OFFSET_OFFSET                   15:0
+
+#define ZV1_CAPTURE_FIFO_CTRL                           0x098018
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO                      2:0
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_0                    0
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_1                    1
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_2                    2
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_3                    3
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_4                    4
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_5                    5
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_6                    6
+#define ZV1_CAPTURE_FIFO_CTRL_FIFO_7                    7
+
+#define ZV1_CAPTURE_YRGB_CONST                          0x09801C
+#define ZV1_CAPTURE_YRGB_CONST_Y                        31:24
+#define ZV1_CAPTURE_YRGB_CONST_R                        23:16
+#define ZV1_CAPTURE_YRGB_CONST_G                        15:8
+#define ZV1_CAPTURE_YRGB_CONST_B                        7:0
+
+
+
+//#include "regi2c.h"
+#define I2C_BYTE_COUNT                                  0x010040
+#define I2C_BYTE_COUNT_COUNT                            3:0
+
+#define I2C_CTRL                                        0x010041
+#define I2C_CTRL_INT                                    4:4
+#define I2C_CTRL_INT_DISABLE                            0
+#define I2C_CTRL_INT_ENABLE                             1
+#define I2C_CTRL_CTRL                                   2:2
+#define I2C_CTRL_CTRL_STOP                              0
+#define I2C_CTRL_CTRL_START                             1
+#define I2C_CTRL_MODE                                   1:1
+#define I2C_CTRL_MODE_STANDARD                          0
+#define I2C_CTRL_MODE_FAST                              1
+#define I2C_CTRL_EN                                     0:0
+#define I2C_CTRL_EN_DISABLE                             0
+#define I2C_CTRL_EN_ENABLE                              1
+
+#define I2C_STATUS                                      0x010042
+#define I2C_STATUS_TX                                   3:3
+#define I2C_STATUS_TX_PROGRESS                          0
+#define I2C_STATUS_TX_COMPLETED                         1
+#define I2C_STATUS_ERR                                  2:2
+#define I2C_STATUS_ERR_NORMAL                           0
+#define I2C_STATUS_ERR_ERROR                            1
+#define I2C_STATUS_ERR_CLEAR                            0
+#define I2C_STATUS_ACK                                  1:1
+#define I2C_STATUS_ACK_RECEIVED                         0
+#define I2C_STATUS_ACK_NOT                              1
+#define I2C_STATUS_BSY                                  0:0
+#define I2C_STATUS_BSY_IDLE                             0
+#define I2C_STATUS_BSY_BUSY                             1
+
+#define I2C_RESET                                       0x010042
+#define I2C_RESET_BUS_ERROR                             2:2
+#define I2C_RESET_BUS_ERROR_CLEAR                       0
+
+#define I2C_SLAVE_ADDRESS                               0x010043
+#define I2C_SLAVE_ADDRESS_ADDRESS                       7:1
+#define I2C_SLAVE_ADDRESS_RW                            0:0
+#define I2C_SLAVE_ADDRESS_RW_W                          0
+#define I2C_SLAVE_ADDRESS_RW_R                          1
+
+#define I2C_DATA0                                       0x010044
+#define I2C_DATA1                                       0x010045
+#define I2C_DATA2                                       0x010046
+#define I2C_DATA3                                       0x010047
+#define I2C_DATA4                                       0x010048
+#define I2C_DATA5                                       0x010049
+#define I2C_DATA6                                       0x01004A
+#define I2C_DATA7                                       0x01004B
+#define I2C_DATA8                                       0x01004C
+#define I2C_DATA9                                       0x01004D
+#define I2C_DATA10                                      0x01004E
+#define I2C_DATA11                                      0x01004F
+#define I2C_DATA12                                      0x010050
+#define I2C_DATA13                                      0x010051
+#define I2C_DATA14                                      0x010052
+#define I2C_DATA15                                      0x010053
+
+/* MMIO offset between I2C0 and I2C1 */
+#define I2C_OFFSET 0x20
+
+//#include "regtimer.h"
+
+/* There are 4 timers in the system with the same definition,
+   but different MMIO address as below
+  
+   TIMER 0  0x010030
+   TIMER 1  0x010034
+   TIMER 2  0x010038
+   TIMER 3  0x01003C
+
+   We only define the MMIO for timer 0, the MMIO for other
+   timer can be work out like this:
+   0x10030 + (4 x Timer number)
+
+*/
+
+#define TIMER_CONTROL                                   0x010030
+#define TIMER_CONTROL_COUNTER                           31:4
+#define TIMER_CONTROL_RAWINT_STATUS                     3:3
+#define TIMER_CONTROL_RAWINT_STATUS_CLEAR               0
+#define TIMER_CONTROL_RAWINT_STATUS_PENDING             1
+#define TIMER_CONTROL_RAWINT_STATUS_RESET               1
+#define TIMER_CONTROL_RAWINT_ENABLE                     2:2  
+#define TIMER_CONTROL_RAWINT_ENABLE_DISABLE             0
+#define TIMER_CONTROL_RAWINT_ENABLE_ENABLE              1
+#define TIMER_CONTROL_DIV16                             1:1
+#define TIMER_CONTROL_DIV16_DISABLE                     0
+#define TIMER_CONTROL_DIV16_ENABLE                      1
+#define TIMER_CONTROL_ENABLE                            0:0
+#define TIMER_CONTROL_ENABLE_DISABLE                    0
+#define TIMER_CONTROL_ENABLE_ENABLE                     1
+
+#define I2S_TX_DATA_L                              0x0A0200
+#define I2S_TX_DATA_L_DATA						   15:0
+
+#define I2S_TX_DATA_R                              0x0A0204
+#define I2S_TX_DATA_R_DATA                         15:0
+
+#define I2S_RX_DATA_L                              0x0A0208
+#define I2S_RX_DATA_L_DATA						   15:0
+
+#define I2S_RX_DATA_R                              0x0A020C
+#define I2S_RX_DATA_R_DATA						   15:0
+
+#define I2S_STATUS                                 0x0A0210
+#define I2S_STATUS_R                               11:11
+#define I2S_STATUS_R_NO_ERR                        0
+#define I2S_STATUS_R_OVERFLOW                      1
+#define I2S_STATUS_T                               10:10
+#define I2S_STATUS_T_NO_ERR                        0
+#define I2S_STATUS_T_UNDERFLOW                     1
+#define I2S_STATUS_TX                              2:2
+#define I2S_STATUS_TX_DISABLE                      0
+#define I2S_STATUS_TX_ENABLE                       1
+
+#define I2S_CTRL                                    0x0A0214
+#define I2S_CTRL_MODE                               7:7
+#define I2S_CTRL_MODE_SLAVE                         0
+#define I2S_CTRL_MODE_MASTER                        1
+#define I2S_CTRL_CS                                 6:5
+#define I2S_CTRL_CS_16                              0
+#define I2S_CTRL_CS_24                              1
+#define I2S_CTRL_CS_32                              2
+#define I2S_CTRL_CDIV                               4:0
+
+
+#define I2S_SRAM_DMA                                0x0A0218
+#define I2S_SRAM_DMA_STATE                          31:31    
+#define I2S_SRAM_DMA_STATE_DISABLE                  0            
+#define I2S_SRAM_DMA_STATE_ENABLE                   1
+#define I2S_SRAM_DMA_SIZE                           23:16     
+#define I2S_SRAM_DMA_ADDRESS						8:0                               
+           
+#define I2S_SRAM_DMA_STATUS                         0x0A021C
+#define I2S_SRAM_DMA_STATUS_TC                      0:0    
+#define I2S_SRAM_DMA_STATUS_TC_COMPLETE             1            
+#define I2S_SRAM_DMA_STATUS_TC_CLEAR                0
+
+
+
+#define SRAM_OUTPUT_BASE							0x8000
+#define SRAM_INPUT_BASE								0x8800
+#define SRAM_SIZE									0x0800
+
+
+
+/* Internal macros */
+#define _F_START(f)             (0 ? f)
+#define _F_END(f)               (1 ? f)
+#define _F_SIZE(f)              (1 + _F_END(f) - _F_START(f))
+#define _F_MASK(f)              (((1 << _F_SIZE(f)) - 1) << _F_START(f))
+#define _F_NORMALIZE(v, f)      (((v) & _F_MASK(f)) >> _F_START(f))
+#define _F_DENORMALIZE(v, f)    (((v) << _F_START(f)) & _F_MASK(f))
+
+/* Global macros */
+#define FIELD_GET(x, reg, field) \
+( \
+    _F_NORMALIZE((x), reg ## _ ## field) \
+)
+
+#define FIELD_SET(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
+)
+
+#define FIELD_VALUE(x, reg, field, value) \
+( \
+    (x & ~_F_MASK(reg ## _ ## field)) \
+    | _F_DENORMALIZE(value, reg ## _ ## field) \
+)
+
+#define FIELD_CLEAR(reg, field) \
+( \
+    ~ _F_MASK(reg ## _ ## field) \
+)
+
+/* FIELD MACROS */
+#define FIELD_START(field)              (0 ? field)
+#define FIELD_END(field)                (1 ? field)
+#define FIELD_SIZE(field)               (1 + FIELD_END(field) - FIELD_START(field))
+#define FIELD_MASK(field)               (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field))
+#define FIELD_NORMALIZE(reg, field)     (((reg) & FIELD_MASK(field)) >> FIELD_START(field))
+#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field))
+#define FIELD_INIT(reg, field, value)   FIELD_DENORMALIZE(reg ## _ ## field, \
+                                                          reg ## _ ## field ## _ ## value)
+#define FIELD_INIT_VAL(reg, field, value) \
+                                        (FIELD_DENORMALIZE(reg ## _ ## field, value))
+#define FIELD_VAL_SET(x, r, f, v)       x = x & ~FIELD_MASK(r ## _ ## f) \
+                                              | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v)
+
+#define RGB(r, g, b) \
+( \
+    (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define RGB16(r, g, b) \
+( \
+    (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \
+)
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.c
new file mode 100644
index 000000000000..1f0cdc5970c7
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.c
@@ -0,0 +1,712 @@
+/*******************************************************************
+ *
+ *         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+ *
+ *  All rights are reserved. Reproduction or in part is prohibited
+ *  without the written consent of the copyright owner.
+ *
+ *  swi2c.c --- SM750/SM718 DDK
+ *  This file contains the source code for I2C using software
+ *  implementation.
+ *
+ *******************************************************************/
+//#include "defs.h"
+#include <linux/delay.h>
+
+#include "ddk768_reg.h"
+//#include "ddk768_hardware.h"
+#include "ddk768_chip.h"
+#include "ddk768_power.h"
+#include "ddk768_timer.h"
+#include "ddk768_swi2c.h"
+#include "ddk768_help.h"
+
+
+/*******************************************************************
+ * I2C Software Master Driver:
+ * ===========================
+ * Each i2c cycle is split into 4 sections. Each of these section marks
+ * a point in time where the SCL or SDA may be changed.
+ *
+ * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
+ *            +-------------+-------------+-------------+-------------+
+ *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
+ *
+ *                                          ____________ _____________
+ * SCL == XXXX _____________ ____________ /
+ *
+ * I.e. the SCL may only be changed in section 1. and section 3. while
+ * the SDA may only be changed in section 2. and section 4. The table
+ * below gives the changes for these 2 lines in the varios sections.
+ *
+ * Section changes Table:
+ * ======================
+ * blank = no change, L = set bit LOW, H = set bit HIGH
+ *
+ *                                | 1.| 2.| 3.| 4.|
+ *                 ---------------+---+---+---+---+
+ *                 Tx Start   SDA |   | H |   | L |
+ *                            SCL | L |   | H |   |
+ *                 ---------------+---+---+---+---+
+ *                 Tx Stop    SDA |   | L |   | H |
+ *                            SCL | L |   | H |   |
+ *                 ---------------+---+---+---+---+
+ *                 Tx bit H   SDA |   | H |   |   |
+ *                            SCL | L |   | H |   |
+ *                 ---------------+---+---+---+---+
+ *                 Tx bit L   SDA |   | L |   |   |
+ *                            SCL | L |   | H |   |
+ *                 ---------------+---+---+---+---+
+ *
+ ******************************************************************/
+
+/* GPIO pins used for this I2C. It ranges from 0 to 31. */
+unsigned char g_i2cClockGPIO = DEFAULT_I2C0_SCL;
+unsigned char g_i2cDataGPIO = DEFAULT_I2C0_SDA;
+
+/*
+ *  Below is the variable declaration for the GPIO pin register usage
+ *  for the i2c Clock and i2c Data.
+ *
+ *  Note:
+ *      Notice that the GPIO usage for the i2c clock and i2c Data are
+ *      separated. This is to make this code flexible enough when 
+ *      two separate GPIO pins for the clock and data are located
+ *      in two different GPIO register set (worst case).
+ */
+
+/* i2c Clock GPIO Register usage */
+static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
+static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
+static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+/* i2c Data GPIO Register usage */
+static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
+static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
+static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+/*
+ *  This function puts a delay between command
+ */        
+static void swI2CWait(void)
+{
+    //SM768 has build-in timer. Use it instead of SW loop.
+    timerWaitTicks(3, 0x3ff);
+}
+
+static void swI2CSCL(unsigned char value, unsigned char i2cClockGPIO)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if (value) /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+    else /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+        ulGPIOData &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function read the data from the SDA GPIO pin
+ *
+ *  Return Value:
+ *      The SDA data bit sent by the Slave
+ */
+static unsigned char swI2CReadSCL(unsigned char i2cClockGPIO)
+{
+    unsigned long ulGPIODirection;
+    unsigned long ulGPIOData;
+
+    /* Make sure that the direction is input (High) */
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if ((ulGPIODirection & (1 << i2cClockGPIO)) != (~(1 << i2cClockGPIO)))
+    {
+        ulGPIODirection &= ~(1 << i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+
+    /* Now read the SCL line */
+    ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+    if (ulGPIOData & (1 << i2cClockGPIO))
+        return 1;
+    else
+        return 0;
+}
+
+static void swI2CSDA(unsigned char value, unsigned char i2cDataGPIO)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if (value) /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+    else /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+        ulGPIOData &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+/*
+ *  This function read the data from the SDA GPIO pin
+ *
+ *  Return Value:
+ *      The SDA data bit sent by the Slave
+ */
+static unsigned char swI2CReadSDA(unsigned char i2cDataGPIO)
+{
+    unsigned long ulGPIODirection;
+    unsigned long ulGPIOData;
+
+    /* Make sure that the direction is input (High) */
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if ((ulGPIODirection & (1 << i2cDataGPIO)) != (~(1 << i2cDataGPIO)))
+    {
+        ulGPIODirection &= ~(1 << i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+
+    /* Now read the SDA line */
+    ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+    if (ulGPIOData & (1 << i2cDataGPIO))
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ *  This function set/reset the SDA GPIO pin
+ *
+ *  Parameters:
+ *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ *
+ *  Notes:
+ *      When setting SCL to high, just set the GPIO as input where the pull up
+ *      resistor will pull the signal up. Do not use software to pull up the
+ *      signal because the i2c will fail when other device try to drive the
+ *      signal due to SM50x will drive the signal to always high.
+ */
+void ddk768_swI2CSDA(unsigned char value)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg);
+    if (value)      /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << g_i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+    else            /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg);
+        ulGPIOData &= ~(1 << g_i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << g_i2cDataGPIO);
+        pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection);
+    }
+}
+
+
+/*
+ *  This function set/reset the SCL GPIO pin
+ *
+ *  Parameters:
+ *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
+ *
+ *  Notes:
+ *      When setting SCL to high, just set the GPIO as input where the pull up
+ *      resistor will pull the signal up. Do not use software to pull up the
+ *      signal because the i2c will fail when other device try to drive the
+ *      signal due to SM50x will drive the signal to always high.
+ */
+void ddk768_swI2CSCL(unsigned char value)
+{
+    unsigned long ulGPIOData;
+    unsigned long ulGPIODirection;
+
+    ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg);
+    if (value)      /* High */
+    {
+        /* Set direction as input. This will automatically pull the signal up. */
+        ulGPIODirection &= ~(1 << g_i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+    else            /* Low */
+    {
+        /* Set the signal down */
+        ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg);
+        ulGPIOData &= ~(1 << g_i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData);
+
+        /* Set direction as output */
+        ulGPIODirection |= (1 << g_i2cClockGPIO);
+        pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection);
+    }
+}
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+/*
+ *  This function sends ACK signal
+ */
+static void swI2CAck(unsigned char ack)
+{
+        if(ack)
+    {
+        ddk768_swI2CSCL(0);
+        ddk768_swI2CSDA(0);
+        swI2CWait();
+        ddk768_swI2CSCL(1);
+        swI2CWait();
+        ddk768_swI2CSCL(0);
+        ddk768_swI2CSDA(0);
+        swI2CWait();
+    }
+    else
+    {
+        ddk768_swI2CSCL(0);
+        ddk768_swI2CSDA(1);
+        swI2CWait();
+        ddk768_swI2CSCL(1);
+        swI2CWait();
+        ddk768_swI2CSCL(0);
+        ddk768_swI2CSDA(0);
+        swI2CWait();
+    }
+
+    return;  /* Single byte read is ok without it. */
+}
+
+
+/*
+ *  This function sends the start command to the slave device
+ */
+void ddk768_swI2CStart(void)
+{
+    /* Start I2C */
+    swI2CSDA(1, g_i2cDataGPIO);
+    swI2CSCL(1, g_i2cClockGPIO);
+    swI2CSDA(0, g_i2cDataGPIO);
+}
+
+/*
+ *  This function sends the stop command to the slave device
+ */
+void ddk768_swI2CStop(void)
+{
+    /* Stop the I2C */
+    swI2CSCL(1, g_i2cClockGPIO);
+    swI2CSDA(0, g_i2cDataGPIO);
+    swI2CSDA(1, g_i2cDataGPIO);
+}
+
+void ddk768_swI2CClean(void)
+{
+    swI2CSCL(0, g_i2cClockGPIO);
+    swI2CWait();
+    swI2CSCL(1, g_i2cClockGPIO);
+    swI2CWait();
+}
+
+/*
+ *  This function writes one byte to the slave device
+ *
+ *  Parameters:
+ *      data    - Data to be write to the slave device
+ *
+ *  Return Value:
+ *       0   - Success
+ *      -1   - Fail to write byte
+ */
+long ddk768_swI2CWriteByte(unsigned char data) 
+{
+    unsigned char value = data;
+    int i;
+
+    /* Sending the data bit by bit */
+    for (i=0; i<8; i++)
+    {
+        /* Set SCL to low */
+        swI2CSCL(0, g_i2cClockGPIO);
+
+        /* Send data bit */
+        if ((value & 0x80) != 0)
+            swI2CSDA(1, g_i2cDataGPIO);
+        else
+            swI2CSDA(0, g_i2cDataGPIO);
+
+        swI2CWait();
+
+        /* Toggle clk line to one */
+        swI2CSCL(1, g_i2cClockGPIO);
+      
+
+        /* Shift byte to be sent */
+        value = value << 1;
+    }
+
+    /* Set the SCL Low and SDA High (prepare to get input) */
+    swI2CSCL(0, g_i2cClockGPIO);
+    swI2CSDA(1, g_i2cDataGPIO);
+
+    /* Set the SCL High for ack */
+    swI2CWait();
+    swI2CSCL(1, g_i2cClockGPIO);
+
+
+    /* Read SDA, until SDA==0 */
+    for(i=0; i<0xf; i++) 
+    {
+        if (!swI2CReadSDA(g_i2cDataGPIO))
+            break;
+
+
+        swI2CWait();
+
+        swI2CWait();
+    }
+
+    /* Set the SCL Low and SDA High */
+    swI2CSCL(0, g_i2cClockGPIO);
+    swI2CSDA(1, g_i2cDataGPIO);
+
+    if (i<0xf)
+        return 0;
+    else
+        return (-1);
+}
+
+#pragma GCC pop_options
+
+long ddk768_swI2CSetGPIO(
+    unsigned char i2cClkGPIO,
+    unsigned char i2cDataGPIO)
+{
+    /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
+    if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
+        return (-1);
+
+    /* Initialize the GPIO pin for the i2c Clock Register */
+    g_i2cClkGPIOMuxReg = GPIO_MUX;
+    g_i2cClkGPIODataReg = GPIO_DATA;
+    g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+
+
+    /* Initialize the GPIO pin for the i2c Data Register */
+    g_i2cDataGPIOMuxReg = GPIO_MUX;
+    g_i2cDataGPIODataReg = GPIO_DATA;
+    g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
+
+
+
+    /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
+    pokeRegisterDWord(g_i2cClkGPIOMuxReg,
+                      peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << i2cClkGPIO));
+    pokeRegisterDWord(g_i2cDataGPIOMuxReg,
+                      peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << i2cDataGPIO));
+
+    /* Enable GPIO power */
+    //enableGPIO(1);
+    
+    return 0;
+}
+
+/*
+ * This function initializes the i2c attributes and bus
+ *
+ * Parameters:
+ *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
+ *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ *      -1   - Fail to initialize the i2c
+ *       0   - Success
+ */
+long ddk768_swI2CInit(unsigned char i2cClkGPIO, unsigned char i2cDataGPIO)
+{
+
+    /* GPIO pins used for this I2C. It ranges from 0 to 31. */
+    g_i2cClockGPIO = i2cClkGPIO;
+    g_i2cDataGPIO = i2cDataGPIO;
+
+    if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO))
+        return (-1);
+
+#if 0
+    /* Clear the i2c lines. */
+    {
+        int i = 0;
+        for (i = 0; i < 9; i++)
+            ddk768_swI2CStop();
+    }
+#endif
+    return 0;
+}
+
+static void smi_ddc_setsda(void *data, int state)
+{
+    struct smi_connector *connector = data;
+    swI2CSDA(state, connector->i2c_sda);
+    /* smi_set_i2c_signal(data, I2C_SDA_MASK, state); */
+}
+
+static void smi_ddc_setscl(void *data, int state)
+{
+    struct smi_connector *connector = data;
+    swI2CSCL(state, connector->i2c_scl);
+    /* smi_set_i2c_signal(data, I2C_SCL_MASK, state); */
+}
+
+static int smi_ddc_getsda(void *data)
+{
+
+    struct smi_connector *connector = data;
+    return (int)swI2CReadSDA(connector->i2c_sda);
+    /* return smi_get_i2c_signal(data, I2C_SDA_MASK); */
+}
+
+static int smi_ddc_getscl(void *data)
+{
+    struct smi_connector *connector = data;
+    return (int)swI2CReadSCL(connector->i2c_scl);
+    /* return smi_get_i2c_signal(data, I2C_SCL_MASK); */
+}
+
+static int smi_ddc_create(struct smi_connector *connector)
+{
+    connector->adapter.owner = THIS_MODULE;
+    connector->adapter.class = I2C_CLASS_DDC;
+    snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI SW I2C Bit Bus");
+    connector->adapter.dev.parent = connector->base.dev->dev;
+    i2c_set_adapdata(&connector->adapter, connector);
+    connector->adapter.algo_data = &connector->bit_data;
+
+    connector->bit_data.udelay = 2; /* 0x3ff ticks, 168MHZ */
+    connector->bit_data.timeout = usecs_to_jiffies(2200);
+    connector->bit_data.data = connector;
+    connector->bit_data.setsda = smi_ddc_setsda;
+    connector->bit_data.setscl = smi_ddc_setscl;
+    connector->bit_data.getsda = smi_ddc_getsda;
+    connector->bit_data.getscl = smi_ddc_getscl;
+
+    if (i2c_bit_add_bus(&connector->adapter))
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+
+long ddk768_AdaptSWI2CInit(struct smi_connector *smi_connector)
+{
+    struct drm_connector *connector = &smi_connector->base;
+    unsigned char i2cClkGPIO;
+    unsigned char i2cDataGPIO;
+
+    if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+    {
+        i2cClkGPIO = 30;
+        i2cDataGPIO = 31;
+    }
+    else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+    {
+        i2cClkGPIO = 6;
+        i2cDataGPIO = 7;
+    }
+    else if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+    {
+        i2cClkGPIO = 8;
+        i2cDataGPIO = 9;
+    }
+    else
+    {
+        return -1;
+    }
+
+    smi_connector->i2c_scl = i2cClkGPIO;
+    smi_connector->i2c_sda = i2cDataGPIO;
+
+    if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO))
+    {
+        return (-1);
+    }
+
+#if 0
+    /* Clear the i2c lines. */
+    {
+        int i = 0;
+        for (i = 0; i < 9; i++)
+            ddk768_swI2CStop();
+    }
+#endif
+
+    udelay(20);
+
+    if (smi_ddc_create(smi_connector))
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* After closing HW I2C, give a SCL clk by SW to avoid the deadlock */
+long ddk768_AdaptSWI2CCleanBus(
+    struct smi_connector *connector)
+{
+    unsigned char i2cClkGPIO = connector->i2c_scl;
+    unsigned char i2cDataGPIO = connector->i2c_sda;
+
+    if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO))
+        return (-1);
+
+    udelay(20);
+    swI2CSCL(0, i2cClkGPIO);
+    udelay(20);
+    swI2CSCL(1, i2cClkGPIO);
+    udelay(20);
+//    ddk768_swI2CClean();
+
+    return 0;
+}
+
+
+/*
+ *  This function writes a value to the slave device's register
+ *  (here the g_i2cClockGPIO and g_i2cDataGPIO must have been initilized) 
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk768_swI2CWriteReg(
+    unsigned char deviceAddress,
+    unsigned char registerIndex,
+    unsigned char data)
+{
+    long returnValue = 0;
+    
+    /* Send the Start signal */
+    ddk768_swI2CStart();
+
+    /* Send the device address and read the data. All should return success
+       in order for the writing processed to be successful
+     */
+    if ((ddk768_swI2CWriteByte(deviceAddress) != 0) ||
+        (ddk768_swI2CWriteByte(registerIndex) != 0) ||
+        (ddk768_swI2CWriteByte(data) != 0))
+    {
+        returnValue = -1;
+    }
+
+    /* Stop i2c and release the bus */
+    ddk768_swI2CStop();
+
+    return returnValue;
+}
+
+
+unsigned char ddk768_swI2CReadByte(unsigned char ack)
+{
+    int i;
+    unsigned char data = 0;
+
+    for(i=7; i>=0; i--)
+    {
+        /* Set the SCL to Low and SDA to High (Input) */
+        ddk768_swI2CSCL(0);
+        ddk768_swI2CSDA(1);
+        swI2CWait();
+
+        /* Set the SCL High */
+        ddk768_swI2CSCL(1);
+        swI2CWait();
+
+        /* Read data bits from SDA */
+        data |= (swI2CReadSDA(g_i2cDataGPIO) << i);
+    }
+
+       swI2CAck(ack);
+
+
+    return data;
+}
+
+/*
+ *  This function reads the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be read from
+ *      registerIndex   - Slave device's register to be read
+ *
+ *  Return Value:
+ *      Register value
+ */
+
+
+unsigned char ddk768_swI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+)
+{
+    unsigned char data;
+
+    /* Send the Start signal */
+    ddk768_swI2CStart();
+
+    /* Send the device address */
+    ddk768_swI2CWriteByte(deviceAddress);                                                  
+
+    /* Send the register index */
+    ddk768_swI2CWriteByte(registerIndex);               
+
+    /* Get the bus again and get the data from the device read address */
+    ddk768_swI2CStart();
+    ddk768_swI2CWriteByte(deviceAddress + 1);
+
+       data = ddk768_swI2CReadByte(0);
+
+    /* Stop swI2C and release the bus */
+    ddk768_swI2CStop();
+
+    return data;
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.h
new file mode 100644
index 000000000000..391211d009ce
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_swi2c.h
@@ -0,0 +1,73 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  swi2c.h --- SM750/SM718 DDK 
+*  This file contains the definitions for i2c using software 
+*  implementation.
+* 
+*******************************************************************/
+#ifndef _DDK768_SWI2C_H_
+#define _DDK768_SWI2C_H_
+
+#include "../smi_drv.h"
+
+/* Default i2c CLK and Data GPIO. These are the default i2c pins */
+#define DEFAULT_I2C0_SCL                     30
+#define DEFAULT_I2C0_SDA                     31
+
+#define DEFAULT_I2C1_SCL                     6
+#define DEFAULT_I2C1_SDA                     7
+
+/*
+ * This function initializes the i2c attributes and bus
+ *
+ * Parameters:
+ *      i2cClkGPIO  - The GPIO pin to be used as i2c SCL
+ *      i2cDataGPIO - The GPIO pin to be used as i2c SDA
+ *
+ * Return Value:
+ *      -1   - Fail to initialize the i2c
+ *       0   - Success
+ */
+long ddk768_swI2CInit(
+    unsigned char i2cClkGPIO, 
+    unsigned char i2cDataGPIO
+);
+
+/*
+ *  This function writes a value to the slave device's register
+ *
+ *  Parameters:
+ *      deviceAddress   - i2c Slave device address which register
+ *                        to be written
+ *      registerIndex   - Slave device's register to be written
+ *      data            - Data to be written to the register
+ *
+ *  Result:
+ *          0   - Success
+ *         -1   - Fail
+ */
+long ddk768_swI2CWriteReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex, 
+    unsigned char data
+);
+
+unsigned char ddk768_swI2CReadReg(
+    unsigned char deviceAddress, 
+    unsigned char registerIndex
+);
+
+
+long ddk768_AdaptSWI2CInit(struct smi_connector *smi_connector);
+
+long ddk768_AdaptSWI2CCleanBus(
+    struct smi_connector *connector);
+
+
+
+#endif  /* _SWI2C_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.c
new file mode 100644
index 000000000000..63d83f5fae51
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.c
@@ -0,0 +1,343 @@
+/*******************************************************************
+*
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+*
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+*
+*  This file contains the definitions for the timer functions.
+*
+*******************************************************************/
+#include "ddk768_reg.h"
+#include "ddk768_helper.h"
+#include "ddk768_intr.h"
+#include "ddk768_timer.h"
+#include "ddk768_help.h"
+
+/* 
+ * A global varible to store the counter values set in the timer.
+ * It is needed because the counter value cannot be read back from the timer.
+ * A read to the timer counter only gets the latest value being decremented.
+ */
+static unsigned long gTimerCounter[4] = {0, 0, 0, 0};
+
+/*
+ * Calculate a value for timer counter according to input time in micro-second.
+ * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks.
+ */
+unsigned long calcTimerCounter(
+    unsigned long microSeconds
+)
+{
+    return( microSeconds * 168 / 16);
+}
+
+/*
+ * This function start the timer with raw interrupt enabled.
+ * When the timer decrements to 0, timer raw interrupt will be generated.
+ *
+ * Raw interrupt of the timers can be used in one of 2 ways:
+ * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0.
+ * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system.
+ *
+ */
+void timerStart(
+    timer_number_t timer,         /* which timer: 0 to 3 */
+    unsigned long timerCounter,   /* Timer counter */
+    unsigned long div16Enable     /* Enable the 16 divisor, time out will be increased by 16 */
+)
+{  
+    unsigned long ulTimerAddr, ulTimerValue;
+
+    if (timerCounter == 0) return; /* Nothing to set */
+
+    /* Work out the timer's MMIO address 
+       Timer 0 address + ( timer number x 4 )
+    */
+    ulTimerAddr = TIMER_CONTROL + (timer << 2);
+
+    ulTimerValue =
+          FIELD_VALUE(0, TIMER_CONTROL, COUNTER, timerCounter)
+        | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET)    /* Reset the raw interrupt */
+        | FIELD_SET(0, TIMER_CONTROL, RAWINT_ENABLE, ENABLE)   /* Enable raw interrupt to happen when time out */
+        | FIELD_VALUE(0, TIMER_CONTROL, DIV16, div16Enable)
+        | FIELD_SET(0, TIMER_CONTROL, ENABLE, ENABLE);           /* Start the timer */
+
+    pokeRegisterDWord(ulTimerAddr, ulTimerValue);
+
+    gTimerCounter[timer] = timerCounter;
+}
+
+/*
+ * This function checks if a timer's raw interrupt has been pending.
+ * When raw interrupt is detected with pending status, it indicate the
+ * countdown of timerStart() has been completed.
+ * 
+ * Return:
+ *        1 = Raw interrupt status is pending.
+ *        0 = Raw int is NOT pending.
+ */
+unsigned long timerRawIntPending(
+    timer_number_t timer         /* which timer: 0 to 3 */
+)
+{  
+    unsigned long ulTimerAddr, rawIntStatus;
+
+    /* Work out the timer's MMIO address 
+       Timer 0 address + ( timer number x 4 )
+    */
+    ulTimerAddr = TIMER_CONTROL + (timer << 2);
+    rawIntStatus = FIELD_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, RAWINT_STATUS);
+
+    return(rawIntStatus);
+}
+
+/*
+ * This function clears the RAW interrupt status of the timer.
+ * 
+ * When a timer completes countdown, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different sessions of countdown.
+ * 
+ */
+void timerClearRawInt(
+    timer_number_t timer         /* which timer: 0 to 3 */
+)
+{  
+    unsigned long ulTimerAddr, ulTimerValue;
+
+    /* Work out the timer's MMIO address 
+       Timer 0 address + ( timer number x 4 )
+    */
+    ulTimerAddr = TIMER_CONTROL + (timer << 2);
+    ulTimerValue = peekRegisterDWord(ulTimerAddr)
+                 & FIELD_CLEAR(TIMER_CONTROL, COUNTER); /* We don't want the current counter value */
+
+    pokeRegisterDWord(ulTimerAddr,
+            ulTimerValue
+          | FIELD_VALUE(0, TIMER_CONTROL, COUNTER, gTimerCounter[timer]) /* When clearing raw int, we don't want to erase the original counter value */
+          | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET));    /* Reset the raw interrupt */
+}
+
+/*
+ * This function stop the timer.
+ *
+ */
+void timerStop(
+    timer_number_t timer         /* which timer: 0 to 3 */
+)
+{  
+    unsigned long ulTimerAddr, ulTimerValue;
+
+    /* Work out the timer's MMIO address 
+       Timer 0 address + ( timer number x 4 )
+    */
+    ulTimerAddr = TIMER_CONTROL + (timer << 2);
+
+    ulTimerValue =
+          FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET)    /* Reset the raw interrupt */
+        | FIELD_SET(0, TIMER_CONTROL, ENABLE, DISABLE);        /* Stop the timer */
+
+    pokeRegisterDWord(ulTimerAddr, ulTimerValue);
+
+    gTimerCounter[timer] = 0;
+}
+
+/*
+ * This function read the current value in the timer counter.
+ *
+ * Note: When timer is disable, always read back 0.
+ */
+unsigned long timerGetCounter(
+    timer_number_t timer         /* which timer: 0 to 3 */
+)
+{  
+    unsigned long ulTimerAddr, ulCounter;
+
+    /* Work out the timer's MMIO address 
+       Timer 0 address + ( timer number x 4 )
+    */
+    ulTimerAddr = TIMER_CONTROL + (timer << 2);
+    ulCounter = FIELD_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, COUNTER);
+
+    return(ulCounter);
+}
+
+/*
+ * This function gets the countdown setting stored in timer.
+ * Function timerGetCounter() can only get the current counter value.
+ * It cannot get the original countdown setting of timer.
+ *
+ * Note: When timer is disable, always read back 0.
+ */
+unsigned long timerGetCounterSetting(
+    timer_number_t timer         /* which timer: 0 to 3 */
+)
+{
+    /* The counter value put in timer cannot be read back from the register.
+       It has to keep in global variable.
+    */
+    return(gTimerCounter[timer]);
+}
+
+/* 
+ * This funciton uses the timer to wait a specific amount of time
+ * in micro-second.
+ */
+void timerWait(
+    timer_number_t timer,
+    unsigned long microSeconds
+)
+{
+    unsigned long ticks;
+	unsigned long retry = 1000;
+
+    // Limit  max delay to 10 seconds 
+    if (microSeconds > 10000000)
+        microSeconds = 10000000;
+
+    ticks = calcTimerCounter(microSeconds);
+
+    //Tick count is based on enabling DIV 16.
+    //Third parameter to timerStart is 1.
+    timerStart(timer, ticks, 1);
+
+    while (!timerRawIntPending(timer) && --retry);
+
+    timerStop(timer);
+}
+
+/* 
+ * This funciton uses the timer to wait a specific ticks of master clock
+ *
+ */
+void timerWaitTicks(
+    timer_number_t timer, /* Use timer 0, 1, 2 or 3 */
+    unsigned long ticks
+)
+{
+	unsigned long retry = 1000;
+    //Counter is 28 bits only.
+    ticks &= 0xFFFFFFF;
+
+    timerStart(timer, ticks, 0);
+
+    while (!timerRawIntPending(timer) && --retry);
+
+    timerStop(timer);
+}
+
+/* 
+ * This function returns the INT mask for a specific timer.
+ *
+ */
+unsigned long timerIntMask(
+    timer_number_t timer        /* Which timer: 0 to 3 */
+)
+{
+    unsigned long mask;
+
+    mask = 0;
+    switch (timer)
+    {
+        case 0:
+            mask |= FIELD_SET(0, INT_MASK, TIMER0, ENABLE);
+            break;
+        case 1:
+            mask |= FIELD_SET(0, INT_MASK, TIMER1, ENABLE);
+            break;
+        case 2:
+            mask |= FIELD_SET(0, INT_MASK, TIMER2, ENABLE);
+            break;
+        case 3:
+            mask |= FIELD_SET(0, INT_MASK, TIMER3, ENABLE);
+            break;
+        default:
+            break;
+    }
+
+    return mask;
+}
+
+/*
+ * This is a reference sample showing how to implement ISR for timers.
+ * It works together with libsrc\intr.c module.
+ * 
+ * Refer to Apps\timer\tstimer.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+void timerIsrTemplate(unsigned long status)
+{
+    if (FIELD_GET(status, INT_STATUS, TIMER0) == INT_STATUS_TIMER0_ACTIVE)
+    {
+        /* Perform ISR action for timer 0 here */
+        incTestCounter();
+
+        timerClearRawInt(0);
+    }            
+
+    if (FIELD_GET(status, INT_STATUS, TIMER1) == INT_STATUS_TIMER1_ACTIVE)
+    {
+        /* Perform ISR action for timer 1 here */
+        incTestCounter();
+
+        timerClearRawInt(1);
+    }            
+
+    if (FIELD_GET(status, INT_STATUS, TIMER2) == INT_STATUS_TIMER2_ACTIVE)
+    {
+        /* Perform ISR action for timer 2 here */
+        incTestCounter();
+
+        timerClearRawInt(2);
+    }            
+
+    if (FIELD_GET(status, INT_STATUS, TIMER3) == INT_STATUS_TIMER3_ACTIVE)
+    {
+        /* Perform ISR action for timer 3 here */
+        incTestCounter();
+
+        timerClearRawInt(3);
+    }            
+}
+
+
+void timerWaitMsec(
+    unsigned long milliSeconds
+)
+{
+    timer_number_t timer = TIMER3;
+    unsigned long ticks;
+
+    /* Calculate how many ticks are needed for the amount of time.   */
+    ticks = 168000 * milliSeconds;
+
+    timerStart(timer, ticks, 0);
+
+    while (!timerRawIntPending(timer));
+
+    timerStop(timer);
+}
+
+void timerWaitUsec(
+    unsigned long USeconds
+)
+{
+    timer_number_t timer = TIMER3;
+    unsigned long ticks;
+
+    /* Calculate how many ticks are needed for the amount of time.   */
+    ticks = 168 * USeconds;
+
+    timerStart(timer, ticks, 0);
+
+    while (!timerRawIntPending(timer));
+
+    timerStop(timer);
+}
+
+
+
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.h
new file mode 100644
index 000000000000..f2f0420960cd
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_timer.h
@@ -0,0 +1,150 @@
+/*******************************************************************
+*
+*         Copyright (c) 2014 by Silicon Motion, Inc. (SMI)
+*
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+*
+*  This file contains the definitions for the timer functions.
+*
+*******************************************************************/
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+
+
+typedef enum _timer_number_t
+{
+    TIMER0 = 0,
+    TIMER1 = 1,
+    TIMER2 = 2,
+    TIMER3 = 3,
+}
+timer_number_t;
+
+/*
+ * Calculate a value for timer counter according to input time in micro-second.
+ * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks.
+ */
+unsigned long calcTimerCounter(
+    unsigned long microSeconds
+);
+
+/*
+ * This function start the timer with raw interrupt enabled.
+ * When the timer decrements to 0, timer raw interrupt will be generated.
+ *
+ * Raw interrupt of the timers can be used in one of 2 ways:
+ * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0.
+ * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system.
+ *
+ */
+void timerStart(
+    timer_number_t timer,         /* which timer: 0 to 3 */
+    unsigned long timerCounter,      /* Timer counter: use calcTimerCounter() to work out a counter for a specific period. */
+    unsigned long div16Enable     /* Enable the 16 divisor, time out will be increased by 16 */
+);
+
+/*
+ * This function checks if a timer's raw interrupt has been pending.
+ * When raw interrupt is detected with pending status, it indicate the
+ * countdown of timerStart() has been completed.
+ *
+ * Return:
+ *        1 = Raw interrupt status is pending.
+ *        0 = Raw int is NOT pending.
+ */
+unsigned long timerRawIntPending(
+    timer_number_t timer         /* which timer: 0 to 3 */
+);
+
+/*
+ * This function clears the RAW interrupt status of the timer.
+ *
+ * When a timer completes countdown, the raw interrupt bit will be set.
+ * It has to be cleared, in order to distinguish between different sessions of countdown.
+ *
+ */
+void timerClearRawInt(
+    timer_number_t timer         /* which timer: 0 to 3 */
+);
+
+/*
+ * This function stop the timer.
+ *
+ */
+void timerStop(
+    timer_number_t timer         /* which timer: 0 to 3 */
+);
+
+/*
+ * This function read the current value in the timer counter.
+ *
+ * Note: When timer is disable, always read back 0.
+ */
+unsigned long timerGetCounter(
+    timer_number_t timer         /* which timer: 0 to 3 */
+);
+
+/*
+ * This function gets the countdown setting stored in timer.
+ * Function timerGetCounter() can only get the current counter value.
+ * It cannot get the original countdown setting of timer.
+ *
+ * Note: When timer is disable, always read back 0.
+ */
+unsigned long timerGetCounterSetting(
+    timer_number_t timer         /* which timer: 0 to 3 */
+);
+
+/* 
+ * This funciton uses the timer to wait a specific amount of time
+ * in micro-second.
+ */
+void timerWait(
+    timer_number_t timer,
+    unsigned long microSeconds
+);
+
+/* 
+ * This funciton uses the timer to wait a specific ticks of master clock
+ *
+ */
+void timerWaitTicks(
+    timer_number_t timer, /* Use timer 0, 1, 2 or 3 */
+    unsigned long ticks
+);
+
+/* 
+ * This function returns the INT mask for a specific timer.
+ *
+ */
+unsigned long timerIntMask(
+    timer_number_t timer        /* Which timer: 0 to 3 */
+);
+
+unsigned long getTestCounter(void);
+
+void setTestCounter(unsigned long value);
+
+/*
+ * This is a reference sample showing how to implement ISR for timers.
+ * It works together with libsrc\intr.c module.
+ * 
+ * Refer to Apps\timer\tstimer.c on how to hook up this function with system
+ * interrupt under WATCOM DOS extender.
+ * 
+ */
+void timerIsrTemplate(unsigned long status);
+
+void timerWaitMsec(
+    unsigned long milliSeconds
+);
+
+void timerWaitUsec(
+    unsigned long USeconds
+);
+#define sb_OS_WAIT_MSEC_POLL(ms) timerWaitMsec(ms)
+#define sb_OS_WAIT_USEC_POLL(us) timerWaitUsec(us)
+#endif /* _TIMER_H_ */
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_video.c b/drivers/gpu/drm/smifb2/ddk768/ddk768_video.c
new file mode 100644
index 000000000000..4de5af27cb48
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_video.c
@@ -0,0 +1,1153 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  Video.C --- Falcon SDK 
+*  This file contains the definitions for the Video functions.
+* 
+*******************************************************************/
+#include "ddk768_help.h"
+#include "ddk768_chip.h"
+#include "ddk768_mode.h"
+#include "ddk768_video.h"
+#include "ddk768_reg.h"
+
+
+/* New video function */
+
+#define SCALE_CONSTANT                      (1 << 12)
+
+/* Offset Adjustment for the window */
+static short gWidthAdjustment = 0;
+static short gHeightAdjustment = 0;
+
+/* Source Video Width and Height */
+static unsigned long gSrcVideoWidth = 0;
+static unsigned long gSrcVideoHeight = 0;
+
+/*
+ *  videoSetWindowAdjustment
+ *      This function sets the video window adjustment. There are usually
+ *      some garbage lines or pixels at the bottom and right of the video
+ *      window. These function will adjust the video window accordingly.
+ *
+ *  Input:
+ *      widthAdjustment     - Width adjustments in pixel
+ *      heightAdjustment    - Height adjustment in line        
+ */
+void videoSetWindowAdjustment(
+	unsigned dispCtrl,
+    short widthAdjustment,
+    short heightAdjustment
+)
+{
+    unsigned long width, height;
+    videoGetWindowSize(dispCtrl, &width, &height);
+    
+    gWidthAdjustment = widthAdjustment;
+    gHeightAdjustment = heightAdjustment;
+    
+    videoSetWindowSize(dispCtrl, width, height);
+}
+
+/*
+ *  videoGetWindowAdjustment
+ *      This function gets the video window adjustment.
+ *
+ *  Input:
+ *      widthAdjustment     - Width adjustments in pixel
+ *      heightAdjustment    - Height adjustment in line 
+ */
+void videoGetWindowAdjustment(
+    short *pWidthAdjustment,
+    short *pHeightAdjustment
+)
+{
+    if (pWidthAdjustment != ((short *)0))
+        *pWidthAdjustment = gWidthAdjustment;
+    
+    if (pHeightAdjustment != ((short *)0))
+        *pHeightAdjustment = gHeightAdjustment;
+}
+
+/*
+ * videoGetBufferStatus
+ *      This function gets the status of the video buffer, either the buffer
+ *      has been used or not.
+ *
+ *  Input:
+ *      bufferIndex     - The index of the buffer which size to be retrieved
+ *
+ *  Output:
+ *      0 - No flip pending
+ *      1 - Flip pending
+ */
+unsigned long videoGetBufferStatus(
+    unsigned long bufferIndex
+)
+{
+        return (FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, STATUS));
+}
+
+/*
+ * videoGetPitch
+ *      This function gets the video plane pitch
+ *
+ * Output:
+ *      pitch   - Number of bytes per line of the video plane 
+ *                specified in 128-bit aligned bytes.
+ */
+unsigned short videoGetPitch()
+{
+    return (FIELD_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, WIDTH));
+}
+
+/*
+ * videoGetLineOffset
+ *      This function gets the video plane line offset
+ *
+ * Output:
+ *      lineOffset  - Number of 128-bit aligned bytes per line 
+ *                    of the video plane.
+ */
+unsigned short videoGetLineOffset()
+{
+    return (FIELD_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, OFFSET));
+}
+
+/*
+ * videoGetBufferSize
+ *      This function gets the buffer size
+ *
+ *  Input:
+ *      bufferIndex - The index of the buffer which size to be retrieved
+ */
+unsigned long videoGetBufferSize(
+    unsigned long bufferIndex
+)
+{
+    unsigned long value = 0;
+    
+    if (bufferIndex == 0)
+    {
+        value = (unsigned long)
+            FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS);
+    }
+    
+    return value;
+}
+
+
+/*
+ * videoGetBuffer
+ *      This function gets the video buffer
+ *
+ *  Input:
+ *      bufferIndex - The index of the buffer to get
+ *
+ *  Output:
+ *      The video buffer of the requested index.
+ */
+unsigned long videoGetBuffer(
+    unsigned char bufferIndex
+)
+{
+        return (FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS));
+}
+
+/*
+ * videoSetBufferLastAddress
+ *      This function sets the video buffer last address.
+ *      The value can be calculated by subtracting one line offset 
+ *      from the buffer size (Total number of line offset * 
+ *      source video height).
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer to be set
+ *      bufferSize          - Size of the video buffer.
+ */
+void videoSetBufferLastAddress(
+    unsigned char bufferIndex,          /* The index of the buffer to be set. */
+    unsigned long bufferStart,          /* Buffer start */
+    unsigned long bufferSize            /* Size of the video buffer */
+)
+{
+#if 0
+
+	if (getChipType() == SM750)    
+	{
+	    /* Substract with one line offset to get the last address value when added
+	       with the bufferStart. Somehow, this is only happen in SM750 chip */    
+	    bufferSize -= (unsigned long) videoGetLineOffset();
+	}
+
+    if (bufferIndex == 0)
+    {
+        /* Set Video Buffer 0 Last Address */
+        pokeRegisterDWord(VIDEO_FB_0_LAST_ADDRESS,
+            FIELD_VALUE(0, VIDEO_FB_0_LAST_ADDRESS, ADDRESS, bufferStart + bufferSize));
+    }
+    else
+    {   
+        /* Set Video Buffer 1 Last Address */ 
+        pokeRegisterDWord(VIDEO_FB_1_LAST_ADDRESS,
+            FIELD_VALUE(0, VIDEO_FB_1_LAST_ADDRESS, ADDRESS, bufferStart + bufferSize));
+    }
+#endif
+}
+
+/*
+ * videoGetBufferLastAddress
+ *      This function gets the video buffer last address.
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer last address to be retrieved
+ */
+unsigned long videoGetBufferLastAddress(
+    unsigned char bufferIndex           /* The index of the buffer last address to be retrieved. */
+)
+{
+#if 0
+    if (bufferIndex == 0)
+    {
+        /* Get Video Buffer 0 Last Address */
+        return (unsigned long) (FIELD_GET(peekRegisterDWord(VIDEO_FB_0_LAST_ADDRESS), 
+                                          VIDEO_FB_0_LAST_ADDRESS, ADDRESS));
+    }
+    else
+    {   
+        /* Get Video Buffer 1 Last Address */ 
+        return (unsigned long) (FIELD_GET(peekRegisterDWord(VIDEO_FB_1_LAST_ADDRESS), 
+                                          VIDEO_FB_1_LAST_ADDRESS, ADDRESS));
+    }
+#endif
+	return 0;
+}
+
+/*
+ * videoSetBuffer
+ *      This function sets the video buffer
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer to be set
+ *      bufferStartAddress  - The starting address of the buffer
+ */
+void videoSetBuffer(
+	unsigned dispCtrl,
+    unsigned char bufferIndex,          /* The index of the buffer to be set. */
+    unsigned long bufferStartAddress    /* Video buffer with 128-bit alignment */
+)
+{
+    unsigned long bufferSize, lastAddress;
+	unsigned long regFB;
+
+    /* Get the buffer size first */
+    bufferSize = videoGetBufferSize(bufferIndex);
+    
+    lastAddress = videoGetBufferLastAddress(bufferIndex);
+#if 0    
+	if (getChipType() == SM750)    
+	{
+	    if (lastAddress <= (bufferStartAddress + bufferSize - videoGetLineOffset()))
+	        videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize);
+    }
+    else
+#endif
+    {
+		if (lastAddress <= (bufferStartAddress + bufferSize))
+	        videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize);
+    }
+
+    if (bufferIndex == 0)
+    {
+		regFB = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS : (VIDEO_FB_ADDRESS+CHANNEL_OFFSET);
+	    pokeRegisterDWord(regFB,
+	            FIELD_SET(0, VIDEO_FB_ADDRESS, STATUS, PENDING) |
+	            FIELD_VALUE(0, VIDEO_FB_ADDRESS, ADDRESS, bufferStartAddress));
+    }
+}
+/*
+ * videoSetUVBuffer
+ *      This function sets the video buffer
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer to be set
+ *      bufferStartAddress  - The starting address of the buffer
+ */
+void videoSetUVBuffer(
+	unsigned dispCtrl,
+    unsigned long bufferStartUAddress,    /* Video buffer with 128-bit alignment */
+    unsigned long bufferStartVAddress    /* Video buffer with 128-bit alignment */
+)
+{
+	unsigned long regU, regV;
+
+	regU = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS_U : (VIDEO_FB_ADDRESS_U+CHANNEL_OFFSET);
+	regV = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS_V : (VIDEO_FB_ADDRESS_V+CHANNEL_OFFSET);
+    pokeRegisterDWord(regU,
+        FIELD_VALUE(0, VIDEO_FB_ADDRESS_U, ADDRESS, bufferStartUAddress));
+    pokeRegisterDWord(regV,
+        FIELD_VALUE(0, VIDEO_FB_ADDRESS_V, ADDRESS, bufferStartVAddress));
+}
+
+/*
+ * videoSetPitchOffset
+ *      This function sets the video plane pitch and offset
+ *
+ *  Input:
+ *      pitch           - Number of bytes per line of the video plane 
+ *                        specified in 128-bit aligned bytes.
+ *      lineOffset      - Number of 128-bit aligned bytes per line 
+ *                        of the video plane.
+ */
+void videoSetPitchOffset(
+	unsigned dispCtrl,
+    unsigned short pitch,
+    unsigned short lineOffset
+)
+{
+	unsigned long regWidth;
+
+    /* Set Video Buffer Offset (pitch) */
+	regWidth = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH : (VIDEO_FB_WIDTH+CHANNEL_OFFSET);
+	pokeRegisterDWord(regWidth,
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH, WIDTH, pitch) |
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH, OFFSET, lineOffset));
+}
+/*
+ * videoSetUVPitchOffset
+ *      This function sets the video plane pitch and offset of U and V
+ *
+ *  Input:
+ *      pitch           - Number of bytes per line of the video plane 
+ *                        specified in 128-bit aligned bytes.
+ *      lineOffset      - Number of 128-bit aligned bytes per line 
+ *                        of the video plane.
+ */
+void videoSetUVPitchOffset(
+	unsigned dispCtrl,
+    unsigned short pitch,
+    unsigned short lineOffset
+)
+{
+	unsigned long regWidthU, regWidthV;
+	regWidthU = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH_U : (VIDEO_FB_WIDTH_U+CHANNEL_OFFSET);
+	regWidthV =	(dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH_V : (VIDEO_FB_WIDTH_V+CHANNEL_OFFSET);
+	pokeRegisterDWord(regWidthU,
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH_U, WIDTH, pitch) |
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH_U, OFFSET, lineOffset));
+	pokeRegisterDWord(regWidthV,
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH_V, WIDTH, pitch) |
+	    FIELD_VALUE(0, VIDEO_FB_WIDTH_V, OFFSET, lineOffset));
+}
+/*
+ *  videoSetLast 
+ *      This function sets the video source last lines and width.
+ *
+ *  Input:
+ *
+ *      width      - Video source width
+ *      height      - Video source height
+ */
+void videoSetLast(
+	unsigned dispCtrl,
+    unsigned long width,
+    unsigned long height
+)
+{
+#if 0 // SM768 don't have this register. Leave empty function here.
+    if (dispCtrl == CHANNEL0_CTRL)
+	{
+	    pokeRegisterDWord(CHANNEL0_VIDEO_LAST, 
+	        FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, COLUMN, width) |
+	        FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, ROW, height)); 
+	}
+	else
+	{
+	    pokeRegisterDWord(CHANNEL1_VIDEO_LAST, 
+	        FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, COLUMN, width) |
+	        FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, ROW, height)); 
+	}													   
+#endif
+}
+/*
+ *  videoSetWindowSize
+ *      This function sets the video window size.
+ *
+ *  Input:
+ *      width       - Video Window width
+ *      height      - Video Window height
+ */
+void videoSetWindowSize(
+	unsigned dispCtrl,
+    unsigned long width,
+    unsigned long height
+)
+{
+    unsigned long value, startX, startY;
+	unsigned long regTL, regBR;
+	regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET);
+	regBR = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_BR : (VIDEO_PLANE_BR+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regTL);
+	startX = FIELD_GET(value, VIDEO_PLANE_TL, LEFT);
+	startY = FIELD_GET(value, VIDEO_PLANE_TL, TOP);
+
+	/* Set bottom and right position */
+	pokeRegisterDWord(regBR,
+	    FIELD_VALUE(0, VIDEO_PLANE_BR, BOTTOM, startY + height - 1 - gHeightAdjustment) |
+	    FIELD_VALUE(0, VIDEO_PLANE_BR, RIGHT, startX + width - 1 - gWidthAdjustment)); 
+}
+
+/*
+ *  videoGetWindowSize
+ *      This function gets the video window size.
+ *
+ *  Output:
+ *      width       - Video Window width
+ *      height      - Video Window height
+ */
+void videoGetWindowSize(
+	unsigned dispCtrl,
+    unsigned long *pVideoWidth,
+    unsigned long *pVideoHeight
+)
+{
+    unsigned long positionTopLeft, positionRightBottom;
+    unsigned long videoWidth, videoHeight;
+	unsigned long regTL, regBR;
+	regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET);
+	regBR = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_BR : (VIDEO_PLANE_BR+CHANNEL_OFFSET);
+
+	positionTopLeft = peekRegisterDWord(regTL);
+	positionRightBottom = peekRegisterDWord(regBR);
+	videoWidth  = FIELD_GET(positionRightBottom, VIDEO_PLANE_BR, RIGHT) - 
+	              FIELD_GET(positionTopLeft, VIDEO_PLANE_TL, LEFT) + 1 +
+	              gWidthAdjustment;
+	videoHeight = FIELD_GET(positionRightBottom, VIDEO_PLANE_BR, BOTTOM) - 
+	              FIELD_GET(positionTopLeft, VIDEO_PLANE_TL, TOP) + 1 +
+	              gHeightAdjustment;
+
+    if (pVideoWidth != ((unsigned long *)0))
+        *pVideoWidth = videoWidth;
+    
+    if (pVideoHeight != ((unsigned long *)0))
+        *pVideoHeight = videoHeight;
+}
+
+/*
+ *  videoSetPosition
+ *      This function sets the video starting coordinate position.
+ *
+ *  Input:
+ *      startX      - X Coordinate of the video window starting position
+ *      startY      - Y Coordinate of the video window starting position
+ */
+void videoSetPosition(
+	unsigned dispCtrl,
+    unsigned long startX,
+    unsigned long startY
+)
+{
+    unsigned long videoWidth, videoHeight;
+	unsigned long regTL;
+
+	regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET);
+
+	/* Get the video window width and height */
+    videoGetWindowSize(dispCtrl, &videoWidth, &videoHeight);
+
+	pokeRegisterDWord(regTL,
+	    FIELD_VALUE(0, VIDEO_PLANE_TL, TOP, startY) |
+	    FIELD_VALUE(0, VIDEO_PLANE_TL, LEFT, startX));
+
+    /* Set bottom and right position */    
+    videoSetWindowSize(dispCtrl, videoWidth, videoHeight);
+
+}
+
+/*
+ *  videoSetConstants
+ *      This function sets the video constants. The actual component will be
+ *      added by this constant to get the expected component value.
+ *
+ *  Input:
+ *      yConstant       - Y Constant Value
+ *      redConstant     - Red Constant Value
+ *      greenConstant   - Green Constant Value
+ *      blueConstant    - Blue Constant Value
+ */
+void videoSetConstants(
+    unsigned dispCtrl,
+    unsigned char  yConstant,               /* Y Adjustment */
+    unsigned char  redConstant,             /* Red Conversion constant */
+    unsigned char  greenConstant,           /* Green Conversion constant */
+    unsigned char  blueConstant             /* Blue Conversion constant */
+)
+{
+	unsigned long regYUV;
+
+	regYUV = (dispCtrl == CHANNEL0_CTRL)? VIDEO_YUV_CONSTANTS : (VIDEO_YUV_CONSTANTS+CHANNEL_OFFSET);
+	pokeRegisterDWord(regYUV,
+	    FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, Y, yConstant) |
+	    FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, R, redConstant) |
+	    FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, G, greenConstant) |
+	    FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, B, blueConstant));
+}
+
+/*
+ *  videoSetInitialScale
+ *      This function sets the video buffer initial vertical scale.
+ *
+ *  Input:
+ *      bufferIndex         - Index of the buffer which vertical scale value
+ *                            to be set.
+ *      bufferInitScale     - Buffer Initial vertical scale value
+ */
+void videoSetInitialScale(
+	unsigned dispCtrl,
+    unsigned short InitScaleHorizontal,
+    unsigned short InitScaleVertical
+)
+{
+    unsigned long value;
+	unsigned long regScale;
+
+	regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_INITIAL_SCALE : (VIDEO_INITIAL_SCALE+CHANNEL_OFFSET);
+
+    value = peekRegisterDWord(regScale);
+    value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, VERTICAL, InitScaleVertical);
+    value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, HORIZONTAL, InitScaleHorizontal);
+    pokeRegisterDWord(regScale, value);
+}
+
+/*
+ *  videoGetInitialScale
+ *      This function gets the video buffer initial vertical scale.
+ *
+ *  Input:
+ *      pbuffer0InitScale   - Pointer to variable to store buffer 0 initial vertical scale
+ *      pbuffer1InitScale   - Pointer to variable to store buffer 1 initial vertical scale
+ */
+void videoGetInitialScale(
+	unsigned dispCtrl,
+    unsigned short *pBufferVInitScale,
+    unsigned short *pBufferHInitScale
+)
+{
+	unsigned long regScale;
+
+	regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_INITIAL_SCALE : (VIDEO_INITIAL_SCALE+CHANNEL_OFFSET);
+
+    *pBufferHInitScale = (unsigned short)
+        FIELD_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, HORIZONTAL);
+    *pBufferVInitScale = (unsigned short)
+        FIELD_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, VERTICAL);
+}
+
+/*
+ *  videoScale
+ *      This function scales the video.
+ *
+ *  Input:
+ *      srcWidth     - The source video width
+ *      srcHeight    - The source video height
+ *      dstWidth     - The destination video width 
+ *      dstHeight    - The destination video height
+ */
+void videoScale(
+	unsigned dispCtrl,
+    unsigned long srcWidth,
+    unsigned long srcHeight,
+    unsigned long dstWidth,
+    unsigned long dstHeight
+)
+{
+    unsigned long value = 0;
+    unsigned long scaleFactor;
+	unsigned long regScale;
+
+	regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_SCALE : (VIDEO_SCALE+CHANNEL_OFFSET);
+
+	if (dstHeight >= srcHeight)
+	{
+	    /* Calculate the factor */
+	    scaleFactor = (srcHeight-1) * SCALE_CONSTANT / dstHeight;
+	    value = FIELD_VALUE(value, VIDEO_SCALE , VERTICAL_SCALE, scaleFactor);
+	}
+	
+	/* Scale the horizontal size */
+	if (dstWidth >= srcWidth)
+	{
+	    /* Calculate the factor */
+	    scaleFactor = (srcWidth-1) * SCALE_CONSTANT / dstWidth;
+	    value = FIELD_VALUE(value, VIDEO_SCALE, HORIZONTAL_SCALE, scaleFactor);
+	}
+	
+	pokeRegisterDWord(regScale, value);
+}
+
+
+/*
+ *  videoSwapYUVByte
+ *      This function swaps the YUV data byte.
+ *
+ *  Input:
+ *      byteSwap    - Flag to enable/disable YUV data byte swap.
+ */
+void videoSwapYUVByte(
+	unsigned dispCtrl,
+   	video_byteswap_t byteSwap  
+)
+{
+    unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	if (byteSwap == SWAP_BYTE)
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, ENABLE);
+	else
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, DISABLE);
+	
+	pokeRegisterDWord(regCtrl, value);
+}
+
+/*
+ *  videoSetInterpolation
+ *      This function enables/disables the horizontal and vertical interpolation.
+ *
+ *  Input:
+ *      enableHorzInterpolation   - Flag to enable/disable Horizontal interpolation
+ *      enableVertInterpolation   - Flag to enable/disable Vertical interpolation
+ */
+void videoSetInterpolation(
+	unsigned dispCtrl,
+    unsigned long enableHorzInterpolation,
+    unsigned long enableVertInterpolation
+)
+{
+    unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	
+	if (enableHorzInterpolation)
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, INTERPOLATE);
+	else
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, REPLICATE);
+	    
+	if (enableVertInterpolation)
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, INTERPOLATE);
+	else
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, REPLICATE);
+	    
+	pokeRegisterDWord(regCtrl, value);
+}
+
+/*
+ *  videoGetInterpolation
+ *      This function gets the horizontal and vertical interpolation enable status.
+ *
+ *  Input:
+ *      pHorzInterpolationStatus	- Pointer to store the horizontal interpolation status
+ *      pVertInterpolationStatus	- Pointer to store the vertical interpolation status
+ */
+void videoGetInterpolation(
+    unsigned long *pHorzInterpolationStatus,
+    unsigned long *pVertInterpolationStatus
+)
+{
+    unsigned long value;
+    
+    value = peekRegisterDWord(VIDEO_DISPLAY_CTRL);
+    if (pHorzInterpolationStatus != (unsigned long *)0)
+	{
+		if (FIELD_GET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE) == VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE)
+        	*pHorzInterpolationStatus = 1;
+		else
+			*pHorzInterpolationStatus = 0;
+	}
+        
+    if (pHorzInterpolationStatus != (unsigned long *)0)
+	{
+		if (FIELD_GET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE) == VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE)
+			*pVertInterpolationStatus = 1;
+		else
+			*pVertInterpolationStatus = 0;
+	}
+}
+
+/*
+ *  videoSetStartPanningPixel
+ *      This function sets the starting pixel number for smooth pixel panning.
+ *
+ *  Input:
+ *      startPixel  - Starting pixel number for smooth pixel panning
+ */
+void videoSetStartPanningPixel(
+    unsigned char startPixel
+)
+{
+    pokeRegisterDWord(VIDEO_DISPLAY_CTRL, 
+                      peekRegisterDWord(VIDEO_DISPLAY_CTRL) | 
+                      FIELD_VALUE(0, VIDEO_DISPLAY_CTRL, PIXEL, startPixel));    
+}
+
+/*
+ *  videoSetGamma
+ *      This function enables/disables gamma control.
+ *
+ *  Input:
+ *      enableGammaCtrl - The gamma enable control
+ *
+ *  NOTE:
+ *      The gamma can only be enabled in RGB565 and RGB888. Enable this gamma
+ *      without proper format will have no effect.
+ */
+void videoSetGammaCtrl(
+    unsigned dispCtrl,
+    unsigned long enableGammaCtrl
+)
+{
+    unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	
+	if (enableGammaCtrl)
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, ENABLE);
+	else
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, DISABLE);
+	    
+	pokeRegisterDWord(regCtrl, value);    
+}
+
+/*
+ *  isVideoEnable
+ *      This function check whether the video plane is already enabled or not.
+ *
+ *  Output:
+ *      0   - Disable
+ *      1   - Enable
+ */
+unsigned char isVideoEnable()
+{
+    unsigned long value;
+    
+    value = peekRegisterDWord(VIDEO_DISPLAY_CTRL);
+    
+    return ((FIELD_GET(value, VIDEO_DISPLAY_CTRL, PLANE) == VIDEO_DISPLAY_CTRL_PLANE_ENABLE) ? 1 : 0);
+}
+
+/*
+ *  videoSetCtrl
+ *      This function enable/disable the video plane.
+ *
+ *  Input:
+ *      videoCtrl   - Enable/Disable video
+ */
+static void videoSetCtrl(
+    disp_control_t dispCtrl,
+    video_ctrl_t videoCtrl
+)
+{
+    unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	
+	if (videoCtrl == VIDEO_ON)
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, ENABLE);
+	else
+	    value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, DISABLE);
+	            
+	pokeRegisterDWord(regCtrl, value); 
+}
+
+/*
+ *  videoSetFormat
+ *      This function sets the video format.
+ *
+ *  Input:
+ *      videoFormat - The video content format
+ *                    * FORMAT_RGB565 - 16-bit RGB 5:6:5 mode
+ *                    * FORMAT_YUYV - 16-bit YUYV mode
+ */
+static void videoSetFormat(
+    unsigned dispCtrl,
+    video_format_t  videoFormat
+)
+{
+    unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	switch (videoFormat)
+	{
+	    default:
+	    case FORMAT_RGB565:
+	        value = FIELD_SET(value,  VIDEO_DISPLAY_CTRL , FORMAT, 16);
+	        break;
+	    case FORMAT_RGB888:
+	        value = FIELD_SET(value,  VIDEO_DISPLAY_CTRL , FORMAT, 32);
+	        break;
+	    case FORMAT_YUYV:
+	        value = FIELD_SET(value,  VIDEO_DISPLAY_CTRL , FORMAT, YUV422);
+	        break;
+	    case FORMAT_YUV420:
+	        value = FIELD_SET(value,  VIDEO_DISPLAY_CTRL , FORMAT, YUV420);
+	        break;
+	}
+	
+	pokeRegisterDWord(regCtrl, value);
+}
+
+/*
+ *  videoSetEdgeDetection
+ *      This function enable/disable the edge detection and fill out the edge detection
+ *      value as well. This function only works in SM718. SM750 does not support this
+ *      feature.
+ *
+ *  Input:
+ *      enableEdgeDetect    - Enable/Disable Edge Detection (0 - disable, 1 = enable)
+ *      edgeDetectValue     - The Edge Detection value. This is the difference (delta)
+ *                            of the pixel colors to be considered as an edge.
+ *
+ *  Note:
+ *      This edge correction only works in up-scale video.
+ */
+void videoSetEdgeDetection(
+    unsigned long enableEdgeDetect,
+    unsigned long edgeDetectValue
+)
+{
+#if 0 //SM768 don't have this register. Just leave an empty function here.
+    unsigned long value;
+    
+    if (getChipType() == SM718)
+    {
+        if (enableEdgeDetect == 1)
+        {
+            value = FIELD_SET(0, VIDEO_EDGE_DETECTION, DETECT, ENABLE) |
+                    FIELD_VALUE(value, VIDEO_EDGE_DETECTION, VALUE, edgeDetectValue);
+            pokeRegisterDWord(VIDEO_EDGE_DETECTION, value); 
+        }
+        else
+        {
+            value = FIELD_SET(peekRegisterDWord(VIDEO_EDGE_DETECTION), VIDEO_EDGE_DETECTION, DETECT, DISABLE);
+            pokeRegisterDWord(VIDEO_EDGE_DETECTION, value);
+        }
+    }
+#endif
+}
+
+/*
+ *  videoGetEdgeDetection
+ *      This function gets the information whether the edge detection is enabled or not.
+ *      It also outputs the edge detection value if required.
+ *      This function only works in SM718. SM750 does not support this feature.
+ *
+ *  Input:
+ *      pEdgeDetectValue    - Pointer to a buffer to store the edge detection value.
+ *
+ *  Note:
+ *      0   - Edge Detection is disabled
+ *      1   - Edge Detection is enabled
+ */
+unsigned long videoGetEdgeDetection(
+    unsigned long *pEdgeDetectValue
+)
+{
+#if 0 //Not for SM768
+    unsigned long value;
+    
+    if (getChipType() == SM718)
+    {
+        value = peekRegisterDWord(VIDEO_EDGE_DETECTION);
+        
+        if (pEdgeDetectValue != (unsigned long *)0)
+            *pEdgeDetectValue = (unsigned long) FIELD_GET(value, VIDEO_EDGE_DETECTION, VALUE);
+            
+        if (FIELD_GET(value, VIDEO_EDGE_DETECTION, DETECT) == VIDEO_EDGE_DETECTION_DETECT_ENABLE)
+            return 1;
+        else
+            return 0; 
+    }
+#endif    
+    return 0;
+}
+
+/*
+ *  videoSetup
+ *      This function setups the video. This function only works in SM718. 
+ *      SM750 does not support edge detection feature. If calling this function
+ *      in SM750, set edgeDetect flag to 0
+ *
+ *  Input:
+ *      x               - X Coordinate of the video window
+ *      y               - Y Coordinate of the video window
+ *      srcWidth        - The source video width
+ *      srcHeight       - The source video height
+ *      dstWidth        - The destination video width
+ *      dstHeight       - The destination video height
+ *      doubleBuffer    - Double Buffer enable flag
+ *      srcAddress0     - The source of the video buffer 0 to display
+ *      srcAddress1     - The source of the video buffer 1 to display
+ *                        (only for double buffering).
+ *      srcPitch        - The source video plane pitch in bytes
+ *      srcLineOffset   - The source video plane line offset in bytes.
+ *                        In normal usage, set it the same as the srcBufferPitch
+ *      videoFormat     - Source video format
+ *      edgeDetect      - Edge Detection enable flag (can only works with vertical upscaling)
+ *                              0 - Disable
+ *                              1 - Always Enable (alwasy enabled regardless horizontal scaling condition)
+ *                              2 - Auto Enable (only enabled when no horizontal shrink)
+ *      edgeDetectValue - Edge Detection value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1  - Fail
+ */
+unsigned char videoSetupEx(
+	unsigned dispCtrl,
+    unsigned long x,                /* X Coordinate of the video window */
+    unsigned long y,                /* Y Coordinate of the video window */
+    unsigned long srcWidth,         /* The source video width */
+    unsigned long srcHeight,        /* The source video height */
+    unsigned long dstWidth,         /* The destination video width */
+    unsigned long dstHeight,        /* The destination video height */
+    unsigned long doubleBuffer,     /* Double Buffer enable flag */
+    unsigned long srcAddress0,      /* The source of the video buffer 0 to display */
+    unsigned long sUAddress,            /* U Source Base Address (not used in RGB Space) */
+    unsigned long sVAddress,            /* V Source Base Address (not used in RGB Space) */
+    unsigned long sUVPitch,             /* UV plane pitch value in bytes (not used in */ 
+    unsigned long srcPitch,         /* The source video plane pitch in bytes */
+    unsigned long srcLineOffset,    /* The source video plane line offset in bytes.
+                                       Set it the same as srcPitch in normal
+                                       usage. */
+    video_format_t videoFormat,      /* Source video format */
+    unsigned long edgeDetect,       /* Edge Detection enable flag */
+    unsigned long edgeDetectValue   /* Edge Detection value. SM718 only use bit 9 to 0 */
+)
+{
+    unsigned long enableEdgeDetect;
+    /* Save the source video width and height */
+    gSrcVideoWidth = srcWidth;
+    gSrcVideoHeight = srcHeight;
+    /* Disable the video plane first */
+    videoSetCtrl(dispCtrl, VIDEO_OFF);
+    
+    /* Set the video position */
+    videoSetPosition(dispCtrl, x, y);
+    
+    /* Set the scale factor */
+    videoScale(dispCtrl, srcWidth, srcHeight, dstWidth, dstHeight);
+    
+    /* Set the video format */
+    videoSetFormat(dispCtrl, videoFormat);
+    
+    /* Set the buffer pitch */
+    videoSetPitchOffset(dispCtrl, srcPitch, srcLineOffset);
+    /* Set the UV buffer pitch */
+    videoSetUVPitchOffset(dispCtrl, sUVPitch, sUVPitch);
+    
+    /* Enable double buffer */
+//    videoEnableDoubleBuffer(doubleBuffer);
+    
+    /* Set the video buffer 0 and 1 */
+    videoSetBuffer(dispCtrl, 0, srcAddress0);
+//    videoSetBuffer(dispCtrl, 1, srcAddress1);
+   
+    /* Set the video buffer U and V */
+    videoSetUVBuffer(dispCtrl, sUAddress, sVAddress);
+        
+    /* Set the destination video window */
+    videoSetWindowSize(dispCtrl, dstWidth, dstHeight);
+
+    /* Set the last line */
+    videoSetLast(dispCtrl, srcWidth, srcHeight);
+    
+    /* Set the edge detection enable bit and its value (if applicable) */
+    if (edgeDetect == 0)
+        enableEdgeDetect = 0;
+    else if (edgeDetect == 1)
+        enableEdgeDetect = 1;
+    else
+    {
+        /* Only enable the edgeDetection when scaling up vertically and no 
+           shrinking on the horizontal. */
+        if ((dstHeight > srcHeight) && (dstWidth >= srcWidth))
+            enableEdgeDetect = 1;
+        else
+            enableEdgeDetect = 0;
+    }
+    videoSetEdgeDetection(enableEdgeDetect, edgeDetectValue);
+    
+    return 0;
+}
+
+/*
+ *  videoSetup
+ *      This function setups the video.
+ *
+ *  Input:
+ *      x               - X Coordinate of the video window
+ *      y               - Y Coordinate of the video window
+ *      srcWidth        - The source video width
+ *      srcHeight       - The source video height
+ *      dstWidth        - The destination video width
+ *      dstHeight       - The destination video height
+ *      doubleBuffer    - Double Buffer enable flag
+ *      srcAddress0     - The source of the video buffer 0 to display
+ *      srcAddress1     - The source of the video buffer 1 to display
+ *                        (only for double buffering).
+ *      srcPitch        - The source video plane pitch in bytes
+ *      srcLineOffset   - The source video plane line offset in bytes.
+ *                        In normal usage, set it the same as the srcBufferPitch
+ *      videoFormat     - Source video format
+ *
+ *  Output:
+ *      0   - Success
+ *     -1  - Fail
+ */
+unsigned char videoSetup(
+    disp_control_t dispCtrl,
+    unsigned long x,                /* X Coordinate of the video window */
+    unsigned long y,                /* Y Coordinate of the video window */
+    unsigned long srcWidth,         /* The source video width */
+    unsigned long srcHeight,        /* The source video height */
+    unsigned long dstWidth,         /* The destination video width */
+    unsigned long dstHeight,        /* The destination video height */
+    unsigned long doubleBuffer,     /* Double Buffer enable flag */
+    unsigned long srcAddress0,      /* The source of the video buffer 0 to display */
+    unsigned long srcAddress1,      /* The source of the video buffer 1 to display
+                                       (only for double buffering).
+                                     */
+    unsigned long srcPitch,         /* The source video plane pitch in bytes */
+    unsigned long srcLineOffset,    /* The source video plane line offset in bytes.
+                                       Set it the same as srcPitch in normal
+                                       usage. */
+    video_format_t videoFormat      /* Source video format */
+)
+{
+    return videoSetupEx(dispCtrl, x, y, srcWidth, srcHeight, dstWidth, dstHeight, doubleBuffer, 
+                        srcAddress0, 0, 0, 0,srcPitch, srcLineOffset, videoFormat,
+                        0, 0);
+    
+}
+
+/*
+ *  startVideo
+ *      This function starts the video.
+ */
+void startVideo( 
+unsigned dispCtrl
+)
+{
+    /* Enable the video plane */
+    videoSetCtrl(dispCtrl, VIDEO_ON);
+}
+
+/*
+ *  stopVideo
+ *      This function stops the video.
+ */
+void stopVideo(unsigned dispCtrl)
+{
+    /* Just disable the video plane */
+    videoSetCtrl(dispCtrl, VIDEO_OFF);
+}
+
+/*
+ * Only valid for Overlay layer. Setup video settings and enable it. 
+*/
+
+int SM768_setOverlay(
+    disp_control_t dispControl, /* Channel 0 or Channel 1) */
+    PBLIT_BLK src,  /* Only need: source Width & Height, Pitch */
+    PYUV_BUF_ADDR SrcAddr,   /* Y U V source base address */
+    PBLIT_BLK dest,  /* Needed input value: destination X & Y & Width & Height */
+    file_format srcFormat
+)
+{
+    unsigned long yPitch = 0, uvPitch = 0; 
+    video_format_t VideoFormat = FORMAT_RGB565;
+
+    /* Set Video Conversion Constant */
+    videoSetConstants(
+			 dispControl,            				  
+			 0,                /* Y Adjustment */
+                      0xED,             /* Red Conversion constant */
+                      0xED,             /* Green Conversion constant */
+                      0xED);            /* Blue Conversion constant */
+                      
+    /* Set video initial scale for Buffer 0 and buffer 1 */                      
+    videoSetInitialScale(dispControl, 0, 0);
+
+    /* Set source buffer */
+    //    videoSetSourceBuffer(NORMAL_BUFFER);
+
+    /* Set the YUV Swap byte */
+    videoSwapYUVByte(dispControl,NORMAL);
+
+    /* Set video interpolation */
+    videoSetInterpolation(dispControl, 0, 0);
+
+    /* Not using Gamma Control */
+    videoSetGammaCtrl(dispControl, 0);
+
+    /* Setup the video */
+    /* Based on the selected fileFormat, calculate the video source addresses (if necessary) and pitches. */
+    switch (srcFormat)
+    {
+        case FFT_RGB565:
+            yPitch = PITCH(src->Width, 16);
+            uvPitch = 0;
+            VideoFormat = FORMAT_RGB565;
+            break;
+        case FFT_RGBx888:
+            yPitch = PITCH(src->Width, 32);
+            uvPitch = 0;
+            VideoFormat = FORMAT_RGB888;
+            break;
+    }
+    videoSetupEx(
+               dispControl,
+    		   dest->x,    /* X Coordinate of the video window */
+               dest->y,   /* Y Coordinate of the video window */ 
+               src->Width,            /* The source video width */ 
+               src->Height,           /* The source video height */ 
+               dest->Width,            /* The destination video width */ 
+               dest->Height,           /* The destination video height */
+               0,                       /* Double buffer enable flag */
+               SrcAddr->bufYAddr,            /* The source of the video buffer 0 to display */
+               SrcAddr->bufCbAddr,            /* U Source Base Address (not used in RGB Space) */
+               SrcAddr->bufCrAddr,            /* V Source Base Address (not used in RGB Space) */
+               uvPitch,             /* UV plane pitch value in bytes (not used in */
+               yPitch, /* The source address buffer pitch in bytes */ 
+               yPitch, /* The source address buffer offset in bytes.  
+                                       Set it the same as srcPitch in normal
+                                       usage. */
+               VideoFormat,            /* Source video format */
+               0,       /* Edge Detection enable flag */
+               0);   /* Edge Detection value. SM718 only use bit 9 to 0 */
+    
+    /* Start Video */
+    startVideo(dispControl);
+    return 0;
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddk768_video.h b/drivers/gpu/drm/smifb2/ddk768/ddk768_video.h
new file mode 100644
index 000000000000..bdfa4c5222ca
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddk768_video.h
@@ -0,0 +1,606 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  Video.H --- SM768 DDK 
+*  This file contains the definitions for the Video functions.
+* 
+*******************************************************************/
+
+
+/****************************************************************************
+   Structure and data type definition 
+ ****************************************************************************/
+
+/* video format: 
+   - 16-bit RGB 5:6:5 mode
+   - 16-bit YUYV mode
+  
+   Note: The 8-bit index and RGB 8:8:8 formats are not supported
+ */
+typedef enum _video_format_t
+{
+    FORMAT_RGB565 = 0,
+    FORMAT_YUV420,
+    FORMAT_YUYV,
+	FORMAT_RGB888
+}
+video_format_t;
+
+/* YUV Data Byte Swap */
+typedef enum _video_byteswap_t
+{
+    NORMAL = 0,
+    SWAP_BYTE
+}
+video_byteswap_t;
+
+/* Turn on/off video */
+typedef enum _video_sync_source_t
+{
+    NORMAL_BUFFER = 0,
+    CAPTURE_BUFFER
+}
+video_sync_source_t;
+
+/* FIFO Request Level */
+typedef enum _video_fifo_t
+{
+    FIFO_LEVEL_1 = 0,
+    FIFO_LEVEL_3,
+    FIFO_LEVEL_7,
+    FIFO_LEVEL_11
+}
+video_fifo_t;
+
+/* Turn on/off video */
+typedef enum _video_ctrl_t
+{
+    VIDEO_OFF = 0,
+    VIDEO_ON
+}
+video_ctrl_t;
+
+
+
+
+
+
+#define PITCH(width, bpp)               (((width) * (bpp) / 8 + 15) & ~15)
+
+typedef enum _file_format
+{
+    FFT_RGB565 = 0 ,
+    FFT_RGBx888
+}file_format;
+
+typedef struct YUV_BUF_ADDR
+{
+    unsigned long bufYAddr;
+    unsigned long bufCbAddr;
+    unsigned long bufCrAddr;
+} YUV_BUF_ADDR, *PYUV_BUF_ADDR;
+typedef struct BLIT_BLK
+{
+    unsigned long Base;
+    unsigned long Pitch;
+    unsigned long Bpp;          /* Only needed for the destination surface */
+    unsigned long x;
+    unsigned long y;
+    unsigned long Width;
+    unsigned long Height;
+} BLIT_BLK, *PBLIT_BLK;
+
+
+
+
+
+
+
+/****************************************************************************
+   Function prototype 
+ ****************************************************************************/
+
+/*
+ *  videoSetWindowAdjustment
+ *      This function sets the video window adjustment. There are usually
+ *      some garbage lines or pixels at the bottom and right of the video
+ *      window. These function will adjust the video window accordingly.
+ *
+ *  Input:
+ *      widthAdjustment     - Width adjustments in pixel
+ *      heightAdjustment    - Height adjustment in line        
+ */
+void videoSetWindowAdjustment(
+	unsigned dispCtrl,
+    short widthAdjustment,
+    short heightAdjustment
+);
+
+/*
+ *  videoGetWindowAdjustment
+ *      This function gets the video window adjustment.
+ *
+ *  Input:
+ *      widthAdjustment     - Width adjustments in pixel
+ *      heightAdjustment    - Height adjustment in line 
+ */
+void videoGetWindowAdjustment(
+    short *pWidthAdjustment,
+    short *pHeightAdjustment
+);
+
+/*
+ * videoGetCurrentBufferDisplay
+ *      This function gets the current buffer used by SM50x to display on the screen
+ *
+ *  Return:
+ *      0   - Buffer 0
+ *      1   - Buffer 1 
+ */
+// unsigned char videoGetCurrentBufferDisplay();
+
+/*
+ * videoEnableDoubleBuffer
+ *      This function enables/disables the double buffer usage
+ *
+ *  Input:
+ *      enable  - Flag to enable/disable the double buffer. 
+ */
+#if 0
+void videoEnableDoubleBuffer(
+    unsigned long enable
+);
+#endif
+
+/*
+ * videoGetBufferStatus
+ *      This function gets the status of the video buffer, either the buffer
+ *      has been used or not.
+ *
+ *  Input:
+ *      bufferIndex     - The index of the buffer which size to be retrieved
+ *
+ *  Output:
+ *      0 - No flip pending
+ *      1 - Flip pending
+ */
+unsigned long videoGetBufferStatus(
+    unsigned long bufferIndex
+);
+
+/*
+ * videoGetBuffer
+ *      This function gets the video buffer
+ *
+ *  Input:
+ *      bufferIndex - The index of the buffer to get
+ *
+ *  Output:
+ *      The video buffer of the requested index.
+ */
+unsigned long videoGetBuffer(
+    unsigned char bufferIndex
+);
+
+/*
+ * videoSetBuffer
+ *      This function sets the video buffer
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer to be set
+ *      bufferStartAddress  - The starting address of the buffer
+ */
+void videoSetBuffer(
+	unsigned dispCtrl,
+    unsigned char bufferIndex,          /* The index of the buffer to be set. */
+    unsigned long bufferStartAddress    /* Video buffer with 128-bit alignment */
+);
+/*
+ * videoSetUVBuffer
+ *      This function sets the video buffer of U and V
+ *
+ *  Input:
+ *      bufferIndex         - The index of the buffer to be set
+ *      bufferStartAddress  - The starting address of the buffer
+ */
+void videoSetUVBuffer(
+	unsigned dispCtrl,
+    unsigned long bufferStartUAddress,    /* Video buffer with 128-bit alignment */
+    unsigned long bufferStartVAddress    /* Video buffer with 128-bit alignment */
+);
+
+/*
+ * videoSetPitchOffset
+ *      This function sets the video plane pitch and offset
+ *
+ *  Input:
+ *      pitch           - Number of bytes per line of the video plane 
+ *                        specified in 128-bit aligned bytes.
+ *      lineOffset      - Number of 128-bit aligned bytes per line 
+ *                        of the video plane.
+ */
+void videoSetPitchOffset(
+	unsigned dispCtrl,
+    unsigned short pitch,
+    unsigned short lineOffset
+);
+
+/*
+ * videoSetUVPitchOffset
+ *      This function sets the video plane pitch and offset of U and V
+ *
+ *  Input:
+ *      pitch           - Number of bytes per line of the video plane 
+ *                        specified in 128-bit aligned bytes.
+ *      lineOffset      - Number of 128-bit aligned bytes per line 
+ *                        of the video plane.
+ */
+void videoSetUVPitchOffset(
+	unsigned dispCtrl,
+    unsigned short pitch,
+    unsigned short lineOffset
+);
+
+/*
+ * videoGetPitch
+ *      This function gets the video plane pitch
+ *
+ * Output:
+ *      pitch   - Number of bytes per line of the video plane 
+ *                specified in 128-bit aligned bytes.
+ */
+unsigned short videoGetPitch(void);
+
+/*
+ * videoGetLineOffset
+ *      This function gets the video plane line offset
+ *
+ * Output:
+ *      lineOffset  - Number of 128-bit aligned bytes per line 
+ *                    of the video plane.
+ */
+unsigned short videoGetLineOffset(void);
+/*
+ *  videoSetLast 
+ *      This function sets the video source last lines and width.
+ *
+ *  Input:
+ *
+ *      width      - Video source width
+ *      height      - Video source height
+ */
+void videoSetLast(
+	unsigned dispCtrl,
+    unsigned long width,
+    unsigned long height
+);
+
+/*
+ *  videoSetWindowSize
+ *      This function sets the video window size.
+ *
+ *  Input:
+ *      width       - Video Window width
+ *      height      - Video Window height
+ */
+void videoSetWindowSize(
+	unsigned dispCtrl,
+    unsigned long width,
+    unsigned long height
+);
+
+/*
+ *  videoGetWindowSize
+ *      This function gets the video window size.
+ *
+ *  Output:
+ *      width       - Video Window width
+ *      height      - Video Window height
+ */
+void videoGetWindowSize(
+	unsigned dispCtrl,
+    unsigned long *pWidth,
+    unsigned long *pHeight
+);
+
+/*
+ *  videoSetPosition
+ *      This function sets the video starting coordinate position.
+ *
+ *  Input:
+ *      startX      - X Coordinate of the video window starting position
+ *      startY      - Y Coordinate of the video window starting position
+ */
+void videoSetPosition(
+	unsigned dispCtrl,
+    unsigned long startX,
+    unsigned long startY
+);
+
+/*
+ *  videoSetConstants
+ *      This function sets the video constants. The actual component will be
+ *      added by this constant to get the expected component value.
+ *
+ *  Input:
+ *      yConstant       - Y Constant Value
+ *      redConstant     - Red Constant Value
+ *      greenConstant   - Green Constant Value
+ *      blueConstant    - Blue Constant Value
+ */
+void videoSetConstants(
+	unsigned dispCtrl,
+    unsigned char  yConstant,               /* Y Adjustment */
+    unsigned char  redConstant,             /* Red Conversion constant */
+    unsigned char  greenConstant,           /* Green Conversion constant */
+    unsigned char  blueConstant             /* Blue Conversion constant */
+);
+
+/*
+ *  videoSetInitialScale
+ *      This function sets the video buffer initial vertical scale.
+ *
+ *  Input:
+ *      bufferIndex         - Index of the buffer which vertical scale value
+ *                            to be set.
+ *      bufferInitScale     - Buffer Initial vertical scale value
+ */
+void videoSetInitialScale(
+	unsigned dispCtrl,
+    unsigned short InitScaleHorizontal,
+    unsigned short InitScaleVertical
+);
+
+/*
+ *  videoSetFIFOLevel
+ *      This function sets the video FIFO Request Level.
+ *
+ *  Input:
+ *      videoSource - Buffer source selection
+ */
+#if 0
+void videoSetFIFOLevel(
+    video_fifo_t videoFIFO
+);
+#endif
+/*
+ *  videoSetSourceBuffer
+ *      This function sets the video to use the capture buffer as the source.
+ *
+ *  Input:
+ *      videoSource - Buffer source selection
+ */
+#if 0
+void videoSetSourceBuffer(
+    video_sync_source_t videoSource
+);
+#endif
+
+/*
+ *  videoSwapYUVByte
+ *      This function swaps the YUV data byte.
+ *
+ *  Input:
+ *      byteSwap    - Flag to enable/disable YUV data byte swap.
+ */
+void videoSwapYUVByte(
+   unsigned dispCtrl,
+   video_byteswap_t byteSwap  
+);
+
+/*
+ *  videoSetInterpolation
+ *      This function enables/disables the horizontal and vertical interpolation.
+ *
+ *  Input:
+ *      enableHorzInterpolation   - Flag to enable/disable Horizontal interpolation
+ *      enableVertInterpolation   - Flag to enable/disable Vertical interpolation
+ */
+void videoSetInterpolation(
+	unsigned dispCtrl,
+    unsigned long enableHorzInterpolation,
+    unsigned long enableVertInterpolation
+);
+
+/*
+ *  videoGetInterpolation
+ *      This function gets the horizontal and vertical interpolation enable status.
+ *
+ *  Input:
+ *      pHorzInterpolationStatus	- Pointer to store the horizontal interpolation status
+ *      pVertInterpolationStatus	- Pointer to store the vertical interpolation status
+ */
+void videoGetInterpolation(
+    unsigned long *pHorzInterpolationStatus,
+    unsigned long *pVertInterpolationStatus
+);
+
+/*
+ *  videoSetStartPanningPixel
+ *      This function sets the starting pixel number for smooth pixel panning.
+ *
+ *  Input:
+ *      startPixel  - Starting pixel number for smooth pixel panning
+ */
+void videoSetStartPanningPixel(
+    unsigned char startPixel
+);
+
+/*
+ *  videoSetGamma
+ *      This function enables/disables gamma control.
+ *
+ *  Input:
+ *      enableGammaCtrl - The gamma enable control
+ *
+ *  NOTE:
+ *      The gamma can only be enabled in RGB565 and RGB888. Enable this gamma
+ *      without proper format will have no effect.
+ */
+void videoSetGammaCtrl(
+	unsigned dispCtrl,
+    unsigned long enableGammaCtrl
+);
+
+/*
+ *  isVideoEnable
+ *      This function check whether the video plane is already enabled or not.
+ *
+ *  Output:
+ *      0   - Disable
+ *      1   - Enable
+ */
+unsigned char isVideoEnable(void);
+
+/*
+ *  videoSetEdgeDetection
+ *      This function enable/disable the edge detection and fill out the edge detection
+ *      value as well. This function only works in SM718. SM750 does not support this
+ *      feature.
+ *
+ *  Input:
+ *      enableEdgeDetect    - Enable/Disable Edge Detection
+ *      edgeDetectValue     - The Edge Detection value. This is the difference (delta)
+ *                            of the pixel colors to be considered as an edge.
+ *
+ *  Note:
+ *      This edge correction only works in up-scale video.
+ */
+void videoSetEdgeDetection(
+    unsigned long enableEdgeDetect,
+    unsigned long edgeDetectValue
+);
+
+/*
+ *  videoGetEdgeDetection
+ *      This function gets the information whether the edge detection is enabled or not.
+ *      It also outputs the edge detection value if required.
+ *      This function only works in SM718. SM750 does not support this feature.
+ *
+ *  Input:
+ *      pEdgeDetectValue    - Pointer to a buffer to store the edge detection value.
+ *
+ *  Note:
+ *      0   - Edge Detection is disabled
+ *      1   - Edge Detection is enabled
+ */
+unsigned long videoGetEdgeDetection(
+    unsigned long *pEdgeDetectValue
+);
+
+/*
+ *  videoSetupEx
+ *      This function setups the video. It only applies in SM718
+ *
+ *  Input:
+ *      x               - X Coordinate of the video window
+ *      y               - Y Coordinate of the video window
+ *      srcWidth        - The source video width
+ *      srcHeight       - The source video height
+ *      dstWidth        - The destination video width
+ *      dstHeight       - The destination video height
+ *      doubleBuffer    - Double Buffer enable flag
+ *      srcAddress0     - The source of the video buffer 0 to display
+ *      srcAddress1     - The source of the video buffer 1 to display
+ *                        (only for double buffering).
+ *      srcPitch        - The source video plane pitch in bytes
+ *      srcLineOffset   - The source video plane line offset in bytes.
+ *                        In normal usage, set it the same as the srcBufferPitch
+ *      videoFormat     - Source video format
+ *      edgeDetect      - Edge Detection enable flag
+ *      edgeDetectValue - Edge Detection value
+ *
+ *  Output:
+ *      0   - Success
+ *     -1  - Fail
+ */
+unsigned char videoSetupEx(
+	unsigned dispCtrl,
+    unsigned long x,                /* X Coordinate of the video window */
+    unsigned long y,                /* Y Coordinate of the video window */
+    unsigned long srcWidth,         /* The source video width */
+    unsigned long srcHeight,        /* The source video height */
+    unsigned long dstWidth,         /* The destination video width */
+    unsigned long dstHeight,        /* The destination video height */
+    unsigned long doubleBuffer,     /* Double Buffer enable flag */
+    unsigned long srcAddress0,      /* The source of the video buffer 0 to display */
+    unsigned long sUAddress,            /* U Source Base Address (not used in RGB Space) */
+    unsigned long sVAddress,            /* V Source Base Address (not used in RGB Space) */
+    unsigned long sUVPitch,             /* UV plane pitch value in bytes (not used in */ 
+    unsigned long srcPitch,         /* The source video plane pitch in bytes */
+    unsigned long srcLineOffset,    /* The source video plane line offset in bytes.
+                                       Set it the same as srcPitch in normal
+                                       usage. */
+    video_format_t videoFormat,      /* Source video format */
+    unsigned long edgeDetect,       /* Edge Detection enable flag */
+    unsigned long edgeDetectValue   /* Edge Detection value. SM718 only use bit 9 to 0 */
+);
+
+/*
+ *  videoSetup
+ *      This function setups the video.
+ *
+ *  Input:
+ *      x               - X Coordinate of the video window
+ *      y               - Y Coordinate of the video window
+ *      srcWidth        - The source video width
+ *      srcHeight       - The source video height
+ *      dstWidth        - The destination video width
+ *      dstHeight       - The destination video height
+ *      doubleBuffer    - Double Buffer enable flag
+ *      srcAddress0     - The source of the video buffer 0 to display
+ *      srcAddress1     - The source of the video buffer 1 to display
+ *                        (only for double buffering).
+ *      srcPitch        - The source video plane pitch in bytes
+ *      srcLineOffset   - The source video plane line offset in bytes.
+ *                        In normal usage, set it the same as the srcBufferPitch
+ *      videoFormat     - Source video format
+ *
+ *  Output:
+ *      0   - Success
+ *     -1  - Fail
+ */
+unsigned char videoSetup(
+    disp_control_t dispCtrl,
+    unsigned long x,                /* X Coordinate of the video window */
+    unsigned long y,                /* Y Coordinate of the video window */
+    unsigned long srcWidth,         /* The source video width */
+    unsigned long srcHeight,        /* The source video height */
+    unsigned long dstWidth,         /* The destination video width */
+    unsigned long dstHeight,        /* The destination video height */
+    unsigned long doubleBuffer,     /* Double Buffer enable flag */
+    unsigned long srcAddress0,      /* The source of the video buffer 0 to display */
+    unsigned long srcAddress1,      /* The source of the video buffer 1 to display
+                                       (only for double buffering).
+                                     */
+    unsigned long srcPitch,         /* The source video plane pitch in bytes */
+    unsigned long srcLineOffset,    /* The source video plane line offset in bytes.
+                                       Set it the same as srcPitch in normal
+                                       usage. */
+    video_format_t videoFormat      /* Source video format */
+);
+
+/*
+ *  startVideo
+ *      This function starts the video.
+ */
+void startVideo(unsigned dispCtrl);
+
+/*
+ *  stopVideo
+ *      This function stops the video.
+ */
+void stopVideo(unsigned dispCtrl);
+
+int SM768_setOverlay(
+    disp_control_t dispControl, /* Channel 0 or Channel 1) */
+    PBLIT_BLK src,  /* Only need: source Width & Height, Pitch */
+    PYUV_BUF_ADDR SrcAddr,   /* Y U V source base address */
+    PBLIT_BLK dest,  /* Needed input value: destination X & Y & Width & Height */
+    file_format srcFormat
+);
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddkdebug.c b/drivers/gpu/drm/smifb2/ddk768/ddkdebug.c
new file mode 100644
index 000000000000..95b807eed509
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddkdebug.c
@@ -0,0 +1,227 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  ddkdebug.c --- DDK Debug Tool 
+*  This file contains the source code for the SMI DDK Debugging.
+* 
+*******************************************************************/
+#ifdef DDKDEBUG /* Don't enable debug flag in ARM yet */
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "ddkdebug.h"
+#include "os.h"
+
+/* COM Port index that is used for the debugging */
+#define DEBUG_COM_PORT_INDEX                0
+
+/* Buffer length */
+#define BUFFER_LENGTH                       1024
+
+static ddk_debug_output_t gDebugOutput = DEBUG_OUTPUT_SCREEN;
+static unsigned long gDebugLevelMask = 0;
+static FILE *gFileHandle = (FILE *)0;
+static short gCOMInit = 0;
+static unsigned char gEnableDebugMessage;
+
+/*
+ * This function initializes the debug print out system.
+ *  
+ *  Input:
+ *      debugOutput - Output where to print out the debug. It could be 
+ *                    screen, file, or serial port.
+ *      debugLevel  - Debugging level      
+ */
+void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask)
+{
+    gDebugOutput = debugOutput;
+    gDebugLevelMask = debugLevelMask;
+    gEnableDebugMessage = 1;
+    
+    /* Initialize the output media as necessary */
+    switch (gDebugOutput)
+    {
+        default:
+        case DEBUG_OUTPUT_SCREEN:
+            /* Do nothing */
+            break;
+        case DEBUG_OUTPUT_FILE:
+            /* Close the previous log file if opened */
+            if (gFileHandle != (FILE *)0)
+                fclose(gFileHandle);
+            
+            /* Create a LOG file */    
+            gFileHandle = fopen("ddkdebug.log", "w");
+            if (gFileHandle == NULL)
+                ddkDebugPrint(0, "Can not open log file\n");
+            break;
+        case DEBUG_OUTPUT_SERIAL:
+            /* Open COM Port */
+            if (comInit(DEBUG_COM_PORT_INDEX,
+                        COM_9600, 
+                        DATA_SIZE_8, 
+                        PARITY_NONE, 
+                        STOP_BIT_1,
+                        FLOW_CONTROL_NONE) == 0)
+                gCOMInit = 1;
+            else
+                ddkDebugPrint(0, "Can not open COM Port\n");            
+            break;
+    }
+}
+
+/*
+ *  This function enable or disable the debug message.
+ *  
+ *  Input:
+ *      enableDebugMessage  - Enable/disable the debug message
+ *                            0 - Disable Debug Message
+ *                            1 - Enable Debug Message
+ *
+ *  Note:
+ *      This function can be used to enable/disable the debug message
+ *      at certain point of software, so that the debug messages, that
+ *      are printed, are only the important ones.     
+ */
+void ddkDebugEnable(unsigned char enableDebugMessage)
+{
+    gEnableDebugMessage = enableDebugMessage;
+}
+
+/*
+ * This function prints out the formatted string.
+ *  
+ *  Input:
+ *      debugLevel  - The level of the debug of which the message is intended for.
+ *      pszFormat   - Format of the printed message      
+ */
+void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...)
+{
+	static char pszPrintBuffer[BUFFER_LENGTH];
+	unsigned long nWritten;
+
+    /* Do not print any messages when this variable is flagged. */
+    if (gEnableDebugMessage == 0)
+        return;
+        
+    /* Only process any ddkDebugPrint with the debugLevel less or equal the preset
+       debug Level during the init */
+    if (((debugLevel & gDebugLevelMask) != 0) || (debugLevel == 0))
+    {
+	    /* Format the string */
+	    va_list arg_ptr;
+	    va_start(arg_ptr, pszFormat);
+	    nWritten = (unsigned long) vsnprintf(pszPrintBuffer, BUFFER_LENGTH - 1, pszFormat, arg_ptr);
+	    va_end(arg_ptr);
+        
+        /* Check for buffer overflow */
+	    if (nWritten == (unsigned long)(-1))
+	    {
+		    ddkDebugPrint(0, "ddkDebugPrint(): BUFFER OVERFLOW DETECTED!!!\r\n" \
+			    "MAX STRING LENGTH = %d\n", BUFFER_LENGTH);
+		    return;
+	    }
+
+        /* Print out the data */
+        switch (gDebugOutput)
+        {
+            default:
+            case DEBUG_OUTPUT_SCREEN:
+                printk(KERN_DEBUG "%s", pszPrintBuffer);
+                
+                /* 
+                 * Flush the stdout before the getch function. Otherwise the
+                 * previous printf will not be displayed correctly sometimes.
+                 */
+                fflush(stdout);
+                break;
+            case DEBUG_OUTPUT_FILE:
+                /* Print out the message to the log file */
+                if (gFileHandle != NULL)
+                {
+                    fprintf(gFileHandle, pszPrintBuffer);
+                    fflush(gFileHandle);
+                }
+                break;
+            case DEBUG_OUTPUT_SERIAL:
+                /* Send the data out to the COM Port */
+                if (gCOMInit)
+                {
+#if 1                
+                    char *pString1, *pString2;
+                    unsigned long length;
+                    char linefeed = '\r';
+
+                    length = 0;
+                    pString1 = pszPrintBuffer; 
+                    while(nWritten)
+                    {
+                        /* Search for all '\n' and add '\r' so that the serial port can display correctly. */
+                        pString2 = strchr(pString1, '\n');
+                        if (pString2 != (char *)0)
+                        {
+                            length = pString2 - pString1 + 1;
+                            
+                            /* Check the previous character and the next character */
+                            if ((*(pString2 - 1) != '\r') && (*(pString2 + 1) != '\r'))
+                            {
+                                /* Write the buffer with the '\r' */
+                                comWrite(pString1, length);
+                                comWrite(&linefeed, 1); 
+                            }
+                            else
+                                comWrite(pString1, length);
+                                
+                            /* Adjust the nWritten */
+                            nWritten -= length;
+                            
+                            /* Adjust the new string pointer */
+                            pString1 = pString2 + 1;
+                        }
+                        else
+                        {
+                            comWrite(pString1, nWritten);
+                            nWritten = 0;
+                        }
+                    }
+#else
+                    comWrite(pszPrintBuffer, nWritten);
+#endif
+                }
+                break;                
+        }
+    }
+}
+
+/*
+ * This function cleans up (such as closing the debug file, etc...) when
+ * exiting the debug module.      
+ */
+void ddkDebugPrintExit()
+{
+    /* Clean up the debug print module */
+    switch (gDebugOutput)
+    {
+        default:
+        case DEBUG_OUTPUT_SCREEN:
+            /* Do nothing */
+            break;
+        case DEBUG_OUTPUT_FILE:
+            /* Close the log file */
+            if (gFileHandle != (FILE *)0)
+                fclose(gFileHandle);
+            break;
+        case DEBUG_OUTPUT_SERIAL:
+            comClose();
+            break;
+    } 
+}
+
+#endif
+
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ddkdebug.h b/drivers/gpu/drm/smifb2/ddk768/ddkdebug.h
new file mode 100644
index 000000000000..aa1df840174f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ddkdebug.h
@@ -0,0 +1,141 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  ddkdebug.h --- DDK Debug module 
+*  This file contains the definitions for the SMI DDK debugging.
+* 
+*******************************************************************/
+#ifndef _DDKDEBUG_H_
+#define _DDKDEBUG_H_
+
+#ifdef DDKDEBUG
+
+/*********************
+ * Definition  
+ *********************/
+ 
+/* Debug Print Level definitions */
+/* Bit 16 ~ 31 are used by the library. Bit 0 ~ 15 can be used by application */
+#define ERROR_LEVEL                 0x00010000
+#define WARNING_LEVEL               0x00020000
+#define INIT_LEVEL                  0x00040000
+#define DISPLAY_LEVEL               0x00080000
+#define DMA_LEVEL                   0x00100000
+#define DE_LEVEL                    0x00200000
+#define CAPTURE_LEVEL               0x00400000
+#define SSP_LEVEL                   0x00800000
+#define RESERVED8_LEVEL             0x01000000
+#define RESERVED9_LEVEL             0x02000000
+#define RESERVED10_LEVEL            0x04000000
+#define RESERVED11_LEVEL            0x08000000
+#define RESERVED12_LEVEL            0x10000000
+#define RESERVED13_LEVEL            0x20000000
+#define RESERVED14_LEVEL            0x40000000
+#define RESERVED15_LEVEL            0x80000000
+
+#define SYSTEM_LEVEL_MASK           0xFFFF0000
+#define APPLICATION_LEVEL_MASK      0x0000FFFF
+
+/*********************
+ * Structure 
+ *********************/
+typedef enum _ddk_debug_output_t
+{
+    DEBUG_OUTPUT_SCREEN = 0,
+    DEBUG_OUTPUT_FILE,
+    DEBUG_OUTPUT_SERIAL
+} 
+ddk_debug_output_t;
+
+/*********************
+ * MACROS 
+ *********************/
+ 
+/* This function has to be called before calling other DEBUGPIRNT functions. */
+#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) \
+    ddkDebugPrintInit(debugOutput, debugLevelMask)
+
+/* This function enable or disable the debug message. 
+ *  Note:
+ *      This function can be used to enable/disable the debug message
+ *      at certain point of software, so that the debug messages, that
+ *      are printed, are only the important ones.
+ */
+#define DDKDEBUGENABLE(arg)                           \
+    ddkDebugEnable(arg)
+
+/* Calling the DDKDEBUGPRINT needs to have the arg to be enclosed with
+   two of open and close brackets.
+   Example:
+            DDKDEBUGPRINT(("Hello World: %s\n", pszString));
+ */
+#define DDKDEBUGPRINT(arg)                             \
+    ddkDebugPrint arg
+    
+/* This function has to be called when exiting the application.
+   It is necessary to clean up the debug module. */
+#define DDKDEBUGPRINTEXIT()                            \
+    ddkDebugPrintExit()
+
+/*********************
+ * Function prototype 
+ *********************/
+ 
+/*
+ * This function initializes the debug print out system.
+ *  
+ *  Input:
+ *      debugOutput - Output where to print out the debug. It could be 
+ *                    screen, file, or serial port.
+ *      debugLevel  - Debugging level      
+ */
+void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask);
+
+/*
+ *  This function enable or disable the debug message.
+ *  
+ *  Input:
+ *      enableDebugMessage  - Enable/disable the debug message
+ *                            0 - Disable Debug Message
+ *                            1 - Enable Debug Message
+ *
+ *  Note:
+ *      This function can be used to enable/disable the debug message
+ *      at certain point of software, so that the debug messages, that
+ *      are printed, are only the important ones.     
+ */
+void ddkDebugEnable(unsigned char enableDebugMessage);
+
+/*
+ * This function prints out the formatted string.
+ *  
+ *  Input:
+ *      debugLevel  - The level of the debug of which the message is intended for.
+ *      pszFormat   - Format of the printed message      
+ */
+void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...);
+
+/*
+ * This function cleans up (such as closing the debug file, etc...) when
+ * exiting the debug module.      
+ */
+void ddkDebugPrintExit();
+
+#else
+
+/* 
+ * If there is no DEBUG definition, then treat the macro as an empty macro.
+ * Therefore all the debug print will be stripped out. 
+ */
+#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask)
+#define DDKDEBUGENABLE(arg)
+#define DDKDEBUGPRINT(arg)
+#define DDKDEBUGPRINTEXIT()
+
+#endif
+
+#endif /* _DDKDEBUG_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/ep952_if.h b/drivers/gpu/drm/smifb2/ddk768/ep952_if.h
new file mode 100644
index 000000000000..a0297f106e44
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ep952_if.h
@@ -0,0 +1,147 @@
+#ifndef EP952_IF_H
+#define EP952_IF_H
+
+#include "ep952api.h"
+#include "ep952regdef.h"
+
+//==================================================================================================
+//
+// Protected Data Member
+//
+
+typedef enum {
+	COLORSPACE_601 = 1,
+	COLORSPACE_709
+} COLORSPACE;
+
+typedef enum {
+	SYNCMODE_HVDE = 0,
+	SYNCMODE_HV,
+	SYNCMODE_Embeded
+} SYNCMODE;
+
+typedef enum {
+	COLORFORMAT_RGB = 0,
+	COLORFORMAT_YCC444,
+	COLORFORMAT_YCC422
+} COLORFORMAT;
+
+typedef enum {
+	AFAR_VideoCode = 0,
+	AFAR_4_3,
+	AFAR_16_9,
+	AFAR_14_9
+} AFAR;
+
+typedef enum {
+	SCAN_NoData = 0,
+	SCAN_OverScan,
+	SCAN_UnderScan,
+	SCAN_Future
+} SCAN_MODE;
+
+
+// Video Output Congif Params
+typedef struct _VDO_PARAMS {
+// Which cause Timing Change Reset
+	unsigned char 	Interface;				// DK[3:1], DKEN, DSEL, BSEL, EDGE, FMT12
+	unsigned char 	VideoSettingIndex;	// VIC
+	unsigned char 	HVPol;					// x, x, x, x, VSO_POL, HSO_POL, x, x
+	SYNCMODE 		SyncMode;				// 0 = HVDE, 1 = HV(DE Gen), 2 = Embedded Sync
+	COLORFORMAT 	FormatIn;				// 0 = RGB, 1 = YCC444, 2 = YCC422
+	COLORFORMAT 	FormatOut;				// 0 = RGB, 1 = YCC444, 2 = YCC422
+// Which don't cause Timing Chage Reset
+	COLORSPACE 		ColorSpace;			// 0 = Auto, 1 = 601, 2 = 709
+	AFAR 			AFARate;				// 0 = Auto, 1 = 4:3, 2 = 16:9, 3 = 14:9
+	SCAN_MODE   	SCAN;					// 0 = no data, 1 = overscan, 2 = underscan, 3 = future
+} VDO_PARAMS, *PVDO_PARAMS;
+
+typedef enum {
+	ADSFREQ_32000Hz = 0x03,
+	ADSFREQ_44100Hz = 0x00,
+	ADSFREQ_48000Hz = 0x02,
+	ADSFREQ_88200Hz = 0x08,
+	ADSFREQ_96000Hz = 0x0A,
+	ADSFREQ_176400Hz = 0x0C,
+	ADSFREQ_192000Hz = 0x0E
+} ADSFREQ;
+
+// Audio Output Congif Params
+typedef struct _ADO_PARAMS {
+	unsigned char 		Interface;				// x, x, x, x, IIS, WS_M, WS_POL, SCK_POL
+	unsigned char 		VideoSettingIndex;	// VIC
+	unsigned char 		ChannelNumber;			// 1 = 2 ch, 2 = 3 ch, ... , 5 = 5.1 ch, 7 = 7.1 ch
+	unsigned char 		ADSRate;				// 1 = SF/2, 2 = SF/3, 3 = SF/4 (Down Sample)
+	ADSFREQ		InputFrequency;				// ADSFREQ
+	unsigned char       	VFS; 				// 0 = 59.94Hz, 1 = 60Hz (Vertical Frequency Shift of Video)
+	unsigned char 		NoCopyRight;
+} ADO_PARAMS, *PADO_PARAMS;
+
+//==================================================================================================
+//
+// Public Functions
+//
+
+//--------------------------------------------------------------------------------------------------
+//
+// General
+//
+
+// All Interface Inital
+extern void EP952_IIC_Initial(void);
+extern void EP952_Info_Reset(void);
+
+
+//--------------------------------------------------------------------------------------------------
+//
+// HDMI Transmiter Interface
+//
+
+// Common
+extern void HDMI_Tx_Power_Down(void);
+extern void HDMI_Tx_Power_Up(void);
+extern void HDMI_Tx_HDMI(void);
+extern void HDMI_Tx_DVI(void);
+extern unsigned char HDMI_Tx_HTPLG(void);
+extern unsigned char HDMI_Tx_RSEN(void);
+
+// HDCP
+extern void HDMI_Tx_Mute_Enable(void);
+extern void HDMI_Tx_Mute_Disable(void);
+extern void HDMI_Tx_HDCP_Enable(void);
+extern void HDMI_Tx_HDCP_Disable(void);
+extern void HDMI_Tx_RPTR_Set(void);
+extern void HDMI_Tx_RPTR_Clear(void);
+extern unsigned char HDMI_Tx_RI_RDY(void);
+extern void HDMI_Tx_write_AN(unsigned char *pAN);
+extern unsigned char HDMI_Tx_AKSV_RDY(void);
+extern unsigned char HDMI_Tx_read_AKSV(unsigned char *pAKSV);
+extern void HDMI_Tx_write_BKSV(unsigned char *pBKSV);
+extern unsigned char HDMI_Tx_read_RI(unsigned char *pRI);
+extern void HDMI_Tx_read_M0(unsigned char *pM0);
+extern SMBUS_STATUS HDMI_Tx_Get_Key(unsigned char *Key);
+
+// Special for EP952E
+extern void HDMI_Tx_AMute_Enable(void);
+extern void HDMI_Tx_AMute_Disable(void);
+extern void HDMI_Tx_VMute_Enable(void);
+extern void HDMI_Tx_VMute_Disable(void);
+extern void HDMI_Tx_Video_Config(PVDO_PARAMS Params);
+extern void HDMI_Tx_Audio_Config(PADO_PARAMS Params);
+
+
+//--------------------------------------------------------------------------------------------------
+//
+// Hardware Interface
+//
+
+// EP952
+extern unsigned char EP952_Reg_Read(unsigned char ByteAddr, unsigned char *Data, unsigned int Size);
+extern unsigned char EP952_Reg_Write(unsigned char ByteAddr, unsigned char *Data, unsigned int Size);
+extern unsigned char EP952_Reg_Set_Bit(unsigned char ByteAddr, unsigned char BitMask);
+extern unsigned char EP952_Reg_Clear_Bit(unsigned char ByteAddr, unsigned char BitMask);
+
+
+#endif // EP952_IF_H
+
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ep952api.h b/drivers/gpu/drm/smifb2/ddk768/ep952api.h
new file mode 100644
index 000000000000..6730baa33d99
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ep952api.h
@@ -0,0 +1,113 @@
+#ifndef EP952_API_H
+#define EP952_API_H
+
+//#include <stdio.h>
+
+
+// HDCP	enable define ////////////////
+
+#define Enable_HDCP 	0
+
+//////////////////////////////////////
+
+
+// Debug define	//////////////////////
+
+#define DBG_printf(x) printf x		// enable DBG message
+//#define DBG_printf(x)				// disable DBG message
+
+//////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+
+typedef enum {
+	// Master
+	SMBUS_STATUS_Success = 0x00,
+	SMBUS_STATUS_Pending,//	SMBUS_STATUS_Abort,
+	SMBUS_STATUS_NoAct = 0x02,
+	SMBUS_STATUS_TimeOut,
+	SMBUS_STATUS_ArbitrationLoss = 0x04,
+} SMBUS_STATUS;
+
+
+/*typedef enum {
+	AUD_I2S = 0,
+	AUD_SPDIF	
+}HDMI_AudFmt_t;*/
+
+typedef enum {
+	AUD_None = 0,
+	AUD_SF_32000Hz = 1,
+	AUD_SF_44100Hz,
+	AUD_SF_48000Hz,	
+	//AUD_SF_88200Hz,
+	//AUD_SF_96000Hz,
+	//AUD_SF_176400Hz,
+	//AUD_SF_192000Hz
+
+}HDMI_AudFreq;
+
+//--------------------------------------------------------------------------------------------------
+// 															BitMask		Value
+#define EP_TX_System_Status__KEY_FAIL									0x02
+#define EP_TX_System_Configuration__HDCP_DIS							0x20
+
+#define EP_TX_Video_Interface_Setting_0__DKEN_Disable					0x80	// Disable De-skew
+#define EP_TX_Video_Interface_Setting_0__DKEN_M_4_Step					0x10	// -4 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_M_3_Step					0x30	// -3 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_M_2_Step					0x50	// -2 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_M_1_Step					0x70	// -1 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_M_0_Step					0x90	//  0 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_P_1_Step					0xB0	// +1 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_P_2_Step					0xD0	// +2 step
+#define EP_TX_Video_Interface_Setting_0__DKEN_P_3_Step					0xF0	// +3 step
+
+#define EP_TX_Video_Interface_Setting_0__DSEL							0x08
+#define EP_TX_Video_Interface_Setting_0__BSEL							0x04
+#define EP_TX_Video_Interface_Setting_0__EDGE							0x02
+#define EP_TX_Video_Interface_Setting_0__FMT12							0x01
+
+#define EP_TX_Video_Interface_Setting_1__SYNC				0x0C
+#define EP_TX_Video_Interface_Setting_1__SYNC__HVDE						0x00
+#define EP_TX_Video_Interface_Setting_1__SYNC__HV						0x04
+#define EP_TX_Video_Interface_Setting_1__SYNC__Embeded					0x08
+
+#define EP_TX_Video_Interface_Setting_1__VIN_FMT			0x03
+#define EP_TX_Video_Interface_Setting_1__VIN_FMT__RGB					0x00
+#define EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC444				0x01
+#define EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC422				0x02
+
+#define EP_TX_Audio_Input_Format__ADO_FREQ					0x07
+#define EP_TX_Audio_Input_Format__ADO_FREQ__None					0x00
+#define EP_TX_Audio_Input_Format__ADO_FREQ__32000Hz					0x01
+#define EP_TX_Audio_Input_Format__ADO_FREQ__44100Hz					0x02
+#define EP_TX_Audio_Input_Format__ADO_FREQ__48000Hz					0x03
+#define EP_TX_Audio_Input_Format__ADO_FREQ__88200Hz					0x04
+#define EP_TX_Audio_Input_Format__ADO_FREQ__96000Hz					0x05
+#define EP_TX_Audio_Input_Format__ADO_FREQ__176400Hz				0x06
+#define EP_TX_Audio_Input_Format__ADO_FREQ__192000Hz				0x07
+
+// -----------------------------------------------------------------------------
+
+#ifndef min
+#define min(a,b) (((a)<(b))? (a):(b))
+#endif
+
+#ifndef max
+#define max(a,b) (((a)>(b))? (a):(b))
+#endif
+
+//--------------------------------------------------------------------------------------------------
+void EP_EP952_Reset(void);
+//void EP_HDMI_Set_Audio_Fmt(HDMI_AudFmt_t Audfmt, HDMI_AudFreq Audfreq);
+void  EP_HDMI_Set_Video_Timing(unsigned int isHDMI,unsigned int dsel); //(logicalMode_t *pLogicalMode, unsigned int isHDMI);
+void EP_HDMI_Init(int chipID); 
+void EP_Register_Init(void);
+int EP952_HDMI_Set_Mode (logicalMode_t *pLogicalMode);
+void EP952_Register_Message(void);
+
+
+
+
+//--------------------------------------------------------------------------------------------------
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/ep952controller.h b/drivers/gpu/drm/smifb2/ddk768/ep952controller.h
new file mode 100644
index 000000000000..6d6707e71866
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ep952controller.h
@@ -0,0 +1,82 @@
+#ifndef EP952CONTROLLER_H
+#define EP952CONTROLLER_H
+
+#include "ep952_if.h"
+#include "ep952api.h"
+
+
+
+#define VERSION_MAJOR             52   
+#define VERSION_MINOR              1     
+
+#define INT_enable		1
+#define INT_disable		0
+#define INT_OPEN_DRAIN	1
+#define INT_PUSH_PULL	0
+#define INT_High		1
+#define INT_Low			0
+
+typedef enum {
+	TXS_Search_EDID,
+	TXS_Wait_Upstream,
+	TXS_Stream,
+	TXS_HDCP
+} TX_STATE;
+
+typedef struct _EP952C_REGISTER_MAP {
+
+	unsigned char		System_Status;		
+
+#if Enable_HDCP
+	unsigned char		HDCP_Status;			
+	unsigned char		HDCP_State;
+	unsigned char		HDCP_AKSV[5];
+	unsigned char		HDCP_BKSV[5];
+	unsigned char		HDCP_BCAPS3[3];
+	unsigned char		HDCP_KSV_FIFO[5*16];
+	unsigned char		HDCP_SHA[20];
+	unsigned char		HDCP_M0[8];
+#endif
+
+	unsigned char		Readed_EDID[256];		
+	unsigned char		EDID_ASFreq;
+	unsigned char		EDID_AChannel;
+	//unsigned char		EDID_VideoDataAddr;
+	//unsigned char		EDID_AudioDataAddr;
+	//unsigned char		EDID_SpeakerDataAddr;
+	//unsigned char		EDID_VendorDataAddr;
+
+	unsigned char		System_Configuration;
+
+	unsigned char		Video_Interface[2];		//		
+	unsigned char		Video_Input_Format[2];	//	
+	unsigned char 		Video_Output_Format;	//
+
+	unsigned char		Audio_Interface;		//		
+	unsigned char		Audio_Input_Format;		//
+
+	unsigned char 		Video_change;		
+	unsigned char 		Audio_change;		
+
+} EP952C_REGISTER_MAP, *PEP952C_REGISTER_MAP;
+
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
+
+typedef void (*EP952C_CALLBACK)(void);
+
+void EP952Controller_Initial(PEP952C_REGISTER_MAP pEP952C_RegMap);
+
+void EP952Controller_Task(void);
+
+void EP952Controller_Timer(void);
+
+void EP952_Audio_reg_set(void);
+void EP952_Video_reg_set(void);
+
+void EP952_EXTINT_init(unsigned char INT_Enable, unsigned char INT_OD, unsigned char INT_POL);
+void EP_HDMI_DumpMessage(void);
+
+// -----------------------------------------------------------------------------
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/ep952regdef.h b/drivers/gpu/drm/smifb2/ddk768/ep952regdef.h
new file mode 100644
index 000000000000..742c804fb138
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ep952regdef.h
@@ -0,0 +1,159 @@
+#ifndef EP952REGDEF_H
+#define EP952REGDEF_H
+
+// Registers								Word	BitMask
+
+#define EP952_TX_PHY_Control_0				0x00
+#define EP952_TX_PHY_Control_0__TERM_ON				0x80
+#define EP952_TX_PHY_Control_0__DSWING				0x30
+
+#define EP952_TX_PHY_Control_1				0x01
+#define EP952_TX_PHY_Control_1__SCLK_DLY			0x80
+#define EP952_TX_PHY_Control_1__TPHY_RST			0x40
+#define EP952_TX_PHY_Control_1__RESN_DIS			0x20
+#define EP952_TX_PHY_Control_1__VCO_GAIN			0x0C
+#define EP952_TX_PHY_Control_1__PHD_CUR				0x03
+
+#define EP952_TX_EE_SUM						0x02
+
+#define EP952_General_Control_8				0x05
+#define EP952_General_Control_8__ADO_SPDIF_IN		0x00
+#define EP952_General_Control_8__ADO_IIS_IN			0x10
+#define EP952_General_Control_8__COMR_DIS			0x04
+
+#define EP952_SMPRD							0x06			// 2 Byte
+
+#define EP952_General_Control_1				0x08
+#define EP952_General_Control_1__TSEL_HTP			0x80
+#define EP952_General_Control_1__INT_OD				0x40
+#define EP952_General_Control_1__INT_POL			0x20
+#define EP952_General_Control_1__OSC_PD				0x10
+#define EP952_General_Control_1__DSEL				0x08
+#define EP952_General_Control_1__BSEL				0x04
+#define EP952_General_Control_1__EDGE				0x02
+#define EP952_General_Control_1__PU					0x01
+
+#define EP952_General_Control_2				0x09
+#define EP952_General_Control_2__RSEN				0x80
+#define EP952_General_Control_2__HTPLG				0x40
+#define EP952_General_Control_2__PIFE				0x08
+#define EP952_General_Control_2__RIFE				0x04
+#define EP952_General_Control_2__VIFE				0x02
+#define EP952_General_Control_2__MIFE				0x01
+
+#define EP952_General_Control_3				0x0A	
+
+#define EP952_Configuration					0x0B
+
+#define EP952_Color_Space_Control			0x0C
+#define EP952_Color_Space_Control__422_OUT			0x80
+#define EP952_Color_Space_Control__YCC_OUT			0x40
+#define EP952_Color_Space_Control__COLOR			0x20
+#define EP952_Color_Space_Control__YCC_Range		0x10
+#define EP952_Color_Space_Control__VMUTE			0x08
+#define EP952_Color_Space_Control__AMUTE			0x04
+#define EP952_Color_Space_Control__AVMUTE			0x02
+		
+#define EP952_Pixel_Repetition_Control		0x0D	
+#define EP952_Pixel_Repetition_Control__CS_M		0x80
+#define EP952_Pixel_Repetition_Control__CTS_M		0x40
+#define EP952_Pixel_Repetition_Control__ADSR		0x30
+#define EP952_Pixel_Repetition_Control__VSYNC		0x04	
+#define EP952_Pixel_Repetition_Control__PR			0x03
+
+#define EP952_General_Control_4				0x0E
+#define EP952_General_Control_4__FMT12				0x80
+#define EP952_General_Control_4__422_IN				0x40
+#define EP952_General_Control_4__YCC_IN				0x20
+#define EP952_General_Control_4__E_SYNC				0x10
+#define EP952_General_Control_4__VPOL_DET			0x08
+#define EP952_General_Control_4__HPOL_DET			0x04
+#define EP952_General_Control_4__EESS				0x02
+#define EP952_General_Control_4__HDMI				0x01
+
+#define EP952_General_Control_5				0x0F
+#define EP952_General_Control_5__AKSV_RDY			0x80
+#define EP952_General_Control_5__RPTR				0x10
+#define EP952_General_Control_5__RI_RDY				0x02
+#define EP952_General_Control_5__ENC_EN				0x01
+
+#define EP952_BKSV							0x10			// BKSV1-BKSV5 0x10-0x14
+
+#define EP952_AN							0x15			// AN1-AN8 0x15-0x1C
+
+#define EP952_AKSV							0x1D			// AKSV1-AKSV5 0x1D-0x21
+
+#define EP952_RI							0x22			// RI1-RI2 0x22-0x23
+
+#define EP952_M0							0x25			// 0x25-0x32
+
+#define EP952_DE_DLY						0x32			// 10 bit
+
+#define EP952_DE_Control					0x33			// 10 bit
+#define EP952_DE_Control__DE_GEN					0x40
+#define EP952_DE_Control__VSO_POL					0x08
+#define EP952_DE_Control__HSO_POL					0x04
+
+#define EP952_DE_TOP						0x34			// 6 bit
+
+#define EP952_DE_CNT						0x36			// 10 bit
+
+#define EP952_DE_LIN						0x38			// 10 bit
+
+#define EP952_H_RES							0x3A			// 11 bit
+
+#define EP952_V_RES							0x3C			// 11 bit
+
+#define EP952_Audio_Subpacket_Allocation	0x3E			// Default 0xE4
+
+#define EP952_IIS_Control					0x3F			// Default 0x00
+#define EP952_IIS_Control__ACR_EN					0x80
+#define EP952_IIS_Control__AVI_EN					0x40
+#define EP952_IIS_Control__ADO_EN					0x20
+#define EP952_IIS_Control__GC_EN					0x10
+#define EP952_IIS_Control__AUDIO_EN					0x08
+#define EP952_IIS_Control__WS_M						0x04
+#define EP952_IIS_Control__WS_POL					0x02
+#define EP952_IIS_Control__SCK_POL					0x01
+
+#define EP952_Packet_Control				0x40			// Default 0x00
+#define EP952_Packet_Control__FLAT					0x10
+#define EP952_Packet_Control__VTX0					0x08
+#define EP952_Packet_Control__PKT_RDY				0x01
+
+#define EP952_Data_Packet_Header 			0x41			// HB0-HB2 0x41-0x43
+#define EP952_Data_Packet 					0x44			// PB0-PB27 0x44-0x5F
+
+#define EP952_CTS_H		 					0x60			// 20bit (3 Byte)
+#define EP952_CTS_M		 					0x61			// 20bit (3 Byte)
+#define EP952_CTS_L		 					0x62			// 20bit (3 Byte)
+
+#define EP952_N_H			 				0x63			// 20bit (3 Byte)
+#define EP952_N_M			 				0x64			// 20bit (3 Byte)
+#define EP952_N_L			 				0x65			// 20bit (3 Byte)
+
+#define EP952_AVI_Packet 					0x66			// 14 Byte 0x66-0x73
+
+#define EP952_ADO_Packet 					0x74			// 6 Byte 0x74-0x79
+
+#define EP952_SPDIF_Sampling_Frequency 		0x7A			// 1 Byte
+
+#define EP952_Channel_Status		 		0x7B			// 5 Byte 0x7B-0x7F
+
+#define EP952_Embedded_Sync_Control	 		0x80			// Default 0x00
+
+#define EP952_H_Delay			 			0x81			// 10 bit (2 Byte)
+
+#define EP952_H_Width			 			0x83			// 10 bit (2 Byte)
+
+#define EP952_V_Delay			 			0x85			// 6 bit
+
+#define EP952_V_Width			 			0x86			// 6 bit
+
+#define EP952_V_Off_Set			 			0x87			// 12 bit (2 Byte)
+
+#define EP952_Key_Add			 			0xF0			// 1 Byte
+
+#define EP952_Key_Data			 			0xF1			// 7 Byte
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/ep952settingsdata.h b/drivers/gpu/drm/smifb2/ddk768/ep952settingsdata.h
new file mode 100644
index 000000000000..43a24d9c4b31
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/ep952settingsdata.h
@@ -0,0 +1,101 @@
+#ifndef EP952SETTINGDATA_H
+#define EP952SETTINGDATA_H
+
+// -----------------------------------------------------------------------------
+
+#define EP952_VDO_Settings_IT_Start 76
+
+// Definition of H/V Polarity
+#define  VPosHPos               0x00
+#define  VPosHNeg               0x04
+#define  VNegHPos               0x08
+#define  VNegHNeg               0x0C
+
+// Pixel Freq Type
+typedef enum {
+	PIX_FREQ_25175KHz = 0,
+	PIX_FREQ_25200KHz,
+
+	PIX_FREQ_27000KHz,
+	PIX_FREQ_27027KHz,
+
+	PIX_FREQ_54000KHz,
+	PIX_FREQ_54054KHz,
+
+	PIX_FREQ_72000KHz,
+
+	PIX_FREQ_74176KHz,
+	PIX_FREQ_74250KHz,
+
+	PIX_FREQ_108000KHz,
+	PIX_FREQ_108108KHz,
+
+	PIX_FREQ_148352KHz,
+	PIX_FREQ_148500KHz,
+
+	PIX_FREQ_PC
+
+} PIX_FREQ_TYPE;
+
+//
+// Index = [Video Code]
+//
+typedef struct _HVRES_TYPE {
+   unsigned char  HVPol;
+   unsigned short Hres;
+   unsigned short Vres;
+   unsigned short Vprd;
+} HVRES_TYPE, *PHVRES_TYPE;
+
+// DE Generation
+typedef struct _DE_GEN_SETTINGS { 
+	unsigned short DE_DLY;
+	unsigned short DE_CNT;
+	unsigned char  DE_TOP;
+	unsigned short DE_LIN;
+} DE_GEN_SETTINGS, *PDE_GEN_SETTINGS;
+
+// Embeded Sybc
+typedef struct _E_SYNC_SETTINGS { 
+	unsigned char  CTL;
+	unsigned short H_DLY;
+	unsigned short H_WIDTH;
+	unsigned char  V_DLY;
+	unsigned char  V_WIDTH;
+	unsigned short V_OFST;
+} E_SYNC_SETTINGS, *PE_SYNC_SETTINGS;
+
+// AVI Settings
+typedef struct _VDO_SETTINGS { 
+	unsigned char	VideoCode;
+	HVRES_TYPE      HVRes_Type;
+	DE_GEN_SETTINGS DE_Gen;
+	E_SYNC_SETTINGS E_Sync; // (HV_Gen)
+	unsigned char   AR_PR;
+	PIX_FREQ_TYPE   Pix_Freq_Type;
+} VDO_SETTINGS, *PVDO_SETTINGS;
+
+// Index = [Channel Number]
+// Audio Channel and Allocation
+typedef struct _ADO_SETTINGS { 
+	unsigned char SpeakerMapping;
+	unsigned char Flat;
+} ADO_SETTINGS, *PADO_SETTINGS;
+
+// Index = [Pixel Freq Type]
+// N and CTS
+typedef struct _N_CTS_SETTINGS {
+	unsigned long N;
+	unsigned long CTS; // Use hardware to calculate the CTS
+} N_CTS_SETTINGS, *PN_CTS_SETTINGS;
+
+
+extern unsigned char EP952_VDO_Settings_Max;
+extern VDO_SETTINGS EP952_VDO_Settings[];
+extern ADO_SETTINGS EP952_ADO_Settings[];
+extern N_CTS_SETTINGS N_CTS_32K[];
+extern N_CTS_SETTINGS N_CTS_44K1[];
+extern N_CTS_SETTINGS N_CTS_48K[];
+
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/hdmiregs.h b/drivers/gpu/drm/smifb2/ddk768/hdmiregs.h
new file mode 100644
index 000000000000..e158d82f5e86
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/hdmiregs.h
@@ -0,0 +1,945 @@
+#ifndef  _HDMIREGS_H_
+#define  _HDMIREGS_H_
+
+// SLI-204-06012 Rev.2.01a
+//-----------------------------------------------------------------------------
+// SLISHDMI13T Regsiter Defines         Addr        RW  init    Description
+//-----------------------------------------------------------------------------
+#define     X00_SYSTEM_CONTROL      0       //  RW  10h     Power save and interrupt output control
+	#define 		X00_SYSTEM_CONTROL_MODE													7:4
+	#define			X00_SYSTEM_CONTROL_MODE_A												1
+	#define			X00_SYSTEM_CONTROL_MODE_B												2
+	#define			X00_SYSTEM_CONTROL_MODE_D												4
+	#define			X00_SYSTEM_CONTROL_MODE_E												8
+	#define 		X00_SYSTEM_CONTROL_PLLB													3:3
+	#define			X00_SYSTEM_CONTROL_PLLB_RST			  						 	1
+	#define			X00_SYSTEM_CONTROL_PLLB_UNRST			  					  0
+	#define			X00_SYSTEM_CONTROL_INTOUT												1:1
+	#define			X00_SYSTEM_CONTROL_INTOUT_N	    								0						//Interrupt output mode
+	#define			X00_SYSTEM_CONTROL_INTOUT_PP	    							1						//Interrupt output mode
+	#define			X00_SYSTEM_CONTROL_INTOUT_POLARITY							0:0
+	#define			X00_SYSTEM_CONTROL_INTOUT_POLARITY_L	    			0						//Interrupt output polarity
+	#define			X00_SYSTEM_CONTROL_INTOUT_POLARITY_H	    		  1						//Interrupt output polarity
+
+#define     X01_N19_16            			  1       //  RW  00h     20-bit N used for cycle time stamp
+	#define			X01_N19_16_LRC_SWAP							7:4
+	#define			X01_N19_16_LRC_SWAP_NO					0						//L/R data swap
+	#define			X01_N19_16_LRC_SWAP_SP1					2
+	#define			X01_N19_16_LRC_SWAP_SP2					4
+	#define			X01_N19_16_LRC_SWAP_SP3					8
+	#define			X01_N19_16_AUDCLK								3:0
+#define     X02_N15_8               2       //  RW  00h
+#define     X03_N7_0                3       //  RW  00h
+#define     X04_SPDIF_FS            4       //  RO  00h     SPDIF sampling frequency/CTS[19:16] internal
+	#define			X04_SPDIF_FS_K							7:4
+	#define			X04_SPDIF_FS_K32						3
+	#define			X04_SPDIF_FS_K44_1					0
+	#define			X04_SPDIF_FS_K48						2
+	#define			X04_SPDIF_FS_K88_2					8
+	#define			X04_SPDIF_FS_K96			  		10
+	#define			X04_SPDIF_FS_K176_4		 			12
+	#define			X04_SPDIF_FS_K192						14
+	#define			X04_SPDIF_FS_CTSIN_19_16 		3:0
+
+#define     X05_CTS_INT             5       //  RO  00h     CTS[15:8] internal
+#define     X06_CTS_INT             6       //  RO  00h     CTS[7:0] internal
+#define     X07_CTS_EXT             7       //  RW  00h     CTS[19:16] external
+#define     X08_CTS_EXT             8       //  RW  00h     CTS[15:8] external
+#define     X09_CTS_EXT             9       //  RW  00h     CTS[7:0] external
+#define     X0A_AUDIO_SOURCE        10      //  RW  00h     Audio setting.1
+	#define			X0A_AUDIO_SOURCE_CTS						7:7
+	#define			X0A_AUDIO_SOURCE_CTS_INTERNAL					0
+	#define			X0A_AUDIO_SOURCE_CTS_EXTERNAL					1
+	#define			X0A_AUDIO_SOURCE_DS							6:5
+	#define			X0A_AUDIO_SOURCE_DS_NONE				0
+	#define			X0A_AUDIO_SOURCE_DS_2						1
+	#define			X0A_AUDIO_SOURCE_DS_4						2
+	#define			X0A_AUDIO_SOURCE_SEL						4:3
+	#define			X0A_AUDIO_SOURCE_SEL_I2S				0
+	#define			X0A_AUDIO_SOURCE_SEL_SPDIF			1
+	#define			X0A_AUDIO_SOURCE_SEL_DSD				2
+	#define			X0A_AUDIO_SOURCE_SEL_HBR				3
+	#define			X0A_AUDIO_SOURCE_MCLK						2:2
+	#define			X0A_AUDIO_SOURCE_MCLK_OFF				0
+	#define			X0A_AUDIO_SOURCE_MCLK_ON				1
+	#define			X0A_AUDIO_SOURCE_MRATIO				1:0
+	#define			X0A_AUDIO_SOURCE_MRATIO_128FS		0
+	#define			X0A_AUDIO_SOURCE_MRATIO_256FS		1
+	#define			X0A_AUDIO_SOURCE_MRATIO_384FS		2
+	#define			X0A_AUDIO_SOURCE_MRATIO_512FS		3
+	
+#define     X0B_AUDIO_SET2         			  11      //  RW  00h     Audio setting.2
+	#define			X0B_AUDIO_SET2_IDCLK					7:7
+	#define			X0B_AUDIO_SET2_IDCLK1					0						//BIT.7
+	#define			X0B_AUDIO_SET2_IDCLK1_2				1						//BIT.7
+	#define			X0B_AUDIO_SET2_PRI						6:6
+	#define			X0B_AUDIO_SET2_PRI_ASP				0
+	#define			X0B_AUDIO_SET2_PRI_ACR				1
+	#define			X0B_AUDIO_SET2_IDCLK_MODE					5:5
+	#define			X0B_AUDIO_SET2_IDCLK_MODE_AUTO			0						//BIT.5
+	#define			X0B_AUDIO_SET2_IDCLK_MODE_FIX  		1						//BIT.5
+	#define			X0B_AUDIO_SET2_FLATLINE				4:4
+	#define			X0B_AUDIO_SET2_FLATLINE_NORMAL  0
+	#define			X0B_AUDIO_SET2_FLATLINE_FLAT  	1
+	#define			X0B_AUDIO_SET2_CHANNEL				3:0         //NOT ALL LIST 
+	#define			X0B_AUDIO_SET2_CHANNEL_NOT		0
+	#define			X0B_AUDIO_SET2_CHANNEL_LEFT		8
+	#define			X0B_AUDIO_SET2_CHANNEL_RIGHT	4
+
+#define     X0C_I2S_MODE           					  12      //  RW  00h     I2S audio setting
+	#define			X0C_I2S_MODE_MCLKFQ									7:7	
+	#define			X0C_I2S_MODE_MCLKFQ_BY0AH						0
+	#define			X0C_I2S_MODE_MCLKFQ_OVERRIDE				1
+	#define			X0C_I2S_MODE_CHANNEL  							5:2
+	#define			X0C_I2S_MODE_CHANNEL_2							1
+	#define			X0C_I2S_MODE_CHANNEL_4							3
+	#define			X0C_I2S_MODE_CHANNEL_6						  7
+	#define			X0C_I2S_MODE_CHANNEL_8							15
+	#define			X0C_I2S_MODE_SEL										1:0
+	#define			X0C_I2S_MODE_SEL_STANDARD						0
+	#define			X0C_I2S_MODE_SEL_JSTF_RIGHT					1
+	#define			X0C_I2S_MODE_SEL_JSTF_LEFT					2
+
+#define     X0D_DSD_MODE            13      //  RW  00h     DSD audio setting
+	#define			X0D_DSD_MODE_CHANNEL						7:4
+	#define			X0D_DSD_MODE_CHANNEL_2					1
+	#define			X0D_DSD_MODE_CHANNEL_4					3
+	#define			X0D_DSD_MODE_CHANNEL_6					7
+	#define			X0D_DSD_MODE_CHANNEL_8					0XF		
+
+#define     X0E_DEBUG_MONITOR1      14      //  RO  00h     Reserved
+#define     X0F_DEBUG_MONITOR2      15      //  RO  00h     Reserved
+#define     X10_I2S_PINMODE         16      //  RW  00h     I2S input pin swap
+
+#define     X11_ASTATUS1            17      //  RW  00h     Audio status bits setting1
+	#define     X11_ASTATUS1_VALID          	  7:7
+	#define     X11_ASTATUS1_FREQ            		3:0
+	#define     X11_ASTATUS1_FREQ_44_1K       	15
+	#define     X11_ASTATUS1_FREQ_88_2K       	7
+	#define     X11_ASTATUS1_FREQ_22_05K     	  11
+	#define     X11_ASTATUS1_FREQ_176_4K     	  3
+	#define     X11_ASTATUS1_FREQ_48K       		13
+	#define     X11_ASTATUS1_FREQ_96K	       		5
+	#define     X11_ASTATUS1_FREQ_24K       		9
+	#define     X11_ASTATUS1_FREQ_192K       		1
+	#define     X11_ASTATUS1_FREQ_8K       			6
+	#define     X11_ASTATUS1_FREQ_11_025K    	  10
+	#define     X11_ASTATUS1_FREQ_12K       		2
+	#define     X11_ASTATUS1_FREQ_32K		       	12
+	#define     X11_ASTATUS1_FREQ_16K       		8
+	#define     X11_ASTATUS1_FREQ_DEFAUT       	0
+#define     X12_ASTATUS2            18      //  RW  00h     Audio status bits setting2
+	#define     X12_ASTATUS2_CS1		    			 	7:7
+	#define     X12_ASTATUS2_CS1_LPCM		 				0
+	#define     X12_ASTATUS2_CS1_NONLPCM				1
+	#define     X12_ASTATUS2_CS0								6:6
+	#define     X12_ASTATUS2_CS0_CONSUMER			0
+	#define     X12_ASTATUS2_CS0_PROFESSIONAL 	1
+	#define     X12_ASTATUS2_COPYRIGHT					5:5
+	#define     X12_ASTATUS2_ADDITION						4:2
+	#define     X12_ASTATUS2_ADDITION_PREM_NO		0
+	#define     X12_ASTATUS2_ADDITION_PREM_50US	1
+	#define     X12_ASTATUS2_CLKLEVEL						1:0
+	#define     X12_ASTATUS2_CLKLEVEL_II				0
+	#define     X12_ASTATUS2_CLKLEVEL_I					1
+	#define     X12_ASTATUS2_CLKLEVEL_III				2
+	
+#define     X13_CAT_CODE            19      //  RW  00h     Category code
+#define     X14_A_SOURCE            20      //  RW  00h     Source number/ Audio word length
+#define     X14_A_SOURCE_NUM        7:4
+	#define     X14_A_SOURCE_NUM_NOCOUNT             0
+	#define     X14_A_SOURCE_NUM_1			         1
+	#define     X14_A_SOURCE_NUM_2			         2
+	#define     X14_A_SOURCE_NUM_3			         3
+	#define     X14_A_SOURCE_NUM_4			         4
+	#define     X14_A_SOURCE_NUM_5			         5
+	#define     X14_A_SOURCE_NUM_6			         6
+	#define     X14_A_SOURCE_NUM_7			         7
+	#define     X14_A_SOURCE_NUM_8			         8
+	#define     X14_A_SOURCE_NUM_9			         9
+	#define     X14_A_SOURCE_NUM_10			         10
+	#define     X14_A_SOURCE_NUM_11			         11
+	#define     X14_A_SOURCE_NUM_12			         12
+	#define     X14_A_SOURCE_NUM_13			         13
+	#define     X14_A_SOURCE_NUM_14			         14
+	#define     X14_A_SOURCE_NUM_15			         15
+	#define     X14_A_SOURCE_LENGTH        		     3:0
+	#define     X14_A_SOURCE_LENGTH_16B				 2		
+	#define     X14_A_SOURCE_LENGTH_17B				 12
+	#define     X14_A_SOURCE_LENGTH_18B				 4
+	#define     X14_A_SOURCE_LENGTH_19B				 8
+	#define     X14_A_SOURCE_LENGTH_20B				 10
+	#define     X14_A_SOURCE_LENGTH_20BIT	  	     3
+	#define     X14_A_SOURCE_LENGTH_21B				 13
+	#define     X14_A_SOURCE_LENGTH_22B				 5
+	#define     X14_A_SOURCE_LENGTH_23B				 9
+	#define     X14_A_SOURCE_LENGTH_24B				 11
+	
+#define     X15_AVSET1              21      //  RW  00h     Audio/Video setting.1
+		#define			X15_AVSET1_AUDFREQ				 7:4
+		#define			X15_AVSET1_AUDFREQ_32K 		 3
+		#define			X15_AVSET1_AUDFREQ_44_1K	 0
+		#define			X15_AVSET1_AUDFREQ_48K		 2
+		#define			X15_AVSET1_AUDFREQ_88_2K	 8
+		#define			X15_AVSET1_AUDFREQ_96K		 10
+		#define			X15_AVSET1_AUDFREQ_176_4K	 12
+		#define			X15_AVSET1_AUDFREQ_192K	 	 14
+		#define			X15_AVSET1_AUDFREQ_768K	 	 9
+		#define			X15_AVSET1_VIDFORM							 								3:1				
+		#define			X15_AVSET1_VIDFORM_RGB_YCC444		        		  	 0
+		#define			X15_AVSET1_VIDFORM_YCC422				   			 			   1
+		#define			X15_AVSET1_VIDFORM_YCC422_SAVEAV           	     2
+		#define			X15_AVSET1_VIDFORM_SEPA_SYNCS		        		  	 3	
+		#define			X15_AVSET1_VIDFORM_EMBED_SYNCS	          	     4	
+		#define			X15_AVSET1_VIDFORM_RGB444_YCC444       		       5		
+		#define			X15_AVSET1_VIDFORM_DDR_YCC422				     				 6
+		#define			X15_AVSET1_DE																		 0:0
+		#define			X15_AVSET1_DE_INTERNAL				 	   				  		  0
+		#define			X15_AVSET1_DE_EXTERNAL					  						   1
+
+#define     X16_VIDEO1              22      //  RW  34h     Video setting.1
+		#define			X16_VIDEO1_OUT							 7:6
+		#define			X16_VIDEO1_OUT_RGB444				     0
+		#define			X16_VIDEO1_OUT_YCC444				     1
+		#define			X16_VIDEO1_OUT_YCC422				     2
+		#define			X16_VIDEO1_IN							 5:4
+		#define			X16_VIDEO1_IN_WID_12				     0
+		#define			X16_VIDEO1_IN_WID_10				     1
+		#define			X16_VIDEO1_IN_WID_8					     3
+		#define			X16_VIDEO1_SAV_EAV					     3:2
+		#define			X16_VIDEO1_SAV_EAV_CH0			         0
+		#define			X16_VIDEO1_SAV_EAV_CH1			         1
+		#define			X16_VIDEO1_SAV_EAV_CH2			         2
+		#define			X16_VIDEO1_IN_COLOR					     0:0
+		#define			X16_VIDEO1_IN_COLOR_RGB			         0
+		#define			X16_VIDEO1_IN_COLOR_YCC			         1
+
+#define     X17_DC_REG              23      //  RW  20h     Deep color setting
+		#define	X17_DC_REG_TMDS								 7:6
+		#define	X17_DC_REG_TMDS_8b						     0
+		#define	X17_DC_REG_TMDS_10b						     1
+		#define	X17_DC_REG_TMDS_12b						     2				
+		#define	X17_DC_REG_FIFO								 5:5
+		#define	X17_DC_REG_ESART							 4:4
+		#define	X17_DC_REG_ELAST							 3:3
+		#define	X17_DC_REG_EBYTE							 2:2
+		#define	X17_DC_REG_EXTCLR							 1:1
+		#define	X17_DC_REG_EXTCLR_SOF					     0
+		#define	X17_DC_REG_EXTCLR_SOH					     1
+		
+#define     X18_CSC_C0_HI           24      //  RW  04h     Color Space Conversion Parameters		
+#define     X19_CSC_C0_LO           25      //  RW  00h
+#define     X1A_CSC_C1_HI           26      //  RW  05h     Color Space Conversion Parameters
+#define     X1B_CSC_C1_LO           27      //  RW  09h
+#define     X1C_CSC_C2_HI           28      //  RW  00h
+#define     X1D_CSC_C2_LO           29      //  RW  00h
+#define     X1E_CSC_C3_HI           30      //  RW  02h
+#define     X1F_CSC_C3_LO           31      //  RW  A1h
+#define     X20_CSC_C4_HI           32      //  RW  04h
+#define     X21_CSC_C4_LO           33      //  RW  00h
+#define     X22_CSC_C5_HI           34      //  RW  12h
+#define     X23_CSC_C5_LO           35      //  RW  91h
+#define     X24_CSC_C6_HI           36      //  RW  11h
+#define     X25_CSC_C6_LO           37      //  RW  59h
+#define     X26_CSC_C7_HI           38      //  RW  00h
+#define     X27_CSC_C7_LO           39      //  RW  7Dh
+#define     X28_CSC_C8_HI           40      //  RW  04h
+#define     X29_CSC_C8_LO           41      //  RW  00h
+#define     X2A_CSC_C9_HI           42      //  RW  00h
+#define     X2B_CSC_C9_LO           43      //  RW  00h
+#define     X2C_CSC_C10_HI          44      //  RW  06h
+#define     X2D_CSC_C10_LO          45      //  RW  EFh
+#define     X2E_CSC_C11_HI          46      //  RW  02h
+#define     X2F_CSC_C11_LO          47      //  RW  DDh
+    
+#define X30_EXT_VPARAMS                                         48      //  RW  00h     External video parameter settings
+#define X30_EXT_VPARAMS_VSYNC_OFFSET               7:4
+#define X30_EXT_VPARAMS_VSYNC_PHASE                 3:3
+#define X30_EXT_VPARAMS_VSYNC_PHASE_NEG  	 0
+#define X30_EXT_VPARAMS_VSYNC_PHASE_POS		 1
+#define X30_EXT_VPARAMS_HSYNC_PHASE                 2:2
+#define X30_EXT_VPARAMS_HSYNC_PHASE_NEG 	 0
+#define X30_EXT_VPARAMS_HSYNC_PHASE_POS		 1
+#define X30_EXT_VPARAMS_PI                                     1:1
+#define X30_EXT_VPARAMS_PI_PROGRESSIVE             0
+#define X30_EXT_VPARAMS_PI_INTERLACE			 1
+#define X30_EXT_VPARAMS_USE                                  0:0
+#define X30_EXT_VPARAMS_USE_PRE_PROG                0
+#define X30_EXT_VPARAMS_USE_EXTERNAL                1
+
+#define     X31_EXT_HTOTAL          49      //  RW  00h     External horizontal total
+#define     X32_EXT_HTOTAL          50      //
+#define     X33_EXT_HBLANK          51      //  RW  00h     External horizontal blank
+#define     X34_EXT_HBLANK          52      //
+#define     X35_EXT_HDLY            53      //  RW  00h     External horizontal delay
+#define     X36_EXT_HDLY            54      //
+#define     X37_EXT_HS_DUR          55      //  RW  00h     External horizontal duration
+#define     X38_EXT_HS_DUR          56      //
+#define     X39_EXT_VTOTAL          57      //  RW  00h     External vertical total
+#define     X3A_EXT_VTOTAL          58      //
+#define     X3B_AVSET2                              59              //  RW                                          00h     Audio/Video setting.2
+		#define X3B_AVSET2_CTS_DEBUG				 7:7
+		#define X3B_AVSET2_CD_ZERO					 6:6	
+		#define X3B_AVSET2_EXT_DE					 5:5
+		#define X3B_AVSET2_DCC_I2C_RST			     4:4
+		#define X3B_AVSET2_VID_CODE39				 3:3
+		#define X3B_AVSET2_BLACK_FULL		 		 1:1
+		#define X3B_AVSET2_CSC		 				 0:0
+//				#define     CSC_ENABLE                                  0x01    //          R/W                                     1b  Color Space Conversion enable
+//        #define     SEL_FULL_RANGE                              0x02    //          R/W                                     1b  Select Full/Limited range for Send black video mode
+//        #define     EN_M0_LOAD                                  0x04    //          R/W                                     1b  Load M0 into Akey area
+//        #define     EXT_DE_CNT                                  0x20    //          R/W                                     1b  External DE control
+//        #define     CD_ZERO                                     0x40    //          R/W                                     1b  CD all zero override
+//        #define     CTS_DEBUG                                   0x80    //          R/W                                     1b  Debug bit for CTS timing
+#define     X3C_EX_VID              60      //  RW  00h     External input Video ID(VID)
+#define     X3D_EXT_VBLANK          61      //  RW  00h     External virtical blank
+#define     X3E_EXT_VDLY            62      //  RW  00h     External virtical delay
+#define     X3F_EXT_VS_DUR          63      //  RW  00h     External virtical duration
+//				#define     X40_CTRL_PKT_EN         64      //  RW  00h     Control packet enable
+	#define X40_CTRL_PKT_EN										   0X40
+		#define X40_CTRL_PKT_EN_GENE_CTRL					    						  7:7
+		#define X40_CTRL_PKT_EN_GENE_CTRL_DIS					 						   0
+		#define X40_CTRL_PKT_EN_GENE_CTRL_EN					  						  1
+		#define X40_CTRL_PKT_EN_MPEG                                6:6
+		#define X40_CTRL_PKT_EN_MPEG_DIS														0
+		#define X40_CTRL_PKT_EN_MPEG_EN															1
+		#define X40_CTRL_PKT_EN_PROD                                5:5
+		#define X40_CTRL_PKT_EN_PROD_DIS							 						   0
+		#define X40_CTRL_PKT_EN_PROD_EN						     						   1
+		#define X40_CTRL_PKT_EN_VENDOR                              4:4
+		#define X40_CTRL_PKT_EN_VENDOR_DIS					    						0
+		#define X40_CTRL_PKT_EN_VENDOR_EN														1
+		#define X40_CTRL_PKT_EN_GAMUT                               3:3
+		#define X40_CTRL_PKT_EN_GAMUT_DIS														0
+		#define X40_CTRL_PKT_EN_GAMUT_EN														1
+		#define X40_CTRL_PKT_EN_ISRC                                2:2
+		#define X40_CTRL_PKT_EN_ISRC_DIS														0
+		#define X40_CTRL_PKT_EN_ISRC_EN															1
+		#define X40_CTRL_PKT_EN_ACP	                                1:1
+		#define X40_CTRL_PKT_EN_ACP_DIS															0
+		#define X40_CTRL_PKT_EN_ACP_EN							 								1
+		#define X40_CTRL_PKT_EN_GENE                                0:0
+		#define X40_CTRL_PKT_EN_GENE_DIS															0
+		#define X40_CTRL_PKT_EN_GENE_EN																1
+
+#define     X41_SEND_CPKT_AUTO      65      //  RW  00h     HB0 for generic control packet
+		#define X41_SEND_CPKT_AUTO_GENE_CTRL                        7:7
+		#define X41_SEND_CPKT_AUTO_GENE_CTRL_DIS			    					0
+		#define X41_SEND_CPKT_AUTO_GENE_CTRL_EN					  				  1
+		#define X41_SEND_CPKT_AUTO_MPEG                             6:6
+		#define X41_SEND_CPKT_AUTO_MPEG_DIS													0
+		#define X41_SEND_CPKT_AUTO_MPEG_EN													1
+		#define X41_SEND_CPKT_AUTO_PROD                             5:5
+		#define X41_SEND_CPKT_AUTO_PROD_DIS													0
+		#define X41_SEND_CPKT_AUTO_PROD_EN													1
+		#define X41_SEND_CPKT_AUTO_VENDOR                           4:4
+		#define X41_SEND_CPKT_AUTO_VENDOR_DIS												0
+		#define X41_SEND_CPKT_AUTO_VENDOR_EN												1
+		#define X41_SEND_CPKT_AUTO_GAMUT                            3:3
+		#define X41_SEND_CPKT_AUTO_GAMUT_DIS												0
+		#define X41_SEND_CPKT_AUTO_GAMUT_EN													1
+		#define X41_SEND_CPKT_AUTO_ISRC                             2:2
+		#define X41_SEND_CPKT_AUTO_ISRC_DIS													0
+		#define X41_SEND_CPKT_AUTO_ISRC_EN													1
+		#define X41_SEND_CPKT_AUTO_ACP                              1:1
+		#define X41_SEND_CPKT_AUTO_ACP_DIS													0
+		#define X41_SEND_CPKT_AUTO_ACP_EN                           1
+		#define X41_SEND_CPKT_AUTO_GENERIC                          0:0
+		#define X41_SEND_CPKT_AUTO_GENERIC_DIS				    			  	0
+		#define X41_SEND_CPKT_AUTO_GENERIC_EN												1
+		
+#define     X42_AUTO_CHECKSUM       66      //  RW  00h     Auto checksum option
+#define X42_AUTO_CHECKSUM_OPT						0:0
+#define X42_AUTO_CHECKSUM_OPT_DIS	    	0
+#define X42_AUTO_CHECKSUM_OPT_EN		    1
+
+//  #define     RESERVED                67      //  RW  00h
+//  #define     RESERVED                68      //  RW  00h
+#define     X45_VIDEO2                              69              //  RW                                          00h     Video setting.2
+		#define X45_VIDEO2_CLR_AVMUTE						    7:7
+		#define X45_VIDEO2_CLR_AVMUTE_DIS				    	0
+		#define X45_VIDEO2_CLR_AVMUTE_EN				        1
+		#define X45_VIDEO2_SET_AVMUTE					    	6:6
+		#define X45_VIDEO2_SET_AVMUTE_DIS					    0
+		#define X45_VIDEO2_SET_AVMUTE_EN				    	1
+		#define X45_VIDEO2_AUDIO_RESET						    2:2
+		#define X45_VIDEO2_AUDIO_RESET_CLR			 	        0
+		#define X45_VIDEO2_AUDIO_RESET_SET			            1
+		#define X45_VIDEO2_NOAUDIO							    1:1
+		#define X45_VIDEO2_NOAUDIO_CLR			 	        0
+		#define X45_VIDEO2_NOAUDIO_SET			            1
+		#define X45_VIDEO2_NOVIDEO					        0:0
+		#define X45_VIDEO2_NOVIDEO_CLR			 	        0
+		#define X45_VIDEO2_NOVIDEO_SET			            1
+//				#define     NOVIDEO                                     0x01    //          R/W                                     1b  Send black video
+//        #define     NOAUDIO                                     0x02    //          R/W                                     1b  Send no audio
+//        #define     AUDIORST                                    0x04    //          R/W                                     1b  Audio capture logic reset
+//        #define     SET_AV_MUTE                                 0x40    //          R/W                                     1b  Send �gSet AV mute�h
+//        #define     CLEAR_AV_MUTE                               0x80    //          R/W                                     1b  Clear AV mute�h
+//  #define     RESERVED                70      //  RW  00h     Reserved
+    #define     X46_OUTPUT_OPTION                70      //  RW  00h     Reserved
+//    #define     X47_VIDEO4              71      //  RW  00h     Video setting.4
+//    #define     X48_ACT_LN_STRT_LSB     72      //  RW  00h     Active Line Start LSB
+//    #define     X49_ACT_LN_STRT_MSB     73      //  RW  00h     Active Line Start MSB
+//    #define     X4A_ACT_LN_END_LSB      74      //  RW  00h     Active Line End LSB
+//    #define     X4B_ACT_LN_END_MSB      75      //  RW  00h     Active Line End MSB
+//    #define     X4C_ACT_PIX_STRT_LSB    76      //  RW  00h     Active Pixel Start LSB
+//    #define     X4D_ACT_PIX_STRT_MSB    77      //  RW  00h     Active Pixel Start MSB
+//    #define     X4E_ACT_PIX_END_LSB     78      //  RW  00h     Active Pixel End LSB
+//    #define     X4F_ACT_PIX_END_MSB     79      //  RW  00h     Active Pixel End MSB
+//    #define     X50_EXT_AUDIO_SET       80      //  RW  00h     Extra audio setting
+//SLI10131
+//    #define     X51_SPEAKER_MAP         81      //  RW  00h     speaker Mapping CA[7:0]
+//IP V2.11
+#define     X51_PHY_CTRL            81      //  RW  00h     Revervd[7:4],PHY_OPTION[3:0]
+
+#define     X52_HSYNC_PLACE_656     82      //  RW  00h     HSYNC placement at ITU656
+#define     X53_HSYNC_PLACE_656     83      //
+#define     X54_VSYNC_PLACE_656     84      //  RW  00h     VSYNC placement at ITU656
+#define     X55_VSYNC_PLACE_656     85      //
+	#define     X55_VSYNC_PLACE_656_EN     			             7:7
+	#define     X55_VSYNC_PLACE_656_EN_INACT                     0
+	#define     X55_VSYNC_PLACE_656_EN_ACT   	                 1
+#define     X56_PHY_CTRL            86      //  RW  0Fh     SLIPHDMIT parameter settings
+	#define X56_PHY_CTRL_DRV_TEST_IN							 7:7
+	#define X56_PHY_CTRL_DRV_TEST_EN							 6:6
+	#define X56_PHY_CTRL_PLLA_BYPAS								 4:4
+	#define X56_PHY_CTRL_SPEED_B									 3:2
+	#define X56_PHY_CTRL_SPEED_A					             1:0
+
+#define     X57_PHY_CTRL            87      //  RW  00h
+	#define	X57_PHY_CTRL_PLLB_CONFIG17					     	 2:2
+	#define	X57_PHY_CTRL_PLLA_CONFIG17					    	 1:1
+#define     X58_PHY_CTRL            88      //  RW  00h
+		#define X58_PHY_CTRL_BGR_DISC							 7:7
+		#define X58_PHY_CTRL_BGR_V_OFFSET						 6:4				//BIT6-4
+		#define X58_PHY_CTRL_BGR_I_OFFSET						 2:0				//BIT2-0
+				
+#define     X59_PHY_CTRL            89      //  RW  20h
+#define     X5A_PHY_CTRL            90      //  RW  00h
+#define     X5B_PHY_CTRL            91      //  RW  20h
+#define     X5C_PHY_CTRL            92      //  RW  00h
+
+#define     X5D_PHY_CTRL            93      //  RW  00h
+		#define	X5D_PHY_CTRL_DRV_CONFIG2_0			6:4																		//BIT6-4
+		#define	X5D_PHY_CTRL_PE_CNTRL2_0				         2:0					//BIT2-0				
+#define     X5E_PHY_CTRL         					             94      												//  RW  00h
+		#define	X5E_PHY_CTRL_PLLB_CONFIG16						 5:5
+		#define	X5E_PHY_CTRL_PLLA_CONFIG16						 4:4
+		#define	X5E_PHY_CTRL_AMON_SEL2_0					   	 2:0
+#define     X5F_PACKET_INDEX                        95              //  R/W                                         00h     Packet Buffer Index
+        #define     GENERIC_PACKET                              0x00    //          R/W                                     00h Generic packet
+        #define     ACP_PACKET                                  0x01    //          R/W                                     00h ACP packet
+        #define     ISRC1_PACKET                                0x02    //          R/W                                     00h ISRC1 packet
+        #define     ISRC2_PACKET                                0x03    //          R/W                                     00h ISRC2 packet
+        #define     GAMUT_PACKET                                0x04    //          R/W                                     00h Gamut metadata packet
+        #define     VENDOR_INFO_PACKET                          0x05    //          R/W                                     00h Vendor specific InfoFrame
+        #define     AVI_INFO_PACKET                             0x06    //          R/W                                     00h AVI InfoFrame
+        #define     PRODUCT_INFO_PACKET                         0x07    //          R/W                                     00h Source product descriptor InfoFrame
+        #define     AUDIO_INFO_PACKET                           0x08    //          R/W                                     00h Audio InfoFrame packet
+        #define     MPEG_SRC_INFO_PACKET                        0x09    //          R/W                                     00h MPEG source InfoFrame
+#define     X60_PACKET_HB0          96      //  RW  00h     HB0
+#define     X61_PACKET_HB1          97      //  RW  00h     HB1
+#define     X62_PACKET_HB2          98      //  RW  00h     HB2
+#define     X63_PACKET_PB0          99      //  RW  00h     PB0
+#define     X64_PACKET_PB1          100     //  RW  00h
+#define     X65_PACKET_PB2          101     //  RW  00h
+#define     X66_PACKET_PB3          102     //  RW  00h
+#define     X67_PACKET_PB4          103     //  RW  00h
+#define     X68_PACKET_PB5          104     //  RW  00h
+#define     X69_PACKET_PB6          105     //  RW  00h
+#define     X6A_PACKET_PB7          106     //  RW  00h
+#define     X6B_PACKET_PB8          107     //  RW  00h
+#define     X6C_PACKET_PB9          108     //  RW  00h
+#define     X6D_PACKET_PB10         109     //  RW  00h
+#define     X6E_PACKET_PB11         110     //  RW  00h
+#define     X6F_PACKET_PB12         111     //  RW  00h
+#define     X70_PACKET_PB13         112     //  RW  00h
+#define     X71_PACKET_PB14         113     //  RW  00h
+#define     X72_PACKET_PB15         114     //  RW  00h
+#define     X73_PACKET_PB16         115     //  RW  00h
+#define     X74_PACKET_PB17         116     //  RW  00h
+#define     X75_PACKET_PB18         117     //  RW  00h
+#define     X76_PACKET_PB19         118     //  RW  00h
+#define     X77_PACKET_PB20         119     //  RW  00h
+#define     X78_PACKET_PB21         120     //  RW  00h
+#define     X79_PACKET_PB22         121     //  RW  00h
+#define     X7A_PACKET_PB23         122     //  RW  00h
+#define     X7B_PACKET_PB24         123     //  RW  00h
+#define     X7C_PACKET_PB25         124     //  RW  00h
+#define     X7D_PACKET_PB26         125     //  RW  00h
+#define     X7E_PACKET_PB27         126     //  RW  00h     PB27
+//  #define     RESERVED                127     //  Reserved
+#define     X80_EDID                128     //  RO  -       Access window for EDID buffer
+#define     X81_ISRC2_PB0           129     //  RW  00h     ISRC2 PB0-15
+#define     X82_ISRC2_PB1           130     //  RW  00h
+
+
+//		#define     X83_ISRC2_PB2           131     //  RW  00h
+//    #define     X84_ISRC2_PB3           132     //  RW  00h
+//    #define     X85_ISRC2_PB4           133     //  RW  00h
+//    #define     X86_ISRC2_PB5           134     //  RW  00h
+//    #define     X87_ISRC2_PB6           135     //  RW  00h
+//    #define     X88_ISRC2_PB7           136     //  RW  00h
+//    #define     X89_ISRC2_PB8           137     //  RW  00h
+//    #define     X8A_ISRC2_PB9           138     //  RW  00h     ISRC2 PB0-15
+//    #define     X8B_ISRC2_PB10          139     //  RW  00h
+//    #define     X8C_ISRC2_PB11          140     //  RW  00h
+//    #define     X8D_ISRC2_PB12          141     //  RW  00h
+//    #define     X8E_ISRC2_PB13          142     //  RW  00h
+//    #define     X8F_ISRC2_PB14          143     //  RW  00h
+//    #define     X90_ISRC2_PB15          144     //  RW  00h
+//    #define     X91_ISRC1_HB1           145     //  RW  00h     ISRC2 HB1
+#define     X92_INT_MASK1                   146             //  RW                                          C0h     Mask for Interrupt Group1
+		#define X92_INT_MASK1_HPG										 7:7        //'1B' NO MASKED
+		#define X92_INT_MASK1_MSENS										 6:6				 //'1B' NO MASKED
+		#define X92_INT_MASK1_VSYNC										 5:5				 //'1B' NO MASKED
+		#define X92_INT_MASK1_AFIFO_FULL								 4:4				 //'1B' NO MASKED
+		#define X92_INT_MASK1_EDID_RDY									 2:2				 //'1B' NO MASKED
+		#define X92_INT_MASK1_EDID_ERR									 1:1				 //'1B' NO MASKED
+				
+
+//				#define     EDID_ERR_MSK                        0x02    //          R/W                                     1b  EDID error detect interrupt mask
+//        #define     EDID_RDY_MSK                        0x04    //          R/W                                     1b  EDID ready interrupt mask
+//        #define     AFIFO_FULL_MSK                      0x10    //          R/W                                     0b  Audio FIFO full detect interrupt mask
+//        #define     VSYNC_MSK                           0x20    //          R/W                                     0b  VSYNC detect interrupt mask
+//        #define     MSENS_MSK                           0x40    //          R/W                                     0b  MSENS detect interrupt mask
+//        #define     HPG_MSK                             0x80    //          R/W                                     0b  Hot plug detect interrupt mask
+#define     X93_INT_MASK2                   147             //  RW                                          78h     Mask for Interrupt Group2
+		#define X93_INT_MASK2_HDCP_ERR									 7:7				 //'1B' NO MASKED
+		#define X93_INT_MASK2_BKSV_RPRDY								 6:6				 //'1B' NO MASKED
+		#define X93_INT_MASK2_BKSV_RCRDY								 5:5				 //'1B' NO MASKED
+		#define X93_INT_MASK2_AUTH_DONE									 4:4				 //'1B' NO MASKED
+		#define X93_INT_MASK2_RDY_AUTH									 3:3				 //'1B' NO MASKED
+			
+
+//				#define     RDY_AUTH_MSK                        0x08    //          R/W                                     1b  Authentication ready interrupt mask
+//        #define     AUTH_DONE_MSK                       0x10    //          R/W                                     1b  HDCP authentication done interrupt mask
+//        #define     BKSV_RCRDY_MSK                      0x20    //          R/W                                     1b  BKSV ready from receiver interrupt mask
+//        #define     BKSV_RPRDY_MSK                      0x40    //          R/W                                     1b  BKSVs list ready from repeater interrupt mask
+//        #define     HDCP_ERR_MSK                        0x80    //          R/W                                     0b  HDCP error detect interrupt mask
+#define     X94_INT1_ST                     148             //  RW                                          00h     Interrupt status Group1
+		#define X94_INT1_ST_HPG											 7:7				// 1b means Interrupted
+		#define X94_INT1_ST_HPG_EN										 1
+		#define X94_INT1_ST_HPG_NO										 0
+		#define X94_INT1_ST_MSENS									 	 6:6				// 1b means Interrupted		
+		#define X94_INT1_ST_MSENS_EN									 1
+		#define X94_INT1_ST_MSENS_NO									 0
+		#define X94_INT1_ST_VSYNC										 5:5				// 1b means Interrupted	
+		#define X94_INT1_ST_VSYNC_EN									 1
+		#define X94_INT1_ST_VSYNC_NO									 0
+		#define X94_INT1_ST_AFIFO_FULL							         4:4				// 1b means Interrupted	
+		#define X94_INT1_ST_AFIFO_FULL_EN							     1
+		#define X94_INT1_ST_AFIFO_FULL_NO							     0
+		#define X94_INT1_ST_EDID_RDY								     2:2				// 1b means Interrupted	
+		#define X94_INT1_ST_EDID_RDY_EN								     1
+		#define X94_INT1_ST_EDID_RDY_NO								     0
+		#define X94_INT1_ST_EDID_ERR								     1:1				// 1b means Interrupted		
+		#define X94_INT1_ST_EDID_ERR_EN								     1
+		#define X94_INT1_ST_EDID_ERR_NO								     0
+		
+//				#define     EDID_ERR_INT                        0x02    //          R/W                                     0b  EDID error detect interrupt
+//        #define     EDID_RDY_INT                        0x04    //          R/W                                     0b  EDID ready interrupt
+//        #define     AFIFO_FULL_INT                      0x10    //          R/W                                     0b  Audio FIFO full detect interrupt
+//        #define     VSYNC_INT                           0x20    //          R/W                                     0b  VSYNC detect interrupt
+//        #define     MSENS_INT                           0x40    //          R/W                                     0b  MSENS detect interrupt
+//        #define     HPG_INT                             0x80    //          R/W                                     0b  Hot plug detect interrupt
+#define     X95_INT2_ST                     149             //  RW                                          00h     Interrupt status Group2
+		#define X95_INT2_ST_HDCP_ERR            		7:7 
+		#define X95_INT2_ST_BKSV_RPRDY            	    6:6
+		#define X95_INT2_ST_BKSV_RCRDY            	    5:5
+		#define X95_INT2_ST_AUTH_DONE            	 	4:4
+		#define X95_INT2_ST_RDY_AUTH            	 	3:3
+				
+//				#define     RDY_AUTH_INT                        0x08    //          R/W                                     0b  Authentication ready interrupt
+//        #define     AUTH_DONE_INT                       0x10    //          R/W                                     0b  HDCP authentication done interrupt
+//        #define     BKSV_RCRDY_INT                      0x20    //          R/W                                     0b  BKSV ready from receiver interrupt
+//        #define     BKSV_RPRDY_INT                      0x40    //          R/W                                     0b  BKSVs list ready from repeater interrupt
+//        #define     HDCP_ERR_INT                        0x80    //          R/W                                     0b  HDCP error detect interrupt
+#define     X96_INT_MASK3                   0X96
+#define     X97_INT_MASK3                   0X97
+#define     X98_INT3_ST                   	0X98
+		#define     X98_INT3_ST_SF_MODE_READY           7:7
+		#define     X98_INT3_ST_RI_READY     			6:6
+		#define     X98_INT3_ST_PJ_READY     			5:5
+		#define     X98_INT3_ST_AN_READY     			4:4
+		#define     X98_INT3_ST_SHA1_READY     		    3:3
+		#define     X98_INT3_ST_ENC_EN     				2:2
+		#define     X98_INT3_ST_ENC_DIS_AVMUTE 		    1:1
+		#define     X98_INT3_ST_ENC_DIS_NO_AVMUTE       0:0
+		
+#define     X99_INT4_ST               	    0X99
+		#define     X99_INT4_ST_I2C_ACK              7:7
+		#define     X99_INT4_ST_I2C_ERR_ACK          6:6
+		#define     X99_INT4_ST_RI_SAVE_READY        5:5
+		#define     X99_INT4_ST_PJ_SAVE_READY        4:4
+		#define     X99_INT4_ST_FR_CNT_UPDATE        3:3
+		
+#define     X9A_HDCP_CTRL1               	    0X9A
+		#define     X9A_HDCP_CTRL1_AUTH                7:7
+		#define     X9A_HDCP_CTRL1_AUTH_HWARE          0
+		#define     X9A_HDCP_CTRL1_AUTH_SWARE          1
+		#define     X9A_HDCP_CTRL1_SOFT				   5:5
+		#define     X9A_HDCP_CTRL1_SOFT_CLR            0
+		#define     X9A_HDCP_CTRL1_SOFT_SET            1
+		#define     X9A_HDCP_CTRL1_PREP_AN             4:4
+		#define     X9A_HDCP_CTRL1_REPEAT        	   2:2
+		#define     X9A_HDCP_CTRL1_REPEAT_CLR    	   0
+		#define     X9A_HDCP_CTRL1_REPEAT_SET    	   1
+		#define     X9A_HDCP_CTRL1_START_AUTH          1:1
+		#define     X9A_HDCP_CTRL1_CALC_SHA1   		   0:0
+		
+#define     X9C_FRAME_CNT              	    		0X9C
+#define     X9D_FRAME_CNT_RI              	        0X9D
+#define     X9E_DDC_ACS_LENGTH          	   	    0X9E
+#define     XA0_I2C_OFFSET             	    		0XA0
+#define     XA1_DDC_I2C_CTRL            	    	0XA1
+		#define     XA1_DDC_I2C_CTRL_SEL            	  2:2
+		#define     XA1_DDC_I2C_CTRL_SEL_BUF0_4           0
+		#define     XA1_DDC_I2C_CTRL_SEL_80H           	  1
+		#define     XA1_DDC_I2C_CTRL_W_START              1:1
+		#define     XA1_DDC_I2C_CTRL_R_START              0:0
+#define     XA2_DDC_I2C_RBUF0            	    	0XA2
+#define     XA3_DDC_I2C_RBUF1            	    	0XA3
+#define     XA4_DDC_I2C_RBUF2            	    	0XA4
+#define     XA5_DDC_I2C_RBUF3            	    	0XA5
+#define     XA6_DDC_I2C_RBUF4            	    	0XA6
+#define     XA7_DDC_I2C_WBUF0            	    	0XA7
+#define     XA8_DDC_I2C_WBUF1            	    	0XA8
+#define     XA9_DDC_I2C_WBUF2            	    	0XA9
+#define     XAA_DDC_I2C_WBUF3            	   		0XAA
+#define     XAB_DDC_I2C_WBUF4            	   		0XAB
+#define     XAC_DDC_I2C_WBUF5            	   		0XAC
+#define     XAD_DDC_I2C_WBUF6            	   		0XAD
+#define     XAE_DDC_I2C_WBUF7            	   		0XAE
+
+
+
+//  #define     VN1                     150     //  RW  00h     Generic control packet (PB1-PB23)
+//  #define     VN2                     151     //  RW  00h
+//  #define     VN3                     152     //  RW  00h
+//  #define     VN4                     153     //  RW  00h
+//  #define     VN5                     154     //  RW  00h
+//  #define     VN6                     155     //  RW  00h
+//  #define     VN7                     156     //  RW  00h
+//  #define     VN8                     157     //  RW  00h
+//  #define     PD1                     158     //  RW  00h
+//  #define     PD2                     159     //  RW  00h
+//  #define     PD3                     160     //  RW  00h
+//  #define     PD4                     161     //  RW  00h
+//  #define     PD5                     162     //  RW  00h
+//  #define     PD6                     163     //  RW  00h
+//  #define     PD7                     164     //  RW  00h
+//  #define     PD8                     165     //  RW  00h
+//  #define     PD9                     166     //  RW  00h
+//  #define     PD10                    167     //  RW  00h
+//  #define     PD11                    168     //  RW  00h
+//  #define     PD12                    169     //  RW  00h
+//  #define     PD13                    170     //  RW  00h
+//  #define     PD14                    171     //  RW  00h
+//  #define     PD15                    172     //  RW  00h
+//  #define     PD16                    173     //  RW  00h     Generic control packet (PB24-PB25)
+//  #define     SRC_DEV_INFO            174     //  RW  00h
+#define     XAF_HDCP_CTRL                   175             //  R/W                                         12h     HDCP Control Register
+		#define     XAF_HDCP_CTRL_HDCP_REQ          7:7
+		#define     XAF_HDCP_CTRL_BKSV_PASS         6:6
+		#define     XAF_HDCP_CTRL_BKSV_FAIL         5:5
+		#define     XAF_HDCP_CTRL_FRAME_ENC         4:4
+		#define     XAF_HDCP_CTRL_STOP_AUTH         3:3
+		#define     XAF_HDCP_CTRL_ADV_CIPHER        2:2
+		#define     XAF_HDCP_CTRL_MODE         		1:1
+		#define     XAF_HDCP_CTRL_MODE_DVI         	0
+		#define     XAF_HDCP_CTRL_MODE_HDMI         1
+		#define     XAF_HDCP_CTRL_RESET      		0:0
+
+//        #define     HDCP_RESET                          0x01    //          R/W                                     0b  Reset HDCP
+//        #define     HDMI_MODE_CTRL                      0x02    //          R/W                                     0b  HDMI/DVI mode
+//        #define     ADV_CIPHER                          0x04    //          R/W                                     0b  Advanced cipher mode
+//        #define     STOP_AUTH                           0x08    //          R/W                                     0b  Stop HDCP authentication
+//        #define     FRAME_ENC                           0x10    //          R/W                                     0b  Frame encrypt
+//        #define     BKSV_FAIL                           0x20    //          R/W                                     0b  BKSV check result (FAIL)
+//        #define     BKSV_PASS                           0x40    //          R/W                                     0b  BKSV check result (PASS)
+//        #define     HDCP_REQ                            0x80    //          R/W                                     0b  HDCP authentication start
+//  #define     AN                      176     //  RO  00h     An register
+//                                      177     //
+//                                      178     //
+//                                      179     //
+//                                      180     //
+//                                      181     //
+//                                      182     //
+//                                      183     //
+//    #define     XB0_HDCP_STATUS                 176             //  RO                                          00h     HDCP Status Register
+#define     XB2_RI_FRAME_CNT                 0XB2  
+#define     XB7_DDC_CTL                	 0XB7
+		#define     XB7_DDC_CTL_PRESCL            7:7
+		#define     XB7_DDC_CTL_PRESCL_Y          0
+		#define     XB7_DDC_CTL_PRESCL_NO         1
+		#define     XB7_DDC_CTL_SDA_DRV           6:6
+		#define     XB7_DDC_CTL_SDA_DRV_L         0
+		#define     XB7_DDC_CTL_SDA_DRV_H         1
+		#define     XB7_DDC_CTL_SCL_DRV           5:5
+		#define     XB7_DDC_CTL_SCL_DRV_L         0
+		#define     XB7_DDC_CTL_SCL_DRV_H         1
+		#define     XB7_DDC_CTL_OVERRIDE          4:4
+		#define     XB7_DDC_CTL_OVERRIDE_N        0
+		#define     XB7_DDC_CTL_OVERRIDE_Y        1
+		#define     XB7_DDC_CTL_SDA_ST        	  1:1
+		#define     XB7_DDC_CTL_SDA_ST_L          0
+		#define     XB7_DDC_CTL_SDA_ST_H          1
+		#define     XB7_DDC_CTL_SCL_ST        	  0:0
+		#define     XB7_DDC_CTL_SCL_ST_L          0
+		#define     XB7_DDC_CTL_SCL_ST_H          1
+		
+#define     XB8_HDCP_STATUS                 184             //  RO                                          00h     HDCP Status Register
+		#define     XB8_HDCP_STATUS_AUTH 					7:7
+		#define     XB8_HDCP_STATUS_AUTH_N 					0
+		#define     XB8_HDCP_STATUS_AUTH_Y 		 			1
+		#define     XB8_HDCP_STATUS_ENC 					6:6
+		#define     XB8_HDCP_STATUS_ENC_N 				    0
+		#define     XB8_HDCP_STATUS_ENC_Y 				    1
+		#define     XB8_HDCP_STATUS_MODE 			 		5:5
+		#define     XB8_HDCP_STATUS_MODE_DVI 			    0
+		#define     XB8_HDCP_STATUS_MODE_HDMI 		        1
+		#define     XB8_HDCP_STATUS_IDLE 	 				4:4
+		#define     XB8_HDCP_STATUS_IDLE_N 	 			    0
+		#define     XB8_HDCP_STATUS_IDLE_Y 	 			    1
+		#define 		XB8_HDCP_STATUS_ADV_CIPHER		    3:3
+		#define 		XB8_HDCP_STATUS_ADV_CIPHER_N		0
+		#define 		XB8_HDCP_STATUS_ADV_CIPHER_Y		1				
+//        #define     ADV_CIPHERI_STATUS                  0x08    //          R                                       0b  Advanced cipher status
+//        #define     HDCP_IDLE                           0x10    //          R                                       0b  HDCP state machine status
+//        #define     HDMI_STATUS                         0x20    //          R                                       0b  HDMI/DVI status
+//        #define     ENC                                 0x40    //          R                                       0b  Encryption status
+//        #define     AUTH                                0x80    //          R                                       0b  HDCP authentication status
+//  #define     SHA_DISP0               185     //  RO  00h     SHA1 value
+//  #define     SHA_DISP1               186     //  RO  00h
+//  #define     SHA_DISP2               187     //  RO  00h
+//  #define     SHA_DISP3               188     //  RO  00h
+//  #define     SHA_DISP4               189     //  RO  00h
+#define     XB9_SHA0								0XB9
+#define     XBA_SHA1								0XBA
+#define     XBB_SHA2								0XBB
+#define     XBC_SHA3								0XBC
+#define     XBD_SHA4								0XBD
+//		#define     XBE_BCAPS								0XBE
+
+
+
+#define     XBE_BCAPS               190     //  RO  00h     BCAPS value
+#define     XBF_KSV7_0              191     //  RO  00h     KSV[7:0] - AKSV/BKSV monitor registers
+#define     XC0_KSV15_8             192     //  RO  00h     KSV[15:8] - AKSV/BKSV monitor registers
+#define     XC1_KSV23_16            193     //  RO  00h     KSV[23:16] - AKSV/BKSV monitor registers
+#define     XC2_KSV31_24            194     //  RO  00h     KSV[31:24] - AKSV/BKSV monitor registers
+#define     XC3_KSV39_32            195     //  RO  00h     KSV[39:32] - AKSV/BKSV monitor registers
+#define     XC4_SEG_PTR             196     //  RW  00h     EDID segment pointer
+#define     XC5_EDID_WD_ADDR        197     //  RW  00h     EDID word address
+#define     XC6_GEN_PB26            198     //  RW  00h     Generic control packet (PB26)
+#define     XC7_NUM_DEV							0XC7
+
+//  #define     NUM_DEV                 199     //  RO  00h     HDCP BKSV Size
+#define     XC8_HDCP_ERR            200     //  RO  00h     HDCP error
+#define     BAD_BKSV                            0x01    //          R/W                                     0b  BKSV does not contain 20 0's and 20 1's
+#define     XC9_TIMER               201     //  RW  46h     Timer value for 100ms
+#define     XCA_TIMER               202     //  RW  2ch     Timer value for 5sec
+#define     XCB_READ_RI_CNT         203     //  RW  12h     Ri read count
+#define     XCC_AN_SEED             204     //  RW  00h     An Seed
+#define     XCD_MAX_REC_NUM         205     //  RW  16d     maximum number of receivers allowed
+#define     XCE_HDCP_MEM_CNTL1        0XCE
+#define     XCE_HDCP_MEM_CNTL1_SHORT   7:7
+#define     XCE_HDCP_MEM_CNTL1_W4_DATA 6:0
+
+
+//  #define     //RESERVED              206     //      RO      00h
+#define     XCF_HDCP_MEM_CTRL2             207             //  RW                                          0Oh     [1:0] ID_FAX_KEY, ID_HDCP_KEY
+	#define     XCF_HDCP_MEM_CTRL2_LD_HDCP   1:1
+	#define     XCF_HDCP_MEM_CTRL2_LD_FAX    0:0
+
+//        #define     LD_HDCP_KEY                         0x01    //          R/W                                     0b  Trigger for loading HDCP key from external memory
+//        #define     LD_FAX_KEY                          0x02    //          R/W                                     0b  Trigger for loading fax HDCP key
+#define     XD0_HDCP_CTRL2                  208             //  R/W                                         08h     HDCP Control 2
+#define     XD0_HDCP_CTRL2_DIS_127_CHK      7:7
+#define     XD0_HDCP_CTRL2_BKSV_CHK					6:6
+#define     XD0_HDCP_CTRL2_EN_PJ_CALC				5:5
+#define     XD0_HDCP_CTRL2_DIS_0LEN_HASH		4:4
+#define     XD0_HDCP_CTRL2_DELAY_RI_CHK 		3:3
+#define     XD0_HDCP_CTRL2_USE_PRESENT_AN		2:2
+#define     XD0_HDCP_CTRL2_SEL_PRESENT_AN		1:0
+
+
+//        #define     DELAY_RI_CHK                        0x08    //          R/W                                     0b  Set this bit to compare Ri at 129th frame instead of 128th frame for slower receivers.
+//        #define     DIS_0LEN_HASH                       0x10    //          R/W                                     0b  Some early repeaters may not load Hash value if number of devices is 0. Set this bit to skip Hash comparison when number of devices in Bstatus equals 0.
+//        #define     EN_PJ_CALC                          0x20    //          R/W                                     0b  Even though this bit is set, Pj calculation is enabled only if adv_cipher mode is selected.
+//        #define     DIS_127_CHK                         0x80    //          R/W                                     0b  This bit must be set to disable 127th Ri check if Ri check frequency is altered by ri_frame_cnt (B2h).
+//  #define     //RESERVED              209     //      RO      00h
+#define     XD2_HDCP_KEY_CTRL               210             //  R/W                                         00h     HDCP KEY memory control
+#define     XD2_HDCP_KEY_CTRL_USE_KSV1   		6:6
+#define     XD2_HDCP_KEY_CTRL_USE_KSV2			5:5
+#define     XD2_HDCP_KEY_CTRL_LOAD_AKSV			4:4
+#define     XD2_HDCP_KEY_CTRL_KSV_SEL			3:3
+#define     XD2_HDCP_KEY_CTRL_KSV_VALID			2:2
+#define     XD2_HDCP_KEY_CTRL_KEY_VALID			1:1
+#define     XD2_HDCP_KEY_CTRL_KEY_READY			0:0
+//				#define     KEY_READY                           0x01    //          R                                       0b  This bit shows that HDCP key load has finished.
+//        #define     KEY_VALID                           0x02    //          R                                       0b  This bit shows whether HDCP key loaded from HDCP memory is valid.
+//        #define     KSV_VALID                           0x04    //          R                                       0b  This bit shows whether the loaded KSV is valid (has 20 1�fs and 0�fs).
+//        #define     KSV_SEL                             0x08    //          R                                       0b  This bit shows which KSV was actually loaded into memory from HDCP memory.
+//        #define     LOAD_AKSV                           0x10    //          R/W                                     0b  Select which KSV to be loaded into AKSV/BKSV register (BFh~C3h). Write 1 to load AKSV.
+//        #define     USE_KSV2                            0x20    //          R/W                                     0b  If this bit is set, load the 2nd KSV written in the HDCP memory. If both usv_ksv1 and use_ksv2 are 0, hardware loads whichever that has 20 1�fs and 0�fs.
+//        #define     USE_KSV1                            0x40    //          R/W                                     0b  If this bit is set, load the 1st KSV written in the HDCP memory.
+#define     XD3_CSC_CONFIG1       			  211     //  RW  81h     CSC/Video Config.1
+#define     XD3_CSC_CONFIG1_MODE					7:7
+#define     XD3_CSC_CONFIG1_MODE_MANU			    0
+#define     XD3_CSC_CONFIG1_MODE_AUTO			    1
+#define     XD3_CSC_CONFIG1_COEF					6:3
+#define     XD3_CSC_CONFIG1_COEF_SDTV_LIM		    8
+#define     XD3_CSC_CONFIG1_COEF_SDTV_FUL		    4
+#define     XD3_CSC_CONFIG1_COEF_HDTV				2
+#define     XD3_CSC_CONFIG1_COEF_HDTV_50HZ	        1
+#define     XD3_CSC_CONFIG1_CSC						2:2
+#define     XD3_CSC_CONFIG1_CSC_OFF					0
+#define     XD3_CSC_CONFIG1_CSC_ON					1
+#define     XD3_CSC_CONFIG1_VID_ID				    1:1
+#define     XD3_CSC_CONFIG1_VID_ID_5_19			    0
+#define     XD3_CSC_CONFIG1_VID_ID_28_29		    1
+#define     XD3_CSC_CONFIG1_SWAP_BR					0:0
+#define     XD3_CSC_CONFIG1_SWAP_BR_DONE		    0
+#define     XD3_CSC_CONFIG1_SWAP_BR_NOT			    1
+
+
+
+#define     XD4_VIDEO3              212     //  RW  00h     Video setting 3
+//  #define     RI                      213     //  RO  00h     Ri
+//                                      214     //  RO  00h     Pj
+//  #define     PJ                      215     //  Dir.    Reset       Descriptions
+//  #define     SHA_RD                  216     //  RW  00h     SHA index for read
+
+#define     XD5_RI_N7_0							0XD5
+#define     XD6_RI_N15_8						0XD6
+#define     XD7_PJ								0XD7
+#define     XD8_SHA_RD							0XD8
+
+#define     XD9_GEN_PB27            217     //  RW  00h     Generic InfoFrame PB27
+//  #define     MPEG_B0                 218     //  RW  00h     MPEG source InfoFrame
+//  #define     MPEG_B1                 219     //  RW  00h
+//  #define     MPEG_B2                 220     //  RW  00h
+//  #define     MPEG_B3                 221     //  RW  00h
+//  #define     MPEG_FR_MF              222     //  RW  00h
+#define     XDA_RI_N15_8_SAV				    0XDA
+#define     XDB_PJ_SAV							0XDB
+#define     XDC_NUM_DEVICE					    0XDC
+
+
+#define     XDF_HPG_STATUS                  223             //  R                                           00h     Hot plug/MSENS status
+		#define     XDF_HPG_STATUS_HPG_PRT					7:7
+		#define     XDF_HPG_STATUS_HPG_PRT_L				 0
+		#define     XDF_HPG_STATUS_HPG_PRT_H				 1
+		#define     XDF_HPG_STATUS_MSENS_PRT				6:6
+		#define     XDF_HPG_STATUS_MSENS_PRT_L			     0
+		#define     XDF_HPG_STATUS_MSENS_PRT_H			     1
+		#define     XDF_HPG_STATUS_BIST						1:0
+		#define     XDF_HPG_STATUS_BIST_PASS				 2
+		#define     XDF_HPG_STATUS_BIST_FAIL		         1
+
+//        #define     BIST_FAIL                           0x01    //          R                                       0b  Dual port RAM BIST result fail
+//        #define     BIST_PASS                           0x02    //          R                                       0b  Dual port RAM BIST result passed
+//        #define     MSENS_PRT                           0x40    //          R                                       0b  MSENS input port status
+//        #define     HPG_PRT                             0x80    //          R                                       0b  Hot plug input port status
+#define     XE0_GAMUT_HB1           224     //  RW  00h     gamut metadata HB1
+#define     XE1_GAMUT_HB2           225     //  RW  00h     gamut metadata HB2
+//  #define     GAMUT_PB0               226     //  RW  00h     gamut metadata PB0
+//  #define     GAMUT_PB1               227     //  RW  00h     gamut metadata PB1
+//  #define     GAMUT_PB2               228     //  RW  00h     gamut metadata PB2
+//  #define     GAMUT_PB3               229     //  RW  00h     gamut metadata PB3
+//  #define     GAMUT_PB4               230     //  RW  00h     gamut metadata PB4
+//  #define     GAMUT_PB5               231     //  RW  00h     gamut metadata PB5
+#define     XE3_BKSV_N7_0						0XE3
+#define     XE4_BKSV_N15_8					    0XE4
+#define     XE5_BKSV_N23_16					    0XE5
+#define     XE6_BKSV_N31_24					    0XE6
+#define     XE7_BKSV_N39_32					    0XE7
+//		#define     XE8_AN_N7_0							0XE8
+
+
+#define     XE8_AN0                 232     //  RW  00h     An[7:0]
+#define     XE9_AN1									0XE9
+#define     XEA_AN2							 		0XEA
+#define     XEB_AN3									0XEB
+#define     XEC_AN4									0XEC 
+#define     XED_AN5									0XED 
+#define     XEE_AN6									0XEE 
+#define     XEF_AN7									0XEF
+
+#define     XF0_PROD_ID							    0XF0
+#define     XF1_REVS_ID							    0XF1
+#define     XF3_START_BLK1_LSB			            0XF3
+#define     XF4_START_BLK1_MSB			            0XF4
+#define     XF5_DURA_BLK1						    0XF5
+#define     XF6_DURA_BLK2_LSB				        0XF6
+#define     XF7_DURA_BLK2_MSB			        	0XF7
+#define     XF8_DURA_BLK2						    0XF8
+#define     XF9_START_BLK3_LSB			            0XF9
+#define     XFA_START_BLK3_MSB			            0XFA
+#define     XFB_DURA_BLK3					    	0XFB
+#define     XFC_VID_INPUT					    	0XFC
+	#define     XFC_VID_INPUT_HSYNC					1:1
+	#define     XFC_VID_INPUT_HSYNC_ADJ_Y		    0
+	#define     XFC_VID_INPUT_HSYNC_ADJ_N	    	1
+	#define     XFC_VID_INPUT_VSYNC					0:0
+	#define     XFC_VID_INPUT_VSYNC_ADJ_Y		    0
+	#define     XFC_VID_INPUT_VSYNC_ADJ_N		    1
+#define     XFD_RDAT_OUTPUT						    0XFD
+#define     XFE_TEST								0XFE
+#define     XFE_TEST_FBCK							7:7
+#define     XFE_TEST_FBCK_DIS					    0
+#define     XFE_TEST_FBCK_EN				    	1
+#define     XFE_TEST_FBCK20					    	5:5
+#define     XFE_TEST_FBCK20_DIS				        0
+#define     XFE_TEST_FBCK20_EN				        1
+#define     XFE_TEST_FBCK10						    4:4
+#define     XFE_TEST_FBCK10_DIS				        0
+#define     XFE_TEST_FBCK10_EN				        1
+#define     XFE_TEST_BIST_FLAG				        3:3
+#define     XFE_TEST_BIST_FLAG_END		            0
+#define     XFE_TEST_BIST_FLAG_WORK		            1
+#define     XFE_TEST_PHY_ONLY				    	2:2
+#define     XFE_TEST_PHY_ONLY_DIS		        	0
+#define     XFE_TEST_PHY_ONLY_EN			        1
+#define     XFE_TEST_AUTO_LB				    	1:1
+#define     XFE_TEST_AUTO_LB_MANUAL			        0
+#define     XFE_TEST_AUTO_LB_RANDOM			        1
+#define     XFE_TEST_LB 							0:0
+#define     XFE_TEST_LB_DIS 						0
+#define     XFE_TEST_LB_EN 							1
+
+//  #define     GAMUT_PB7               233     //  RW  00h     gamut metadata PB7
+//  #define     GAMUT_PB8               234     //  RW  00h     gamut metadata PB8
+//  #define     GAMUT_PB9               235     //  RW  00h     gamut metadata PB9
+//  #define     GAMUT_PB10              236     //  RW  00h     gamut metadata PB10
+//  #define     GAMUT_PB11              237     //  RW  00h     gamut metadata PB11
+//  #define     GAMUT_PB12              238     //  RW  00h     gamut metadata PB12
+//  #define     GAMUT_PB13              239     //  RW  00h     gamut metadata PB13
+//  #define     GAMUT_PB14              240     //  RW  00h     gamut metadata PB14
+//  #define     GAMUT_PB15              241     //  RW  00h     gamut metadata PB15
+//  #define     GAMUT_PB16              242     //  RW  00h     gamut metadata PB16
+//  #define     GAMUT_PB17              243     //  RW  00h     gamut metadata PB17
+//  #define     GAMUT_PB18              244     //  RW  00h     gamut metadata PB18
+//  #define     GAMUT_PB19              245     //  RW  00h     gamut metadata PB19
+//  #define     GAMUT_PB20              246     //  RW  00h     gamut metadata PB20
+//  #define     GAMUT_PB21              247     //  RW  00h     gamut metadata PB21
+//  #define     GAMUT_PB22              248     //  RW  00h     gamut metadata PB22
+//  #define     GAMUT_PB23              249     //  RW  00h     gamut metadata PB23
+//  #define     GAMUT_PB24              250     //  RW  00h     gamut metadata PB24
+//  #define     GAMUT_PB25              251     //  RW  00h     gamut metadata PB25
+//  #define     GAMUT_PB26              252     //  RW  00h     gamut metadata PB26
+//  #define     GAMUT_PB27              253     //  RW  00h     gamut metadata PB27
+//  #define     TEST_MODE               254     //  RW  00h     test mode register
+//    #define     XFF_IP_COM_CONTROL              255             //  R/W                                         40h     I/P conversion control
+//        #define     IP_CONV_PIX_REP                     0x01    //          R/W                                     0b  I/P conversion control
+//        #define     IP_CONV_EN                          0x02    //          R/W                                     0b  I/P conversion mode control
+//        #define     PRE_COLOR_CONV_ON                   0x10    //          R/W                                     0b  Pre-color space converter (RGB->YCbCr) control
+//        #define     PRE_DOWN_CONV_ON                    0x20    //          R/W                                     0b  Pre-pixel encoding converter (down sampler) control
+//        #define     STGAM_OFF                           0x40    //          R/W                                     1b  Gamma correction control
+//        #define     IP_REG_OFFSET                       0x80    //          R/W                                     0b  I/P conversion control register access control
+
+
+#endif  /* _HDMIREGS_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/l3.c b/drivers/gpu/drm/smifb2/ddk768/l3.c
new file mode 100644
index 000000000000..e68c371ce307
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/l3.c
@@ -0,0 +1,65 @@
+
+#include "l3.h"
+
+/*
+ * Send one byte of data to the chip.  Data is latched into the chip on
+ * the rising edge of the clock.
+ */
+static void sendbyte(struct l3_pins *adap, unsigned int byte)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		adap->setclk(0);
+		sb_OS_WAIT_USEC_POLL(adap->data_hold);
+		adap->setdat(byte & 1);
+		sb_OS_WAIT_USEC_POLL(adap->data_setup);
+		adap->setclk(1);
+		sb_OS_WAIT_USEC_POLL(adap->clock_high);
+		byte >>= 1;
+	}
+}
+
+/*
+ * Send a set of bytes to the chip.  We need to pulse the MODE line
+ * between each byte, but never at the start nor at the end of the
+ * transfer.
+ */
+static void sendbytes(struct l3_pins *adap, const u8 *buf,
+		      int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (i) {
+			sb_OS_WAIT_USEC_POLL(adap->mode_hold);
+			adap->setmode(0);
+			sb_OS_WAIT_USEC_POLL(adap->mode);
+		}
+		adap->setmode(1);
+		sb_OS_WAIT_USEC_POLL(adap->mode_setup);
+		sendbyte(adap, buf[i]);
+	}
+}
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
+{
+	adap->setclk(1);
+	adap->setdat(1);
+	adap->setmode(1);
+	sb_OS_WAIT_USEC_POLL(adap->mode);
+
+	adap->setmode(0);
+	sb_OS_WAIT_USEC_POLL(adap->mode_setup);
+	sendbyte(adap, addr);
+	sb_OS_WAIT_USEC_POLL(adap->mode_hold);
+
+	sendbytes(adap, data, len);
+
+	adap->setclk(1);
+	adap->setdat(1);
+	adap->setmode(0);
+
+	return len;
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/l3.h b/drivers/gpu/drm/smifb2/ddk768/l3.h
new file mode 100644
index 000000000000..227d9753c4a5
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/l3.h
@@ -0,0 +1,22 @@
+#ifndef _L3_H_
+#define _L3_H_ 
+
+#include <linux/string.h>
+#include "ddk768_timer.h"
+
+
+struct l3_pins {
+	void (*setdat)(int);
+	void (*setclk)(int);
+	void (*setmode)(int);
+	int data_hold;
+	int data_setup;
+	int clock_high;
+	int mode_hold;
+	int mode;
+	int mode_setup;
+};
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len);
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/ddk768/uda1345.c b/drivers/gpu/drm/smifb2/ddk768/uda1345.c
new file mode 100644
index 000000000000..16ca7bbd32e8
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/uda1345.c
@@ -0,0 +1,368 @@
+#include <linux/string.h>
+#include "ddk768_reg.h"
+#include "ddk768_help.h"
+#include "uda1345.h"
+
+static void setdat(int v);
+static void setclk(int v);
+static void setmode(int v);
+
+static const u8 uda1346_reg[UDA1345_REGS_NUM] =
+{
+    /* Status, data regs */
+    0x00, 0x00, 0x80, 0xc1,
+};
+
+static u8 cache[sizeof(uda1346_reg)];
+
+static struct uda1345_data falcon_uda1345 =
+{
+    .l3 = {
+        .setdat = setdat,
+        .setclk = setclk,
+        .setmode = setmode,
+        .data_hold = 1,
+        .data_setup = 1,
+        .clock_high = 1,
+        .mode_hold = 1,
+        .mode = 1,
+        .mode_setup = 1,
+    },
+    .reg_cache_default = (void*)uda1346_reg,
+    .cache_init = 0,
+};
+
+static void setdat(int v)
+{
+    unsigned long value;
+
+    value = peekRegisterDWord(GPIO_DATA);
+    pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_DATA_SHIFT)) : \
+                      (value & ~(1 << GPIO_DATA_GPIO_CODEC_DATA_SHIFT)));
+
+}
+
+static void setclk(int v)
+{
+    unsigned long value;
+
+		value = peekRegisterDWord(GPIO_DATA);
+		pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_CLK_SHIFT)) : \
+						  (value & ~(1 << GPIO_DATA_GPIO_CODEC_CLK_SHIFT)));
+
+
+}
+
+static void setmode(int v)
+{
+    unsigned long value;
+
+		value = peekRegisterDWord(GPIO_DATA);
+		pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_MODE_SHIFT)) : \
+						  (value & ~(1 << GPIO_DATA_GPIO_CODEC_MODE_SHIFT)));
+
+}
+
+static void uda1345_GPIOInit(void)
+{
+    unsigned long value;
+   		 /*l3 mode control pins*/
+
+		value = peekRegisterDWord(GPIO_MUX);
+		value &= ~(1 << GPIO_MUX_GPIO_CODEC_MODE_SHIFT);
+		value &= ~(1 << GPIO_MUX_GPIO_CODEC_CLK_SHIFT);
+		value &= ~(1 << GPIO_MUX_GPIO_CODEC_DATA_SHIFT);
+		pokeRegisterDWord(GPIO_MUX, value);
+
+		/*set 3 pins as input*/
+		value = peekRegisterDWord(GPIO_DATA_DIRECTION);
+		value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_MODE_SHIFT);
+		value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_CLK_SHIFT);
+		value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_DATA_SHIFT);
+		pokeRegisterDWord(GPIO_DATA_DIRECTION, value);
+
+
+}
+
+static inline unsigned int uda1345_read_reg_cache(struct uda1345_data *codec,
+        unsigned int reg)
+{
+    u8 *cache = (u8 *)codec->reg_cache;
+
+    if (reg >= UDA1345_REGS_NUM)
+        return -1;
+	
+    return cache[reg];
+}
+
+/*
+ * Write the register cache
+ */
+static inline int uda1345_write_reg_cache(struct uda1345_data *codec,
+        u8 reg, unsigned int value)
+{
+    u8 *cache = (u8 *)codec->reg_cache;
+
+    if (reg >= UDA1345_REGS_NUM)
+        return -1;
+    cache[reg] = value;
+    return 0;
+}
+
+
+/*
+ * Write to the uda134x registers
+ *
+ */
+static int uda1345_write(unsigned int reg,
+                         unsigned int value)
+{
+    int ret;
+    u8 addr;
+    u8 data = value;
+
+    if (reg >= UDA1345_REGS_NUM)
+    {
+
+        return -1;
+    }
+
+    uda1345_write_reg_cache(&falcon_uda1345, reg, value);
+
+    switch (reg)
+    {
+    case UDA1345_STATUS:
+        addr = UDA1345_STATUS_ADDR;
+        break;
+    case UDA1345_DATA_VOLUME:
+    case UDA1345_DATA_DE_MUTE:
+    case UDA1345_DATA_POWER:
+        addr = UDA1345_DATA_ADDR;
+        break;
+    default:
+        break;
+    }
+
+    ret = l3_write(&falcon_uda1345.l3,
+                   addr, &data, 1);
+   
+   if (ret != 1)
+        return -1;
+
+    return 0;
+}
+
+int uda1345_setsysclkfs(enum uda1345_sysclkf sysclk)
+{
+    u8 data;
+	
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS);
+	
+    data &= ~UDA1345_SYSCLKF_MASK;
+    switch(sysclk)
+    {
+    case SYSCLKF_512FS:
+        data |= UDA1345_SYSCLKF_512FS;
+        break;
+    case SYSCLKF_384FS:
+        data |= UDA1345_SYSCLKF_384FS;
+        break;
+    case SYSCLKF_256FS:
+        data |= UDA1345_SYSCLKF_256FS;
+        break;
+    default:
+        return -1;
+    }
+	
+    return uda1345_write(UDA1345_STATUS,data);
+
+}
+
+int uda1345_setformat(enum uda1345_input_format informat)
+{
+
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS);
+    data &= ~UDA1345_FORMAT_MASK;
+    switch(informat)
+    {
+    case I2S_BUS:
+        data |= UDA1345_I2S_BUS;
+        break;
+    case LSB_16BITS:
+        data |= UDA1345_LSB_16BITS;
+        break;
+    case LSB_18BITS:
+        data |= UDA1345_LSB_18BITS;
+        break;
+    case	LSB_20BITS:
+        data |= UDA1345_LSB_20BITS;
+        break;
+    case	MSB_JUSTIFIED:
+        data |= UDA1345_MSB_JUSTIFIED;
+        break;
+    case	MSB_OUTPUT_LSB_16BITS_INPUT:
+        data |= UDA1345_MSB_OUTPUT_LSB_16BITS_INPUT;
+        break;
+    case	MSB_OUTPUT_LSB_18BITS_INPUT:
+        data |= UDA1345_MSB_OUTPUT_LSB_18BITS_INPUT;
+        break;
+    case	MSB_OUTPUT_LSB_20BITS_INPUT:
+        data |= UDA1345_MSB_OUTPUT_LSB_20BITS_INPUT;
+        break;
+    default:
+        return -1;
+    }
+    return  uda1345_write(UDA1345_STATUS,data);
+
+}
+
+
+int uda1345_setdcfilter(enum uda1345_dc_filter onoff)
+{
+
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS);
+    data &= ~UDA1345_DC_MASK;
+    switch(onoff)
+    {
+    case NO_DC_FILTERING:
+        data |= UDA1345_NO_DC_FILTERING;
+        break;
+    case DC_FILTERING:
+        data |= UDA1345_DC_FILTERING;
+        break;
+    default:
+        return -1;
+    }
+    return  uda1345_write(UDA1345_STATUS,data);
+
+}
+
+
+int uda1345_setvolume(u8 dB)
+{
+
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_VOLUME);
+    data &= ~UDA1345_VOLUME_MASK;
+    data |= (dB&UDA1345_VOLUME_MASK);
+    return  uda1345_write(UDA1345_DATA_VOLUME,data);
+
+}
+
+
+int uda1345_setdemphasis(enum uda1345_de_emphasis emphasis)
+{
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_DE_MUTE);
+    data &= ~UDA1345_DE_EMPHASIS_MASK;
+    switch(emphasis)
+    {
+    case NO_DE_EMPHASIS:
+        data |= UDA1345_NO_DE_EMPHASIS;
+        break;
+    case DE_EMPHASIS_32KHZ:
+        data |= UDA1345_DE_EMPHASIS_32KHZ;
+        break;
+    case DE_EMPHASIS_44KHZ:
+        data |= UDA1345_DE_EMPHASIS_44KHZ;
+        break;
+    case DE_EMPHASIS_48KHZ:
+        data |= UDA1345_DE_EMPHASIS_48KHZ;
+        break;
+    default:
+
+        return -1;
+    }
+    return uda1345_write(UDA1345_DATA_DE_MUTE,data);
+
+}
+
+int uda1345_setmute(enum uda1345_mute onoff)
+{
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_DE_MUTE);
+    data &= ~UDA1345_MUTE_MASK;
+    switch(onoff)
+    {
+    case NO_MUTE:
+        data |= UDA1345_NO_MUTE;
+        break;
+    case MUTE:
+        data |= UDA1345_MUTE;
+        break;
+    default:
+        return -1;
+    }
+    return  uda1345_write(UDA1345_DATA_DE_MUTE,data);
+
+}
+
+int uda1345_setpower(enum uda1345_power onoff)
+{
+    u8 data;
+    data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_POWER);
+    data &= ~UDA1345_ADC_DAC_MASK;
+    switch(onoff)
+    {
+    case ADCOFF_DACOFF:
+        data |= UDA1345_ADCOFF_DACOFF;
+        break;
+    case ADCOFF_DACON:
+        data |= UDA1345_ADCOFF_DACON;
+        break;
+    case ADCON_DACOFF:
+        data |= UDA1345_ADCON_DACOFF;
+        break;
+    case ADCON_DACON:
+        data |= UDA1345_ADCON_DACON;
+        break;
+    default:
+        return -1;
+    }
+    return  uda1345_write(UDA1345_DATA_POWER,data);
+
+}
+
+int uda1345_init(void)
+{
+    uda1345_GPIOInit();    
+
+    if(0 ==  falcon_uda1345.cache_init)
+    {
+        falcon_uda1345.cache_size = sizeof(uda1346_reg);
+        falcon_uda1345.reg_cache = cache;
+        memcpy(falcon_uda1345.reg_cache, falcon_uda1345.reg_cache_default,falcon_uda1345.cache_size );
+        falcon_uda1345.cache_init = 1;
+    }
+
+    if(uda1345_setsysclkfs(SYSCLKF_384FS))
+        return -1;
+    if(uda1345_setformat(I2S_BUS))
+        return -1;
+    if(uda1345_setdcfilter(NO_DC_FILTERING))
+        return -1;
+    if(uda1345_setdemphasis(NO_DE_EMPHASIS))
+        return -1;
+    if(uda1345_setvolume(0))
+        return -1;
+    if(uda1345_setmute(MUTE))
+        return -1;
+    if(uda1345_setpower(ADCOFF_DACOFF))
+        return -1;
+
+    return 0;
+}
+
+int uda1345_deinit(void)
+{
+    uda1345_setpower(ADCOFF_DACOFF);
+    if(falcon_uda1345.cache_init&&falcon_uda1345.reg_cache)
+    {
+        falcon_uda1345.reg_cache = NULL;
+        falcon_uda1345.cache_init =  0;
+    }
+    return 0;
+}
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/uda1345.h b/drivers/gpu/drm/smifb2/ddk768/uda1345.h
new file mode 100644
index 000000000000..926b2c72f2a6
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/uda1345.h
@@ -0,0 +1,131 @@
+#ifndef _UDA1345_CODEC_H
+#define _UDA1345_CODEC_H
+#include "l3.h"
+
+
+#define UDA1345_L3ADDR	5
+#define UDA1345_DATA_ADDR	((UDA1345_L3ADDR << 2) | 0)
+#define UDA1345_STATUS_ADDR	((UDA1345_L3ADDR << 2) | 2)
+
+
+/* UDA1345 registers */
+#define UDA1345_STATUS 0
+#define UDA1345_DATA_VOLUME 1
+#define UDA1345_DATA_DE_MUTE 2
+#define UDA1345_DATA_POWER 3
+
+#define UDA1345_REGS_NUM 4
+
+/*UDA1345 System clock frequency*/
+#define UDA1345_SYSCLKF_MASK (3 << 4)
+#define UDA1345_SYSCLKF_512FS  (0 << 4)
+#define UDA1345_SYSCLKF_384FS  (1 << 4)
+#define UDA1345_SYSCLKF_256FS  (2 << 4)
+enum uda1345_sysclkf
+{
+    SYSCLKF_512FS = 0,
+    SYSCLKF_384FS,
+    SYSCLKF_256FS,
+};
+
+/*UDA1345 data input format*/
+#define UDA1345_FORMAT_MASK (7 << 1)
+#define  UDA1345_I2S_BUS (0 << 1)
+#define  UDA1345_LSB_16BITS (1 << 1)
+#define  UDA1345_LSB_18BITS (2 << 1)
+#define  UDA1345_LSB_20BITS (3 << 1)
+#define  UDA1345_MSB_JUSTIFIED (4 << 1)
+#define  UDA1345_MSB_OUTPUT_LSB_16BITS_INPUT (5 << 1)
+#define  UDA1345_MSB_OUTPUT_LSB_18BITS_INPUT (6 << 1)
+#define  UDA1345_MSB_OUTPUT_LSB_20BITS_INPUT (7 << 1)
+enum uda1345_input_format
+{
+    I2S_BUS = 0,
+    LSB_16BITS,
+    LSB_18BITS,
+    LSB_20BITS,
+    MSB_JUSTIFIED,
+    MSB_OUTPUT_LSB_16BITS_INPUT,
+    MSB_OUTPUT_LSB_18BITS_INPUT,
+    MSB_OUTPUT_LSB_20BITS_INPUT,
+};
+
+/*UDA1345 dc filter*/
+#define UDA1345_DC_MASK 1
+#define UDA1345_DC_FILTERING 1
+#define UDA1345_NO_DC_FILTERING 0
+enum uda1345_dc_filter
+{
+    NO_DC_FILTERING = 0,
+    DC_FILTERING,
+};
+
+/*UDA1345 volume*/
+#define UDA1345_VOLUME_MASK 0x3f
+#define UDA1345_VOLUME_N5DB 6
+#define UDA1345_VOLUME_N10DB 0xB
+
+/*UDA1345 DE-EMPHASIS*/
+#define UDA1345_DE_EMPHASIS_MASK (3 << 3)
+#define UDA1345_NO_DE_EMPHASIS (0 << 3)
+#define UDA1345_DE_EMPHASIS_32KHZ (1 << 3)
+#define UDA1345_DE_EMPHASIS_44KHZ (2 << 3)
+#define UDA1345_DE_EMPHASIS_48KHZ (3 << 3)
+enum uda1345_de_emphasis
+{
+    NO_DE_EMPHASIS = 0,
+    DE_EMPHASIS_32KHZ,
+    DE_EMPHASIS_44KHZ,
+    DE_EMPHASIS_48KHZ,
+};
+
+/*UDA1345 mute*/
+#define UDA1345_MUTE_MASK (1 << 2)
+#define UDA1345_NO_MUTE (0 << 2)
+#define UDA1345_MUTE (1 << 2)
+enum uda1345_mute
+{
+    NO_MUTE = 0,
+    MUTE,
+};
+
+/*UDA1345 power control*/
+#define UDA1345_ADC_DAC_MASK 3
+#define UDA1345_ADCOFF_DACOFF 0
+#define UDA1345_ADCOFF_DACON 1
+#define UDA1345_ADCON_DACOFF 2
+#define UDA1345_ADCON_DACON 3
+enum uda1345_power
+{
+    ADCOFF_DACOFF = 0,
+    ADCOFF_DACON,
+    ADCON_DACOFF,
+    ADCON_DACON,
+};
+
+
+struct uda1345_data
+{
+    struct l3_pins l3;
+    void * reg_cache_default;
+    void * reg_cache;
+    unsigned int cache_size;
+    unsigned int cache_init : 1;
+
+};
+
+
+
+
+
+int uda1345_setsysclkfs(enum uda1345_sysclkf sysclk);
+int uda1345_setformat(enum uda1345_input_format informat);
+int uda1345_setdcfilter(enum uda1345_dc_filter onoff);
+int uda1345_setvolume(u8 dB);
+int uda1345_setdemphasis(enum uda1345_de_emphasis emphasis);
+int uda1345_setmute(enum uda1345_mute onoff);
+int uda1345_setpower(enum uda1345_power onoff);
+int uda1345_init(void);
+int uda1345_deinit(void);
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/ddk768/vdif.h b/drivers/gpu/drm/smifb2/ddk768/vdif.h
new file mode 100644
index 000000000000..36d11d6daa54
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/vdif.h
@@ -0,0 +1,63 @@
+/*******************************************************************
+* 
+*         Copyright (c) 2009 by Silicon Motion, Inc. (SMI)
+* 
+*  All rights are reserved. Reproduction or in part is prohibited
+*  without the written consent of the copyright owner.
+* 
+*  vdif.h --- SMI DDK 
+*  This file contains the video display information format structure
+* 
+*******************************************************************/
+#ifndef _VDIF_H_
+#define _VDIF_H_
+
+/* Sync polarity */
+typedef enum _vdif_sync_polarity_t
+{
+    VDIF_SYNC_NEGATIVE = 0,
+    VDIF_SYNC_POSITIVE
+} vdif_sync_polarity_t; 
+
+/* Scan type */
+typedef enum _vdif_scan_type_t
+{
+    VDIF_NONINTERLACED = 0,
+    VDIF_INTERLACED
+} vdif_scan_type_t;
+
+/* Monitor Timing Information */
+typedef struct _video_display_information_format_t
+{
+    unsigned long pixelClock;
+    unsigned long characterWidth;
+    vdif_scan_type_t scanType; 
+    
+    unsigned long horizontalFrequency;
+    vdif_sync_polarity_t horizontalSyncPolarity;
+    unsigned long horizontalTotal;
+    unsigned long horizontalActive;
+    unsigned long horizontalBlankStart;
+    unsigned long horizontalBlankTime;
+    unsigned long horizontalSyncStart;
+    unsigned long horizontalRightBorder;
+    unsigned long horizontalFrontPorch;
+    unsigned long horizontalSyncWidth;
+    unsigned long horizontalBackPorch;
+    unsigned long horizontalLeftBorder;
+    
+    unsigned long verticalFrequency;
+    vdif_sync_polarity_t verticalSyncPolarity; 
+    unsigned long verticalTotal;
+    unsigned long verticalActive;
+    unsigned long verticalBlankStart;
+    unsigned long verticalBlankTime;
+    unsigned long verticalSyncStart;
+    unsigned long verticalBottomBorder;
+    unsigned long verticalFrontPorch;
+    unsigned long verticalSyncHeight;
+    unsigned long verticalBackPorch;
+    unsigned long verticalTopBorder;
+} vdif_t;
+
+#endif  /* _VDIF_H_ */
diff --git a/drivers/gpu/drm/smifb2/ddk768/wm8978.c b/drivers/gpu/drm/smifb2/ddk768/wm8978.c
new file mode 100644
index 000000000000..07e1a56b0970
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/wm8978.c
@@ -0,0 +1,231 @@
+
+#include <linux/string.h>
+#include "ddk768_reg.h"
+#include "ddk768_help.h"
+#include "ddk768_swi2c.h"
+#include "ddk768_hwi2c.h"
+#include "wm8978.h"
+
+static unsigned short WM8978_REGVAL[58]=
+{
+	0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000,
+	0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF,
+	0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000,
+	0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,
+	0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9,
+	0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100,
+	0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039,
+	0X0001,0X0001
+}; 
+
+unsigned char WM8978_Write_Reg(unsigned char reg, unsigned short val)
+{
+	unsigned char res;
+	unsigned char RegAddr;
+	unsigned char RegValue;
+	RegAddr = (reg<<1)|((unsigned char)((val>>8)&0x01));
+	RegValue = (unsigned char)val;
+	if(!hwi2c_en)
+		res = ddk768_swI2CWriteReg(WM8978_ADDR, RegAddr, RegValue);
+	else
+		res = ddk768_hwI2CWriteReg(0, WM8978_ADDR, RegAddr, RegValue);
+	
+	if(res == 0)
+		WM8978_REGVAL[reg]=val;
+	return res;
+}
+
+unsigned short WM8978_Read_Reg(unsigned char reg)
+{  
+	return WM8978_REGVAL[reg];	
+} 
+
+unsigned char WM8978_Init(void)
+{
+	unsigned char Res;
+
+	if(hwi2c_en)
+		ddk768_hwI2CInit(0);
+	else
+		ddk768_swI2CInit(30, 31);
+
+	
+	Res = WM8978_Write_Reg(0, 0);	//软复位WM8978
+	if(Res)
+		return 1;				     //发送指令失败,WM8978异常
+	/* Set volume to 0 can improve the noise when init codec */
+	WM8978_HPvol_Set(0, 0);   //耳机音量0-63（左和右分开设置）
+	WM8978_SPKvol_Set(0);      //喇叭音量0-63
+	WM8978_Write_Reg(1, 0x1B);  //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
+	WM8978_Write_Reg(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
+	WM8978_Write_Reg(3, 0x6C);  //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能	
+	WM8978_Write_Reg(6, 0);	    //R6,MCLK由外部提供
+	WM8978_Write_Reg(43, 1<<4);//R43,INVROUT2反向,驱动喇叭
+	WM8978_Write_Reg(47, 1<<8);//R47设置,PGABOOSTL,左通道MIC获得20倍增益
+	WM8978_Write_Reg(48, 1<<8);//R48设置,PGABOOSTR,右通道MIC获得20倍增益
+	WM8978_Write_Reg(49, 1<<1);//R49,TSDEN,开启过热保护 
+	WM8978_Write_Reg(10, 1<<3);//R10,SOFTMUTE关闭,128x采样,最佳SNR 
+	WM8978_Write_Reg(14, 1<<3);//R14,ADC 128x采样率
+	
+	/* Playback and record setup */
+
+	WM8978_I2S_Cfg(2, 0);	    //设置I2S接口模式，数据位数不需要设置，播放从设备不使用
+	WM8978_ADDA_Cfg(1, 1);	    //开启DAC和ADC
+	WM8978_Input_Cfg(1, 1, 1);  //开启Line in输入通道，MIC和AUX
+	WM8978_MIC_Gain(20);		//MIC增益设置,MIC录制时可开启
+	WM8978_Output_Cfg(1, 0);	//开启DAC输出，关闭BYPASS输出  
+
+	/* Make sure the IIC is idle when do this operation */
+	WM8978_HPvol_Set(50, 50);   
+	WM8978_SPKvol_Set(50);  
+    
+	return 0;
+}
+
+void WM8978_DeInit(void)
+{
+	if(hwi2c_en)
+		ddk768_hwI2CClose(0);
+	else
+		ddk768_swI2CInit(30, 31);
+
+	/* To Do: Here should be read device register not globle array.*/
+	WM8978_Write_Reg(0, 0);
+}
+
+//WM8978 DAC/ADC配置
+//adcen:adc使能(1)/关闭(0)
+//dacen:dac使能(1)/关闭(0)
+void WM8978_ADDA_Cfg(unsigned char dacen, unsigned char adcen)
+{
+	unsigned short regval;
+	regval = WM8978_Read_Reg(3);	//读取R3
+	if(dacen)
+		regval |= 3<<0;			//R3最低2个位设置为1,开启DACR&DACL
+	else 
+		regval &= ~(3<<0);			//R3最低2个位清零,关闭DACR&DACL.
+	WM8978_Write_Reg(3, regval);	//设置R3
+	regval = WM8978_Read_Reg(2);	//读取R2
+	if(adcen)
+		regval |= 3<<0;			//R2最低2个位设置为1,开启ADCR&ADCL
+	else 
+		regval &= ~(3<<0);			//R2最低2个位清零,关闭ADCR&ADCL.
+	WM8978_Write_Reg(2, regval);	//设置R2	
+}
+
+//WM8978 输入通道配置 
+//micen:MIC开启(1)/关闭(0)
+//lineinen:Line In开启(1)/关闭(0)
+//auxen:aux开启(1)/关闭(0) 
+void WM8978_Input_Cfg(unsigned char micen, unsigned char lineinen, unsigned char auxen)
+{
+	unsigned short regval;  
+	regval = WM8978_Read_Reg(2);  //读取R2
+	if(micen)
+		regval |= 3<<2;			 //开启INPPGAENR,INPPGAENL(MIC的PGA放大)
+	else 
+		regval &= ~(3<<2);			 //关闭INPPGAENR,INPPGAENL.
+ 	WM8978_Write_Reg(2, regval);	 //设置R2 
+	regval = WM8978_Read_Reg(44);//读取R44
+	if(micen)
+		regval |= 3<<4|3<<0;		//开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
+	else 
+		regval &= ~(3<<4|3<<0);	//关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.
+	WM8978_Write_Reg(44, regval);	//设置R44
+	if(lineinen)
+		WM8978_LINEIN_Gain(5);	//LINE IN 0dB增益
+	else 
+		WM8978_LINEIN_Gain(0);	//关闭LINE IN
+	if(auxen)
+		WM8978_AUX_Gain(7);//AUX 6dB增益
+	else 
+		WM8978_AUX_Gain(0);//关闭AUX输入  
+}
+
+//WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
+//gain:0~63,对应-12dB~35.25dB,0.75dB/Step
+void WM8978_MIC_Gain(unsigned char gain)
+{
+	gain &= 0x3F;
+	WM8978_Write_Reg(45, gain);		//R45,左通道PGA设置 
+	WM8978_Write_Reg(46, gain|1<<8);	//R46,右通道PGA设置
+}
+
+//WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益)
+//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
+void WM8978_LINEIN_Gain(unsigned char gain)
+{
+	unsigned short regval;
+	gain &= 0x07;
+	regval = WM8978_Read_Reg(47);		//读取R47
+	regval &= ~(7<<4);						//清除原来的设置 
+ 	WM8978_Write_Reg(47, regval|gain<<4);	//设置R47
+	regval = WM8978_Read_Reg(48);		//读取R48
+	regval &= ~(7<<4);						//清除原来的设置 
+ 	WM8978_Write_Reg(48,regval|gain<<4);	//设置R48
+} 
+
+//WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益)
+//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
+void WM8978_AUX_Gain(unsigned char gain)
+{
+	unsigned short regval;
+	gain &= 0x07;
+	regval = WM8978_Read_Reg(47);		//读取R47
+	regval &= ~(7<<0);						//清除原来的设置 
+ 	WM8978_Write_Reg(47, regval|gain<<0);	//设置R47
+	regval = WM8978_Read_Reg(48);		//读取R48
+	regval &= ~(7<<0);						//清除原来的设置 
+ 	WM8978_Write_Reg(48, regval|gain<<0);	//设置R48
+}  
+
+//WM8978 输出配置 
+//dacen:DAC输出(放音)开启(1)/关闭(0)
+//bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0)
+void WM8978_Output_Cfg(unsigned char dacen, unsigned char bpsen)
+{
+	unsigned short regval = 0;
+	if(dacen)
+		regval |= 1<<0; //DAC输出使能
+	if(bpsen)
+	{
+		regval |= 1<<1; //BYPASS使能
+		regval |= 5<<2; //0dB增益
+	} 
+	WM8978_Write_Reg(50,regval); //R50设置
+	WM8978_Write_Reg(51,regval); //R51设置 
+}
+
+//设置耳机左右声道音量
+//voll:左声道音量(0~63)
+//volr:右声道音量(0~63)
+void WM8978_HPvol_Set(unsigned char voll, unsigned char volr)
+{
+	voll &= 0x3F;
+	volr &= 0x3F;				//限定范围
+	if(voll == 0)voll |= 1<<6;	//音量为0时,直接mute
+	if(volr == 0)volr |= 1<<6;	//音量为0时,直接mute 
+	WM8978_Write_Reg(52, voll);	//R52,耳机左声道音量设置
+	WM8978_Write_Reg(53, volr|(1<<8)); //R53,耳机右声道音量设置,同步更新(HPVU=1)
+}
+
+//设置喇叭音量
+//voll:左声道音量(0~63)
+void WM8978_SPKvol_Set(unsigned char volx)
+{
+	volx &= 0x3F;//限定范围
+	if(volx == 0)volx |= 1<<6;		//音量为0时,直接mute 
+ 	WM8978_Write_Reg(54, volx);	//R54,喇叭左声道音量设置
+	WM8978_Write_Reg(55, volx|(1<<8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
+}
+
+//设置I2S工作模式
+//fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
+//len:0,16位;1,20位;2,24位;3,32位;
+void WM8978_I2S_Cfg(unsigned char fmt, unsigned char len)
+{
+	fmt &= 0x03;
+	len &= 0x03; //限定范围
+	WM8978_Write_Reg(4, (fmt<<3)|(len<<5)); //R4,WM8978工作模式设置	
+	
+}
diff --git a/drivers/gpu/drm/smifb2/ddk768/wm8978.h b/drivers/gpu/drm/smifb2/ddk768/wm8978.h
new file mode 100644
index 000000000000..0fb554297396
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/ddk768/wm8978.h
@@ -0,0 +1,23 @@
+#ifndef __WM8978_H
+#define __WM8978_H
+
+#define WM8978_ADDR	0x34
+
+unsigned char WM8978_Write_Reg(unsigned char reg, unsigned short val);
+unsigned short WM8978_Read_Reg(unsigned char reg);
+unsigned char WM8978_Init(void);
+void WM8978_DeInit(void);
+void WM8978_ADDA_Cfg(unsigned char dacen, unsigned char adcen);
+void WM8978_Output_Cfg(unsigned char dacen, unsigned char bpsen);
+void WM8978_HPvol_Set(unsigned char voll, unsigned char volr);
+void WM8978_SPKvol_Set(unsigned char volx);
+void WM8978_I2S_Cfg(unsigned char fmt, unsigned char len);
+void WM8978_Input_Cfg(unsigned char micen, unsigned char lineinen, unsigned char auxen);
+void WM8978_MIC_Gain(unsigned char gain);
+void WM8978_LINEIN_Gain(unsigned char gain);
+void WM8978_AUX_Gain(unsigned char gain);
+
+extern int hwi2c_en;
+
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/hw750.c b/drivers/gpu/drm/smifb2/hw750.c
new file mode 100644
index 000000000000..c34f346350f8
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/hw750.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+
+#include "ddk750/ddk750_mode.h"
+#include "ddk750/ddk750_help.h"
+#include "ddk750/ddk750_regdc.h"	
+#include "ddk750/ddk750_defs.h"
+#include "ddk750/ddk750_display.h"
+#include "ddk750/ddk750_2d.h"
+#include "ddk750/ddk750_power.h"
+#include "ddk750/ddk750_edid.h"
+#include "ddk750/ddk750_cursor.h"
+#include "ddk750/ddk750_swi2c.h"
+#include "ddk750/ddk750_hwi2c.h"
+
+
+#ifdef USE_HDMICHIP
+#include "ddk750/ddk750_sii9022.h"
+#endif
+#include <linux/version.h>
+
+
+struct smi_750_register{
+	/* registers for save */
+	uint32_t system_ctrl, misc_ctrl,gpio_mux, localmem_arbitration;
+	uint32_t pcimem_arbitration, raw_int, int_status, int_mask;
+	uint32_t current_gate, mode0_gate, mode1_gate, power_mode_ctrl;
+	uint32_t pci_master_base, primary_pll_ctrl,	secondary_pll_ctrl,	vga_pll0_ctrl;
+	uint32_t vga_pll1_ctrl,	mxclk_pll_ctrl,	vga_configuration;
+	
+	uint32_t de_stretch_format, de_masks, de_window_width, de_control;
+
+	uint32_t primary_display_ctrl,primary_pan_ctrl,primary_color_key,primary_fb_address;
+	uint32_t primary_fb_width, primary_window_width,primary_window_height, primary_plane_tl;
+	uint32_t primary_plane_br, primary_horizontal_total, primary_horizontal_sync, primary_vertical_total;
+	uint32_t primary_vertical_sync, primary_current_line;
+	
+	uint32_t secondary_display_ctrl, secondary_fb_address, secondary_fb_width;
+	uint32_t secondary_horizontal_total, secondary_horizontal_sync;
+	uint32_t secondary_vertical_total, secondary_vertical_sync;
+	uint32_t secondary_auto_centering_tl, secondary_auto_centering_br;
+	uint32_t secondary_scale, secondary_hwc_address, secondary_hwc_location;
+	uint32_t secondary_hwc_color_12, secondary_hwc_color_3;
+};
+
+
+
+void hw750_suspend(struct smi_750_register * pSave)
+{
+
+		/* save mmio registers */
+
+		pSave->system_ctrl = PEEK32(SYSTEM_CTRL);
+		pSave->misc_ctrl = PEEK32(MISC_CTRL);
+		pSave->gpio_mux = PEEK32(GPIO_MUX);
+		pSave->localmem_arbitration = PEEK32(LOCALMEM_ARBITRATION);
+		pSave->pcimem_arbitration = PEEK32(PCIMEM_ARBITRATION);
+		pSave->raw_int = PEEK32(RAW_INT);
+		pSave->int_status = PEEK32(INT_STATUS);
+		pSave->int_mask = PEEK32(INT_MASK);
+		pSave->current_gate = PEEK32(CURRENT_GATE);
+		pSave->mode0_gate = PEEK32(MODE0_GATE);
+		pSave->mode1_gate = PEEK32(MODE1_GATE);
+		pSave->power_mode_ctrl = PEEK32(POWER_MODE_CTRL);
+		pSave->pci_master_base = PEEK32(PCI_MASTER_BASE);
+		pSave->primary_pll_ctrl = PEEK32(PRIMARY_PLL_CTRL);
+		pSave->secondary_pll_ctrl = PEEK32(SECONDARY_PLL_CTRL);
+		pSave->vga_pll0_ctrl = PEEK32(VGA_PLL0_CTRL);
+		pSave->vga_pll1_ctrl = PEEK32(VGA_PLL1_CTRL);
+		pSave->mxclk_pll_ctrl = PEEK32(MXCLK_PLL_CTRL);
+		pSave->vga_configuration = PEEK32(VGA_CONFIGURATION);
+
+#if 0// for 2d, JUST HOLD IT.
+		pSave->de_stretch_format = PEEK32(DE_STRETCH_FORMAT);
+		pSave->de_masks = PEEK32(DE_MASKS);
+		pSave->de_window_width = PEEK32(DE_WINDOW_WIDTH);
+		pSave->de_control = PEEK32(DE_CONTROL);
+#endif	
+		pSave->primary_display_ctrl = PEEK32(PRIMARY_DISPLAY_CTRL);
+		pSave->primary_pan_ctrl = PEEK32(PRIMARY_PAN_CTRL);
+		pSave->primary_color_key = PEEK32(PRIMARY_COLOR_KEY);
+		pSave->primary_fb_address = PEEK32(PRIMARY_FB_ADDRESS);
+		pSave->primary_fb_width = PEEK32(PRIMARY_FB_WIDTH);
+		pSave->primary_window_width= PEEK32(PRIMARY_WINDOW_WIDTH);
+		pSave->primary_window_height= PEEK32(PRIMARY_WINDOW_HEIGHT);
+		pSave->primary_plane_tl= PEEK32(PRIMARY_PLANE_TL);
+		pSave->primary_plane_br= PEEK32(PRIMARY_PLANE_BR);
+		pSave->primary_horizontal_total = PEEK32(PRIMARY_HORIZONTAL_TOTAL);
+		pSave->primary_horizontal_sync = PEEK32(PRIMARY_HORIZONTAL_SYNC);
+		pSave->primary_vertical_total = PEEK32(PRIMARY_VERTICAL_TOTAL);
+		pSave->primary_vertical_sync = PEEK32(PRIMARY_VERTICAL_SYNC);
+		pSave->primary_current_line = PEEK32(PRIMARY_CURRENT_LINE);
+#if 0	//for hw cursor, JUST HOLD IT.
+		pSave->primary_hwc_address = PEEK32(PRIMARY_HWC_ADDRESS);
+		pSave->primary_hwc_location = PEEK32(PRIMARY_HWC_LOCATION);
+		pSave->primary_hwc_color_12 = PEEK32(PRIMARY_HWC_COLOR_12);
+		pSave->primary_hwc_color_3 = PEEK32(PRIMARY_HWC_COLOR_3);
+#endif	
+	
+		pSave->secondary_display_ctrl = PEEK32(SECONDARY_DISPLAY_CTRL);
+		pSave->secondary_fb_address = PEEK32(SECONDARY_FB_ADDRESS);
+		pSave->secondary_fb_width = PEEK32(SECONDARY_FB_WIDTH);
+		pSave->secondary_horizontal_total = PEEK32(SECONDARY_HORIZONTAL_TOTAL);
+		pSave->secondary_horizontal_sync = PEEK32(SECONDARY_HORIZONTAL_SYNC);
+		pSave->secondary_vertical_total = PEEK32(SECONDARY_VERTICAL_TOTAL);
+		pSave->secondary_vertical_sync = PEEK32(SECONDARY_VERTICAL_SYNC);
+		pSave->secondary_scale = PEEK32(SECONDARY_SCALE);
+		pSave->secondary_hwc_address = PEEK32(SECONDARY_HWC_ADDRESS);
+		pSave->secondary_hwc_location = PEEK32(SECONDARY_HWC_LOCATION);
+		pSave->secondary_hwc_color_12 = PEEK32(SECONDARY_HWC_COLOR_12);
+		pSave->secondary_hwc_color_3 = PEEK32(SECONDARY_HWC_COLOR_3);
+		pSave->secondary_auto_centering_tl = PEEK32(SECONDARY_AUTO_CENTERING_TL);
+		pSave->secondary_auto_centering_br = PEEK32(SECONDARY_AUTO_CENTERING_BR);
+
+}
+
+void hw750_resume(struct smi_750_register * pSave)
+{
+	/* restore mmio registers */
+	POKE32(SYSTEM_CTRL, pSave->system_ctrl);
+	POKE32(MISC_CTRL, pSave->misc_ctrl);
+	POKE32(GPIO_MUX, pSave->gpio_mux);
+	POKE32(LOCALMEM_ARBITRATION, pSave->localmem_arbitration);
+	POKE32(PCIMEM_ARBITRATION, pSave->pcimem_arbitration);
+	POKE32(RAW_INT, pSave->raw_int);
+	POKE32(INT_STATUS, pSave->int_status);
+	POKE32(INT_MASK, pSave->int_mask);
+	POKE32(CURRENT_GATE, pSave->current_gate);
+
+	POKE32(MODE0_GATE, pSave->mode0_gate);
+	POKE32(MODE1_GATE, pSave->mode1_gate);
+	POKE32(POWER_MODE_CTRL, pSave->power_mode_ctrl);
+	POKE32(PCI_MASTER_BASE, pSave->pci_master_base);
+	POKE32(PRIMARY_PLL_CTRL, pSave->primary_pll_ctrl);
+	POKE32(SECONDARY_PLL_CTRL, pSave->secondary_pll_ctrl);
+	POKE32(VGA_PLL0_CTRL, pSave->vga_pll0_ctrl);
+	POKE32(VGA_PLL1_CTRL, pSave->vga_pll1_ctrl);
+	POKE32(MXCLK_PLL_CTRL, pSave->mxclk_pll_ctrl);
+	POKE32(VGA_CONFIGURATION, pSave->vga_configuration);
+	
+    POKE32(PRIMARY_DISPLAY_CTRL, pSave->primary_display_ctrl);
+	POKE32(PRIMARY_PAN_CTRL, pSave->primary_pan_ctrl);
+	POKE32(PRIMARY_COLOR_KEY, pSave->primary_color_key );
+    POKE32(PRIMARY_FB_ADDRESS, pSave->primary_fb_address);
+    POKE32(PRIMARY_FB_WIDTH, pSave->primary_fb_width);
+	POKE32(PRIMARY_WINDOW_WIDTH, pSave->primary_window_width);
+	POKE32(PRIMARY_WINDOW_HEIGHT, pSave->primary_window_height);
+	POKE32(PRIMARY_PLANE_TL, pSave->primary_plane_tl);
+	POKE32(PRIMARY_PLANE_BR, pSave->primary_plane_br);
+    POKE32(PRIMARY_HORIZONTAL_TOTAL, pSave->primary_horizontal_total);
+    POKE32(PRIMARY_HORIZONTAL_SYNC, pSave->primary_horizontal_sync);
+    POKE32(PRIMARY_VERTICAL_TOTAL, pSave->primary_vertical_total);
+    POKE32(PRIMARY_VERTICAL_SYNC, pSave->primary_vertical_sync);
+    POKE32(PRIMARY_CURRENT_LINE, pSave->primary_current_line);
+
+    POKE32(SECONDARY_DISPLAY_CTRL, pSave->secondary_display_ctrl);	
+    POKE32(SECONDARY_FB_ADDRESS,  pSave->secondary_fb_address);
+    POKE32(SECONDARY_FB_WIDTH, pSave->secondary_fb_width);
+    POKE32(SECONDARY_HORIZONTAL_TOTAL, pSave->secondary_horizontal_total);
+
+    POKE32(SECONDARY_HORIZONTAL_SYNC,    pSave->secondary_horizontal_sync);
+    POKE32(SECONDARY_VERTICAL_TOTAL, pSave->secondary_vertical_total);
+    POKE32(SECONDARY_VERTICAL_SYNC, pSave->secondary_vertical_sync);
+    POKE32(SECONDARY_SCALE, pSave->secondary_scale);
+
+#if 0
+	POKE32(SECONDARY_HWC_ADDRESS, pSave->secondary_hwc_address);
+    POKE32(SECONDARY_HWC_LOCATION, pSave->secondary_hwc_location);
+    POKE32(SECONDARY_HWC_COLOR_12, pSave->secondary_hwc_color_12);
+    POKE32(SECONDARY_HWC_COLOR_3, pSave->secondary_hwc_color_3);
+#endif
+    POKE32(SECONDARY_AUTO_CENTERING_TL, pSave->secondary_auto_centering_tl);
+    POKE32(SECONDARY_AUTO_CENTERING_BR, pSave->secondary_auto_centering_br);
+
+
+#if 0	//HOLD FOR 2D
+    POKE32(DE_STRETCH_FORMAT, pSave->de_stretch_format);
+    POKE32(DE_MASKS, pSave->de_masks);
+    POKE32(DE_WINDOW_WIDTH, pSave->de_window_width);
+    POKE32(DE_CONTROL, pSave->de_control);
+#endif
+
+}
+
+void hw750_set_base(int display,int pitch,int base_addr)
+{	
+
+	if(display == 0)
+	{
+		pokeRegisterDWord(PRIMARY_FB_WIDTH,
+		          FIELD_VALUE(0, PRIMARY_FB_WIDTH, WIDTH, pitch)
+		        | FIELD_VALUE(0, PRIMARY_FB_WIDTH, OFFSET, pitch));
+		setDisplayBaseAddress(PRIMARY_CTRL, base_addr);
+	}
+	else
+	{
+		pokeRegisterDWord(SECONDARY_FB_WIDTH,
+		          FIELD_VALUE(0, SECONDARY_FB_WIDTH, WIDTH, pitch)
+		        | FIELD_VALUE(0, SECONDARY_FB_WIDTH, OFFSET, pitch));
+		setDisplayBaseAddress(SECONDARY_CTRL, base_addr);
+	}
+}
+
+void hw750_set_dpms(int display,int state)
+{
+	if(display == 0)
+	{
+		setDisplayControl(PRIMARY_CTRL, state);           /* Turn on Primary Control */
+		setPath(PANEL_PATH, PRIMARY_CTRL, state); 
+	}
+	else
+	{
+		setDisplayControl(SECONDARY_CTRL, state);         /* Turn on Secondary control */
+		setPath(CRT_PATH, SECONDARY_CTRL, state);
+	}
+}
+
+ 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+int hw750_en_dis_interrupt(int status, int pipe)
+{
+	if(status == 0)
+	{
+		pokeRegisterDWord(INT_MASK, 	(pipe == SECONDARY_CTRL) ? 
+		FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, DISABLE):
+		FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, DISABLE));
+	}
+	else
+	{
+		pokeRegisterDWord(INT_MASK, 	(pipe == SECONDARY_CTRL) ? 
+		FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, ENABLE):
+		FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, ENABLE));
+	}
+	return 0;
+
+}
+#else
+int hw750_en_dis_interrupt(int status)
+	{
+		if(status == 0)
+		{
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, DISABLE));
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, DISABLE)); 
+		}
+		else
+		{
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, ENABLE));
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, ENABLE));  
+		}
+		return 0;
+	}
+
+#endif
+
+
+int hw750_check_vsync_interrupt(int path)
+{
+
+	unsigned long value1,value2;
+	
+	value1 = peekRegisterDWord(RAW_INT);
+	value2 = peekRegisterDWord(INT_MASK);
+	
+	if(path == PRIMARY_CTRL)
+	{
+	    if ((FIELD_GET(value1, RAW_INT, PRIMARY_VSYNC) == RAW_INT_PRIMARY_VSYNC_ACTIVE)
+			&&(FIELD_GET(value2, INT_MASK, PRIMARY_VSYNC) == INT_MASK_PRIMARY_VSYNC_ENABLE))
+	    {
+			return true;
+		}
+	}else{
+		if ((FIELD_GET(value1, RAW_INT, SECONDARY_VSYNC) == RAW_INT_SECONDARY_VSYNC_ACTIVE)
+			&&(FIELD_GET(value2, INT_MASK, SECONDARY_VSYNC) == INT_MASK_SECONDARY_VSYNC_ENABLE))
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+
+
+void hw750_clear_vsync_interrupt(int path)
+{
+
+	unsigned long value;
+		
+	value = peekRegisterDWord(RAW_INT);
+	
+	if(path == PRIMARY_CTRL)
+	{
+	    
+		pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, PRIMARY_VSYNC, CLEAR));
+
+	}else{
+		
+		pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, SECONDARY_VSYNC, CLEAR));	
+		
+	}
+
+}
+
+void ddk750_disable_IntMask(void)
+{
+	
+    pokeRegisterDWord(INT_MASK, 0);
+}
+
+
+void hw750_setgamma(disp_control_t dispCtrl, unsigned long enable)
+{
+	unsigned long value;
+	unsigned long regCtrl;
+
+
+
+	if(dispCtrl == PRIMARY_CTRL)
+		regCtrl = PRIMARY_DISPLAY_CTRL;
+	else
+		regCtrl = SECONDARY_DISPLAY_CTRL;
+
+
+	value = peekRegisterDWord(regCtrl);
+	
+	if (enable)
+	    value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, GAMMA, ENABLE);
+	else
+	    value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, GAMMA, DISABLE);
+	    
+	pokeRegisterDWord(regCtrl, value);    
+}
+
+void hw750_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[])
+{
+	unsigned int i, v;
+	unsigned long regCtrl;
+
+	if(dispCtrl == PRIMARY_CTRL)
+		regCtrl = PRIMARY_PALETTE_RAM;
+	else
+		regCtrl = SECONDARY_PALETTE_RAM;
+
+	for (i = 0; i < size; i++) {
+		v = (lut_r[i] << 16);
+		v |= (lut_g[i] << 8);
+		v |= lut_b[i];
+		pokeRegisterDWord(regCtrl + (i * 4), v);
+	}
+}
+
+
+long hw750_AdaptI2CInit(struct smi_connector *smi_connector)
+{
+    if(hwi2c_en && (smi_connector->base.connector_type == DRM_MODE_CONNECTOR_DVII))
+    {
+        smi_connector->i2c_hw_enabled = 1;
+    }
+    else
+    {
+        smi_connector->i2c_hw_enabled = 0;      
+    }
+
+    if(smi_connector->i2c_hw_enabled)
+    {
+        return ddk750_AdaptHWI2CInit(smi_connector);
+    }
+    else
+    {
+        return ddk750_AdaptSWI2CInit(smi_connector); 
+    }
+}
+
+
+long hw750_AdaptI2CCleanBus(struct drm_connector *connector)
+{
+    struct smi_connector *smi_connector = to_smi_connector(connector);
+    
+    if(smi_connector->i2c_hw_enabled)
+    {
+        return ddk750_AdaptHWI2CCleanBus(smi_connector);
+    }
+
+    return 0;
+}
+
+
+
+
diff --git a/drivers/gpu/drm/smifb2/hw750.h b/drivers/gpu/drm/smifb2/hw750.h
new file mode 100644
index 000000000000..194e6329cfe1
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/hw750.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+
+#ifndef LYNX_HW750_H__
+#define LYNX_HW750_H__
+
+#include "hw_com.h"
+#ifdef USE_EP952
+#include "ddk768/ep952api.h"
+#endif
+
+
+
+
+void ddk750_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId);
+unsigned long ddk750_getFrameBufSize(void);
+long ddk750_initChip(void);
+void ddk750_deInit(void);
+long ddk750_detectCRTMonitor(unsigned char redValue, unsigned char greenValue,
+	unsigned char blueValue);
+
+long ddk750_edidHeaderReadMonitorExHwI2C(void);
+long ddk750_edidHeaderReadMonitorEx(
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);	
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidReadMonitor(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+);
+
+/*
+ *  edidReadMonitor
+ *      This function reads the EDID structure from the attached monitor
+ *
+ *  Input:
+ *      displayPath - Display device which EDID to be read from.
+ *      pEDIDBuffer - Buffer that contains the EDID structure of the monitor
+ *      bufferSize  - The EDID Buffer size index (usually 128-bytes)
+ *      edidExtNo   - Extension Index of the EDID Structure to be read
+ *      sclGpio     - GPIO pin used as the I2C Clock (SCL)
+ *      sdaGpio     - GPIO pin used as the I2C Data (SDA)
+ *
+ *  Output:
+ *      0   - Success
+ *     -1   - Fail
+ */
+long ddk750_edidReadMonitorEx(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);
+
+
+long ddk750_edidReadMonitorEx_HW(
+    disp_path_t displayPath,
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo
+);
+
+
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk750_initCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+);
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk750_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+);
+
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk750_enableCursor(
+    disp_control_t dispControl,     /* Display control (PRIMARY_CTRL or SECONDARY_CTRL) */
+    unsigned long enable
+);
+
+
+
+void hw750_set_base(int display,int pitch,int base_addr);
+
+long setMode(
+	logicalMode_t *pLogicalMode
+);
+void setDisplayControl(disp_control_t dispControl, disp_state_t dispState);
+void setPath(
+    disp_path_t dispPath, 
+    disp_control_t dispControl, 
+    disp_state_t dispState
+);
+
+void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay);
+void setDAC(disp_state_t state);
+void setDPMS(DPMS_t state);
+
+
+
+void hw750_set_dpms(int display,int state);
+void hw750_suspend(struct smi_750_register * pSave);
+void hw750_resume(struct smi_750_register * pSave);
+int hw750_check_vsync_interrupt(int path);
+void hw750_clear_vsync_interrupt(int path);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+int hw750_en_dis_interrupt(int status, int pipe);
+#else
+int hw750_en_dis_interrupt(int status);
+#endif
+
+
+void ddk750_disable_IntMask(void);
+
+int sii9022xInitChip(void);
+int sii9022xSetMode(int);
+unsigned char sii9022xIsConnected(void);
+
+int ddk750_GetDDC_9022Access(void);
+int ddk750_Release9022DDC(void);
+
+void ddk750_DoEdidRead(void);
+
+void hw750_setgamma(disp_control_t dispCtrl, unsigned long enable);
+void hw750_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]);
+
+long hw750_AdaptI2CInit(struct smi_connector *smi_connector);
+long hw750_AdaptI2CCleanBus(
+    struct drm_connector *connector
+);
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/hw768.c b/drivers/gpu/drm/smifb2/hw768.c
new file mode 100644
index 000000000000..6d27ae433e86
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/hw768.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+#include <drm/drm_modes.h>
+
+#include "ddk768/ddk768_mode.h"
+#include "ddk768/ddk768_help.h"
+#include "ddk768/ddk768_reg.h"	
+#include "ddk768/ddk768_display.h"
+#include "ddk768/ddk768_2d.h"
+#include "ddk768/ddk768_power.h"
+#include "ddk768/ddk768_cursor.h"
+#include "ddk768/ddk768_video.h"
+#include "ddk768/ddk768_hdmi.h"
+#include "ddk768/ddk768_pwm.h"
+#include "ddk768/ddk768_swi2c.h"
+#include "ddk768/ddk768_hwi2c.h"
+
+#include <linux/version.h>
+
+
+extern int lcd_scale;
+extern int pwm_ctrl;
+
+
+struct smi_768_register{
+	uint32_t clock_enable, pll_ctrl[3];
+	
+	uint32_t primary_display_ctrl[10], lvds_ctrl, primary_hwcurs_ctrl[4];
+	uint32_t secondary_display_ctrl[10], secondary_hwcurs_ctrl[4];
+};
+
+
+mode_parameter_t convert_drm_mode_to_ddk_mode(struct drm_display_mode mode)
+{
+	mode_parameter_t modeP;
+
+    modeP.horizontal_total = mode.htotal;
+    modeP.horizontal_display_end = mode.hdisplay;
+    modeP.horizontal_sync_start = mode.hsync_start;
+    modeP.horizontal_sync_width = mode.hsync_end - mode.hsync_start;
+    modeP.horizontal_sync_polarity = mode.flags & DRM_MODE_FLAG_PHSYNC ? POS : NEG;
+
+    /* Vertical timing. */
+    modeP.vertical_total = mode.vtotal;
+    modeP.vertical_display_end = mode.vdisplay;
+    modeP.vertical_sync_start = mode.vsync_start;
+    modeP.vertical_sync_height = mode.vsync_end - mode.vsync_start;
+    modeP.vertical_sync_polarity = mode.flags & DRM_MODE_FLAG_PVSYNC ? POS : NEG;
+
+    /* Refresh timing. */
+    modeP.pixel_clock = mode.clock * 1000;
+    modeP.horizontal_frequency = 0;
+    modeP.vertical_frequency = 0;
+    
+    /* Clock Phase. This clock phase only applies to Panel. */
+    modeP.clock_phase_polarity = POS;
+
+	return modeP;
+}
+
+
+
+void hw768_enable_lvds(int channels)
+{
+	if(channels == 1){	
+		pokeRegisterDWord(0x80020,0x31E30000);		
+		pokeRegisterDWord(0x8002C,0x74001200);
+	}else{
+		unsigned long value = 0;
+		pokeRegisterDWord(0x80020, 0x31E3F71D);
+		pokeRegisterDWord(0x8002C,0x750FED02);
+		value = peekRegisterDWord(DISPLAY_CTRL);
+		value = FIELD_SET(value, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT);
+		value = FIELD_SET(value, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, HALF);
+		value = FIELD_SET(value, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+		pokeRegisterDWord(DISPLAY_CTRL,value);
+
+		value = peekRegisterDWord(DISPLAY_CTRL + CHANNEL_OFFSET);
+		value = FIELD_SET(value, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT);
+		pokeRegisterDWord(DISPLAY_CTRL + CHANNEL_OFFSET,value);
+	}
+	
+	
+	if(pwm_ctrl)
+	{
+		unsigned long pwm, divider, highCounter, lowCounter;
+
+	     	pwm = pwm_ctrl & 0xf;
+		divider = (pwm_ctrl & 0xf0) >> 4;
+	    	highCounter = (pwm_ctrl & 0xfff00) >> 8;
+		lowCounter = (pwm_ctrl & 0xfff00000) >> 20;
+
+		ddk768_pwmOpen(pwm);
+		ddk768_pwmStart(pwm, divider, highCounter, lowCounter, 0);
+	}
+
+	
+}	
+
+
+
+void ddk768_setDisplayPlaneDisableOnly(
+   disp_control_t dispControl /* Channel 0 or Channel 1) */
+)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+    ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET);
+    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+
+	
+ 	ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE)|        
+                    FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED); 
+
+	 pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+   
+}
+
+
+
+
+void hw768_suspend(struct smi_768_register * pSave)
+{
+
+	int i;
+
+	pSave->clock_enable = peekRegisterDWord(CLOCK_ENABLE);
+	for (i = 0; i < 3; i++)
+		pSave->pll_ctrl[i] = peekRegisterDWord(MCLK_PLL + i * 4);
+
+	for (i = 0; i < 10; i++)
+		pSave->primary_display_ctrl[i] = peekRegisterDWord(DISPLAY_CTRL + i * 4);
+	pSave->lvds_ctrl = peekRegisterDWord(LVDS_CTRL2);
+	for (i = 0; i < 4; i++)
+		pSave->primary_hwcurs_ctrl[i] = peekRegisterDWord(HWC_CONTROL + i * 4);
+
+	for (i = 0; i < 10; i++)
+		pSave->secondary_display_ctrl[i] = peekRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4);
+	for (i = 0; i < 4; i++)
+		pSave->secondary_hwcurs_ctrl[i] = peekRegisterDWord(0x8000 + HWC_CONTROL + i * 4);
+
+
+}
+
+void hw768_resume(struct smi_768_register * pSave)
+{
+
+	int i;
+
+	pokeRegisterDWord(CLOCK_ENABLE, pSave->clock_enable);
+	for (i = 0; i < 3; i++)
+		pokeRegisterDWord(MCLK_PLL + i * 4, pSave->pll_ctrl[i]);
+
+	for (i = 0; i < 10; i++)
+		pokeRegisterDWord(DISPLAY_CTRL + i * 4, pSave->primary_display_ctrl[i]);
+	pokeRegisterDWord(LVDS_CTRL2, pSave->lvds_ctrl);
+	for (i = 0; i < 4; i++)
+		pokeRegisterDWord(HWC_CONTROL + i * 4, pSave->primary_hwcurs_ctrl[i]);
+
+	for (i = 0; i < 10; i++)
+		pokeRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4, pSave->secondary_display_ctrl[i]);
+	for (i = 0; i < 4; i++)
+		pokeRegisterDWord(0x8000 + HWC_CONTROL + i * 4, pSave->secondary_hwcurs_ctrl[i]);
+
+}
+void hw768_set_base(int display,int pitch,int base_addr)
+{	
+
+	if(display == 0)
+	{
+		/* Frame buffer base */
+	    pokeRegisterDWord((FB_ADDRESS),
+	          FIELD_SET(0, FB_ADDRESS, STATUS, PENDING)
+	        | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, base_addr));
+
+	    /* Pitch value (Hardware people calls it Offset) */
+    	pokeRegisterDWord((FB_WIDTH), FIELD_VALUE(peekRegisterDWord(FB_WIDTH), FB_WIDTH, OFFSET, pitch));
+
+		if(lcd_scale){
+				pokeRegisterDWord((VIDEO_FB_WIDTH),
+					   FIELD_VALUE(0, VIDEO_FB_WIDTH, WIDTH, pitch) |
+					   FIELD_VALUE(0, VIDEO_FB_WIDTH, OFFSET, pitch));
+		
+			   pokeRegisterDWord(VIDEO_FB_ADDRESS,
+					   FIELD_SET(0, VIDEO_FB_ADDRESS, STATUS, PENDING) |
+					   FIELD_VALUE(0, VIDEO_FB_ADDRESS, ADDRESS, base_addr));
+
+		}
+	}
+	else
+	{
+		/* Frame buffer base */
+	    pokeRegisterDWord((FB_ADDRESS+CHANNEL_OFFSET),
+	          FIELD_SET(0, FB_ADDRESS, STATUS, PENDING)
+	        | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, base_addr));
+
+		
+	    /* Pitch value (Hardware people calls it Offset) */	
+	    pokeRegisterDWord((FB_WIDTH+CHANNEL_OFFSET),FIELD_VALUE(peekRegisterDWord(FB_WIDTH+CHANNEL_OFFSET), FB_WIDTH, OFFSET, pitch));
+
+	}
+}
+
+
+void hw768_init_hdmi(void)
+{
+	HDMI_Init();
+}
+
+int hw768_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI)
+{
+	int ret = 1;
+	mode_parameter_t modeParam;
+	
+	// set HDMI parameters
+	HDMI_Disable_Output();
+
+	if(pLogicalMode->valid_edid)
+		modeParam = convert_drm_mode_to_ddk_mode(mode);
+	ret = HDMI_Set_Mode(pLogicalMode,&modeParam,isHDMI);
+	return ret;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+int hw768_en_dis_interrupt(int status, int pipe)
+{
+	if(status == 0)
+	{
+		pokeRegisterDWord(INT_MASK, 	(pipe == CHANNEL0_CTRL) ? 
+		FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, DISABLE):
+		FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, DISABLE));
+	}
+	else
+	{
+		pokeRegisterDWord(INT_MASK, 	(pipe == CHANNEL1_CTRL) ? 
+		FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, ENABLE):
+		FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, ENABLE));
+	}
+	return 0;
+}
+#else
+int hw768_en_dis_interrupt(int status)
+	{
+		if(status == 0)
+		{
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, DISABLE));
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, DISABLE)); 
+		}
+		else
+		{
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, ENABLE));
+			pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, ENABLE));  
+		}
+		return 0;
+	}
+
+#endif
+
+void hw768_HDMI_Enable_Output(void)
+{
+	HDMI_Enable_Output();
+}
+
+void hw768_HDMI_Disable_Output(void)
+{
+	HDMI_Disable_Output();
+}
+
+
+int hw768_get_hdmi_edid(unsigned char *pEDIDBuffer)
+{
+    int ret;
+    enableHdmI2C(1);
+    ret = HDMI_Read_Edid(pEDIDBuffer, 128);
+    enableHdmI2C(0);
+
+    return ret;
+}
+
+int hw768_check_iis_interrupt(void)
+{
+
+	unsigned long value;
+		
+	value = peekRegisterDWord(INT_STATUS);
+
+	
+    if (FIELD_GET(value, INT_STATUS, I2S) == INT_STATUS_I2S_ACTIVE)
+		return true;
+	else	
+		return false;
+}
+
+
+int hw768_check_vsync_interrupt(int path)
+{
+
+	unsigned long value1,value2;
+		
+	value1 = peekRegisterDWord(RAW_INT);
+	value2 = peekRegisterDWord(INT_MASK);
+
+	if(path == CHANNEL0_CTRL)
+	{
+	    if ((FIELD_GET(value1, RAW_INT, CHANNEL0_VSYNC) == RAW_INT_CHANNEL0_VSYNC_ACTIVE)
+			&&(FIELD_GET(value2, INT_MASK, CHANNEL0_VSYNC) == INT_MASK_CHANNEL0_VSYNC_ENABLE))
+	    {
+			return true;
+		}
+	}else{
+		if ((FIELD_GET(value1, RAW_INT, CHANNEL1_VSYNC) == RAW_INT_CHANNEL1_VSYNC_ACTIVE)
+			&&(FIELD_GET(value2, INT_MASK, CHANNEL1_VSYNC) == INT_MASK_CHANNEL1_VSYNC_ENABLE))
+		{
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+
+void hw768_clear_vsync_interrupt(int path)
+{
+	
+	unsigned long value;
+	
+	value = peekRegisterDWord(RAW_INT);
+
+	if (path == CHANNEL0_CTRL)
+	{
+		pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL0_VSYNC, CLEAR));
+	}
+	else
+	{
+		pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL1_VSYNC, CLEAR));
+	}
+}
+
+long hw768_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode)
+{
+	
+	if (!pLogicalMode->valid_edid)
+		return ddk768_setMode(pLogicalMode);
+	else
+	{	
+		mode_parameter_t ModeParam;
+		ModeParam = convert_drm_mode_to_ddk_mode(mode);
+		return ddk768_setCustomMode(pLogicalMode, &ModeParam);
+	}
+	
+}
+
+
+int hdmi_int_status = 0;
+
+inline int hdmi_hotplug_detect(void)
+{
+	int ret = 0;
+	unsigned int intMask = peekRegisterDWord(INT_MASK);
+	intMask = FIELD_SET(intMask, INT_MASK, HDMI, ENABLE);
+	pokeRegisterDWord(INT_MASK, intMask);
+
+	ret = hdmi_detect();
+
+	if (ret == 1)
+	{
+		hdmi_int_status = 1;
+	}
+	else if (ret == 0)
+	{
+		hdmi_int_status = 0;
+	}
+	else
+	{
+		hdmi_int_status = hdmi_int_status & ret;
+	}
+
+	intMask = peekRegisterDWord(INT_MASK);
+	intMask = FIELD_SET(intMask, INT_MASK, HDMI, DISABLE);
+	pokeRegisterDWord(INT_MASK, intMask);
+
+	return hdmi_int_status;
+}
+
+void ddk768_disable_IntMask(void)
+{
+	
+    pokeRegisterDWord(INT_MASK, 0);
+}
+
+void hw768_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half)
+{
+    unsigned long ulDispCtrlAddr;
+    unsigned long ulDispCtrlReg;
+
+    if (dispControl == CHANNEL0_CTRL)
+    {
+        ulDispCtrlAddr = DISPLAY_CTRL;
+    }
+    else
+        return;
+    
+    ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr);
+    
+	if(is_half)
+		ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, HALF);
+	else
+		ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, SINGLE);
+
+
+    pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg);
+}
+
+void hw768_setgamma(disp_control_t dispCtrl, unsigned long enable, unsigned long lvds_ch)
+{
+	unsigned long value;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? DISPLAY_CTRL 
+				: (DISPLAY_CTRL+CHANNEL_OFFSET);
+
+	value = peekRegisterDWord(regCtrl);
+	
+	if (enable)
+	    value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, ENABLE);
+	else
+	    value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, DISABLE);
+
+	if((lvds_ch == 2) && (dispCtrl == CHANNEL0_CTRL))   //dual channel LVDS and channel 0 gamma setting
+		value = FIELD_SET(value, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE);
+	else{
+		value = FIELD_SET(value, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE);
+	}
+	   	
+	pokeRegisterDWord(regCtrl, value);    
+}
+
+void hw768_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[])
+{
+	unsigned int i, v;
+	unsigned long regCtrl;
+
+	regCtrl = (dispCtrl == CHANNEL0_CTRL)? PALETTE_RAM 
+				: (PALETTE_RAM+CHANNEL_OFFSET);
+
+	for (i = 0; i < size; i++) {
+		v = (lut_r[i] << 16);
+		v |= (lut_g[i] << 8);
+		v |= lut_b[i];
+		pokeRegisterDWord(regCtrl + (i * 4), v);
+	}
+}
+
+
+
+long hw768_AdaptI2CInit(struct smi_connector *smi_connector)
+{
+    if(hwi2c_en)
+    {
+        smi_connector->i2c_hw_enabled = 1;
+    }
+    else
+    {
+        smi_connector->i2c_hw_enabled = 0;      
+    }
+
+    if(smi_connector->i2c_hw_enabled)
+    {
+        return ddk768_AdaptHWI2CInit(smi_connector);
+    }
+    else
+    {
+        return ddk768_AdaptSWI2CInit(smi_connector); 
+    }
+}
+
+
+long hw768_AdaptI2CCleanBus(struct drm_connector *connector)
+{
+        struct smi_connector *smi_connector = to_smi_connector(connector);
+    
+    if(smi_connector->i2c_hw_enabled)
+    {
+        return ddk768_AdaptHWI2CCleanBus(smi_connector);
+    }
+    else
+    {
+        return ddk768_AdaptSWI2CCleanBus(smi_connector);
+    }
+}
+
+
+
diff --git a/drivers/gpu/drm/smifb2/hw768.h b/drivers/gpu/drm/smifb2/hw768.h
new file mode 100644
index 000000000000..78ac3f0fadb2
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/hw768.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+
+#ifndef LYNX_HW768_H__
+#define LYNX_HW768_H__
+#include "hw_com.h"
+#ifdef USE_EP952
+#include "ddk768/ep952api.h"
+#endif
+
+
+unsigned char HDMI_connector_detect(void);
+void ddk768_setDisplayPlaneDisableOnly(
+   disp_control_t dispControl /* Channel 0 or Channel 1) */
+);
+
+
+void hw768_enable_lvds(int channels);
+
+void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId);
+unsigned long ddk768_getFrameBufSize(void);
+long ddk768_initChip(void);
+void ddk768_deInit(void);
+
+void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay);
+
+
+long ddk768_edidHeaderReadMonitorEx(
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);
+
+long ddk768_edidHeaderReadMonitorExHwI2C(
+    unsigned char i2cNumber
+);
+
+
+
+long ddk768_detectCRTMonitor(disp_control_t dispControl, unsigned char redValue, 
+	unsigned char greenValue, unsigned char blueValue);
+
+long ddk768_edidReadMonitor(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+);
+
+
+
+
+
+long ddk768_edidReadMonitorEx(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char sclGpio,
+    unsigned char sdaGpio
+);
+
+
+
+int hw768_get_hdmi_edid(unsigned char *pEDIDBuffer);
+
+
+
+long ddk768_edidReadMonitorExHwI2C(
+    unsigned char *pEDIDBuffer,
+    unsigned long bufferSize,
+    unsigned char edidExtNo,
+    unsigned char i2cNumber
+);
+
+/*
+ * Disable double pixel clock. 
+ * This is a teporary function, used to patch for the random fuzzy font problem. 
+ */
+void DisableDoublePixel(disp_control_t dispControl);
+void EnableDoublePixel(disp_control_t dispControl);
+void hw768_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half);
+
+
+/*
+ * This function initializes the cursor attributes.
+ */
+void ddk768_initCursor(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long base,             /* Base Address */ 
+    unsigned long color1,           /* Cursor color 1 in RGB 5:6:5 format */
+    unsigned long color2,           /* Cursor color 2 in RGB 5:6:5 format */
+    unsigned long color3            /* Cursor color 3 in RGB 5:6:5 format */
+);
+
+/*
+ * This function sets the cursor position.
+ */
+void ddk768_setCursorPosition(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long dx,               /* X Coordinate of the cursor */
+    unsigned long dy,               /* Y Coordinate of the cursor */
+    unsigned char topOutside,       /* Top Boundary Select: either partially outside (= 1) 
+                                       or within the screen top boundary (= 0) */
+    unsigned char leftOutside       /* Left Boundary Select: either partially outside (= 1) 
+                                       or within the screen left boundary (= 0) */
+);
+ 
+void hw768_set_base(int display,int pitch,int base_addr);
+ 
+/*
+ * This function enables/disables the cursor.
+ */
+void ddk768_enableCursor(
+    disp_control_t dispControl,     /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */
+    unsigned long enable
+);
+
+void hw768_HDMI_Enable_Output(void);
+
+void hw768_HDMI_Disable_Output(void);
+
+ 
+long ddk768_setMode(
+    logicalMode_t *pLogicalMode
+);
+long setSingleViewOn(disp_control_t dispOutput);
+long initDisplay(void);	
+
+void setDisplayDPMS(
+   disp_control_t dispControl, /* Channel 0 or Channel 1) */
+   DISP_DPMS_t state /* DPMS state */
+   );
+
+void hw768_init_hdmi(void);
+int hw768_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI);
+
+
+
+void ddk768_setDisplayEnable(disp_control_t dispControl, /* Channel 0 or Channel 1) */
+disp_state_t dispState /* ON or OFF */);
+
+int hw768_check_iis_interrupt(void);
+
+int hw768_check_vsync_interrupt(int path);
+void hw768_clear_vsync_interrupt(int path);
+
+long hw768_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+int hw768_en_dis_interrupt(int status, int pipe);
+#else
+int hw768_en_dis_interrupt(int status);
+#endif
+
+int hdmi_detect(void);
+
+int hdmi_hotplug_detect(void);
+
+void HDMI_Audio_Mute (void);
+
+void HDMI_Audio_Unmute (void);
+
+
+void ddk768_disable_IntMask(void);
+
+void hw768_suspend(struct smi_768_register * pSave);
+void hw768_resume(struct smi_768_register * pSave);
+
+void hw768_setgamma(disp_control_t dispCtrl, unsigned long enable,unsigned long lvds_ch);
+void hw768_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]);
+
+long hw768_AdaptI2CCleanBus(
+    struct drm_connector *connector
+);
+long hw768_AdaptI2CInit(struct smi_connector *smi_connector);
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/hw_com.h b/drivers/gpu/drm/smifb2/hw_com.h
new file mode 100644
index 000000000000..775da85ad4f6
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/hw_com.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+
+
+#ifndef LYNX_HW_COM_H__
+#define LYNX_HW_COM_H__
+
+typedef enum _disp_path_t
+{
+    SMI0_PATH = 0,
+    SMI1_PATH  = 1,
+}
+disp_path_t;
+
+typedef enum _disp_control_t
+{
+    SMI0_CTRL = 0,
+    SMI1_CTRL = 1,
+    SMI2_CTRL = 2,
+    ERROR_CTRL = 3,
+}
+disp_control_t;
+
+typedef enum _disp_state_t
+{
+    DISP_OFF = 0,
+    DISP_ON  = 1,
+}
+disp_state_t;
+typedef enum _DPMS_t
+{
+    DPMS_ON,
+    DPMS_STANDBY,
+    DPMS_SUSPEND,
+    DPMS_OFF
+}
+DPMS_t;
+
+typedef enum _DISP_DPMS_t
+{
+    DISP_DPMS_ON,
+    DISP_DPMS_STANDBY,
+    DISP_DPMS_SUSPEND,
+    DISP_DPMS_OFF
+}
+DISP_DPMS_t;
+
+
+
+typedef struct _logicalMode_t
+{
+    unsigned long x;            /* X resolution */
+    unsigned long y;            /* Y resolution */
+    unsigned long bpp;          /* Bits per pixel */
+    unsigned long hz;           /* Refresh rate */
+
+    unsigned long baseAddress;  /* Offset from beginning of frame buffer.
+                                   It is used to control the starting location of a mode.
+                                   Calling function must initialize this field.
+                                 */
+
+    unsigned long pitch;        /* Mode pitch in byte.
+                                   If initialized to 0, setMode function will set
+                                   up this field.
+                                   If not zero, setMode function will use this value.
+                                 */
+	unsigned long valid_edid;
+    disp_control_t dispCtrl;    /* SECONDARY or PRIMARY display control channel */
+    
+    /* These two parameters are used in the setModeEx. */
+    unsigned long xLCD;         /* Panel width */
+    unsigned long yLCD;         /* Panel height */
+    
+    void *userData;             /* Not used now, set it to 0 (for future used only) */
+
+}
+logicalMode_t;
+
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/smi_dbg.h b/drivers/gpu/drm/smifb2/smi_dbg.h
new file mode 100644
index 000000000000..39b64d323a5f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_dbg.h
@@ -0,0 +1,33 @@
+#ifndef __SMI_DBG_H__
+#define __SMI_DBG_H__
+#include <linux/version.h>
+
+#include <drm/drm_print.h>
+
+
+extern int smi_indent;
+extern int smi_debug;
+
+#define ENTER()	do { \
+	if (smi_debug) {\
+		printk("%*c %s\n", smi_indent++, '>', __func__); \
+	} \
+} while (0)
+
+
+#define LEAVE(...)                                                                                 \
+	do {             \
+	if (smi_debug) {\
+		printk("%*c %s\n", --smi_indent, '<', __func__);                         \
+	} \
+		return __VA_ARGS__;                                                                \
+} while (0)
+
+#define dbg_msg(fmt,args...)	do { \
+		if (smi_debug) {\
+			printk(fmt, ##args); \
+		} \
+} while (0)
+
+
+#endif
\ No newline at end of file
diff --git a/drivers/gpu/drm/smifb2/smi_drv.c b/drivers/gpu/drm/smifb2/smi_drv.c
new file mode 100644
index 000000000000..71b5b0d44c52
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_drv.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+#include "smi_drv.h"
+#include <linux/console.h>
+#include <linux/module.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+#include <drm/drmP.h>
+#else
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_print.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+#include <drm/drm_pci.h>
+#else
+#include <linux/pci.h>
+#endif
+#include <drm/drm_vblank.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+#include <drm/drm_aperture.h>
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+#include <drm/drm_probe_helper.h>
+#endif
+#include <drm/drm_crtc_helper.h>
+
+#include "smi_dbg.h"
+
+#include "hw750.h"
+#include "hw768.h"
+
+
+int smi_modeset = -1;
+int smi_indent = 0;
+int smi_bpp = 32;
+int force_connect = 0;
+int g_specId = 0;
+int smi_pat = 0xff;
+int lvds_channel = 0;
+int usb_host = 0;
+int audio_en = 0;
+int fixed_width = 0;
+int fixed_height = 0;
+int hwi2c_en = 0;
+int swcur_en = 0;
+int edid_mode = 1;
+int smi_debug = 0;
+int lcd_scale = 0;
+int pwm_ctrl = 0;
+int clk_phase = -1;
+
+module_param(smi_pat, int, S_IWUSR | S_IRUSR);
+
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, smi_modeset, int, 0400);
+MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:32)");
+module_param_named(bpp, smi_bpp, int, 0400);
+MODULE_PARM_DESC(nopnp, "Force conncet to the monitor without monitor EDID (default:0) bit0:DVI,bit1:VGA,bit2:HDMI ");
+module_param_named(nopnp, force_connect, int, 0400);
+MODULE_PARM_DESC(lvds, "LVDS Channel, 0=disable 1=single channel, 2=dual channel (default:0)");
+module_param_named(lvds, lvds_channel, int, 0400);
+MODULE_PARM_DESC(width, "Fixed mode width for LVDS or nopnp (default:0)");
+module_param_named(width, fixed_width, int, 0400);
+MODULE_PARM_DESC(height, "Fixed mode height for LVDS or nopnp (default:0)");
+module_param_named(height, fixed_height, int, 0400);
+MODULE_PARM_DESC(audio, "SM768 Audio, 0=diable 1=use UDA1345 Codec, 2=use WM8978 Codec(default:0)");
+module_param_named(audio, audio_en, int, 0400);
+MODULE_PARM_DESC(hwi2c, "HW I2C for EDID reading, 0=SW I2C 1=HW I2C(default:0)");
+module_param_named(hwi2c, hwi2c_en, int, 0400);
+MODULE_PARM_DESC(swcur, "Use Software cursor, 0=HW Cursor 1=SW Cursor(default:0)");
+module_param_named(swcur, swcur_en, int, 0400);
+MODULE_PARM_DESC(edidmode, "Use Monitor EDID mode timing, 0 = Driver build-in mode timing 1 = Monitor EDID mode timing(default:1)");
+module_param_named(edidmode, edid_mode, int, 0400);
+MODULE_PARM_DESC(debug, "Driver debug log enable, 0 = disable 1 = enable (default:0)");
+module_param_named(debug, smi_debug, int, 0400);
+MODULE_PARM_DESC(lcdscale, "LCD(LVDS) scale  enable, 0 = disable 1 = enable (default:0)");
+module_param_named(lcdscale, lcd_scale, int, 0400);
+MODULE_PARM_DESC(pwm, "PWM Value, 0 = disable (default:0) bit 0-3: PWM 0/1/2 bit4-7: PWM Divider bit8-19: PWM Low Counter bit20-31: PWM High Counter");
+module_param_named(pwm, pwm_ctrl, int, 0400);
+MODULE_PARM_DESC(clkphase, "Panel Mode Clock phase, -1 = Use Mode table (Default)  0 = Negative 1 = Postive");
+module_param_named(clkphase, clk_phase, int, 0400);
+
+
+
+/*
+ * This is the generic driver code. This binds the driver to the drm core,
+ * which then performs further device association and calls our graphics init
+ * functions
+ */
+#define PCI_VENDOR_ID_SMI 0x126f
+#define PCI_DEVID_SM750 0x0750
+#define PCI_DEVID_SM768 0x0768
+
+static struct drm_driver driver;
+
+/* only bind to the smi chip in qemu */
+static const struct pci_device_id pciidlist[] = {
+	{ PCI_VENDOR_ID_SMI, PCI_DEVID_SM750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_SMI, PCI_DEVID_SM768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{
+		0,
+	}
+};
+
+static void claim(void)
+{
+	printk("+-------------SMI Driver Information------------+\n");
+	printk("Release type: " RELEASE_TYPE "\n");
+	printk("Driver version: v" _version_ "\n");
+	printk("Support products: " SUPPORT_CHIP "\n");
+	printk("+-----------------------------------------------+\n");
+}
+
+static int smi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	struct drm_device *dev;
+#endif
+	int ret __attribute__((unused)) = 0;
+
+	claim();
+	if (ent->vendor != PCI_VENDOR_ID_SMI &&
+	    !(ent->device == PCI_DEVID_LYNX_EXP || ent->device == PCI_DEVID_SM768)) {
+		return -ENODEV;
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
+	drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	drm_aperture_remove_conflicting_pci_framebuffers(pdev, "smidrmfb");
+#else
+	drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "smidrmfb");
+#endif
+#else
+	drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "smidrmfb");
+#endif
+
+	if (ent->vendor == PCI_VENDOR_ID_SMI && ent->device == PCI_DEVID_SM768) {
+		
+		if (lvds_channel != 0) {
+			dbg_msg("LVDS channel set to %d\n", lvds_channel);
+		}
+	}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	dev = drm_dev_alloc(&driver, &pdev->dev);
+	if (IS_ERR(dev)) {
+		ret = PTR_ERR(dev);
+		goto err_pci_disable_device;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
+	dev->pdev = pdev;
+#endif
+
+	pci_set_drvdata(pdev, dev);
+
+	ret = smi_driver_load(dev, ent->driver_data);
+	if (ret)
+		goto err_drm_dev_put;
+
+	ret = drm_dev_register(dev, ent->driver_data);
+	if (ret)
+		goto err_smi_driver_unload;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+	if ((g_specId == SPC_SM750 && (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) || g_specId == SPC_SM768)
+		drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
+#endif
+
+
+	return 0;
+
+err_smi_driver_unload:
+	smi_driver_unload(dev);
+err_drm_dev_put:
+	drm_dev_put(dev);
+err_pci_disable_device:
+	pci_disable_device(pdev);
+	return ret;
+#else
+	return drm_get_pci_dev(pdev, ent, &driver);
+#endif
+}
+
+static void smi_pci_remove(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	drm_dev_unregister(dev);
+	smi_driver_unload(dev);
+	drm_dev_put(dev);
+#else
+	drm_put_dev(dev);
+#endif
+}
+
+static int smi_drm_freeze(struct drm_device *dev)
+{
+	int ret;
+	struct smi_device *sdev = dev->dev_private;
+	ENTER();
+	
+	if (g_specId == SPC_SM750)
+		hw750_suspend(sdev->regsave);
+    else if(g_specId == SPC_SM768){
+		 if(audio_en)
+			 smi_audio_suspend();
+		hw768_suspend(sdev->regsave_768);
+
+    }
+	ret = drm_mode_config_helper_suspend(dev);
+	if (ret)
+		return ret;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pci_save_state(to_pci_dev(dev->dev));
+#else
+    pci_save_state(dev->pdev);
+#endif
+
+	LEAVE(0);
+}
+
+static int smi_drm_thaw(struct drm_device *dev)
+{
+	struct smi_device *sdev = dev->dev_private;
+
+	ENTER();
+	
+	
+	if(g_specId == SPC_SM750)
+			hw750_resume(sdev->regsave);
+	else if(g_specId == SPC_SM768){
+			hw768_resume(sdev->regsave_768);
+		if(audio_en)
+			smi_audio_resume();
+		if (lvds_channel == 1)
+			hw768_enable_lvds(1);
+		else if (lvds_channel == 2) {
+			hw768_enable_lvds(2);
+			EnableDoublePixel(0);
+		}
+	}
+
+	LEAVE(0);
+	
+	
+
+}
+
+static int smi_drm_resume(struct drm_device *dev)
+{
+	struct smi_device *UNUSED(sdev) = dev->dev_private;
+	int ret;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	if (pci_enable_device(to_pci_dev(dev->dev)))
+#else
+    if (pci_enable_device(dev->pdev))
+#endif	
+		return -EIO;
+
+	ret = smi_drm_thaw(dev);
+	if (ret)
+		return ret;
+
+	return drm_mode_config_helper_resume(dev);
+}
+
+static int smi_pm_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *ddev = pci_get_drvdata(pdev);
+	int error;
+
+	error = smi_drm_freeze(ddev);
+	if (error)
+		return error;
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+	
+	return 0;
+}
+
+static int smi_pm_resume(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
+
+	return smi_drm_resume(ddev);
+}
+
+static int smi_pm_freeze(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
+
+	return smi_drm_freeze(ddev);
+}
+
+static int smi_pm_thaw(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
+	return smi_drm_thaw(ddev);
+}
+
+static int smi_pm_poweroff(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev);
+
+	return smi_drm_freeze(ddev);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+static int smi_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	if (g_specId == SPC_SM750) {
+		hw750_en_dis_interrupt(1, pipe);
+	} else if (g_specId == SPC_SM768) {
+		hw768_en_dis_interrupt(1, pipe);
+	}
+	return 0;
+}
+
+static void smi_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	if (g_specId == SPC_SM750) {
+		hw750_en_dis_interrupt(0, pipe);
+	} else if (g_specId == SPC_SM768) {
+		hw768_en_dis_interrupt(0, pipe);
+	}
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+static void smi_irq_preinstall(struct drm_device *dev)
+{
+	// To Do....
+	/* Disable *all* interrupts */
+
+	/* Clear bits if they're already high */
+}
+
+static int smi_irq_postinstall(struct drm_device *dev)
+{
+	return 0;
+}
+
+static void smi_irq_uninstall(struct drm_device *dev)
+{
+	/* Disable *all* interrupts */
+	if (g_specId == SPC_SM750) {
+		ddk750_disable_IntMask();
+	} else if (g_specId == SPC_SM768) {
+		ddk768_disable_IntMask();
+	}
+}
+#endif
+
+irqreturn_t smi_drm_interrupt(DRM_IRQ_ARGS)
+{
+	struct drm_device *dev = (struct drm_device *)arg;
+
+	int handled = 0;
+
+	if (g_specId == SPC_SM750) {
+		if (hw750_check_vsync_interrupt(0)) {
+			/* Clear the panel VSync Interrupt */
+			drm_handle_vblank(dev, 0);
+			handled = 1;
+			hw750_clear_vsync_interrupt(0);
+		}
+		if (hw750_check_vsync_interrupt(1)) {
+			drm_handle_vblank(dev, 1);
+			handled = 1;
+			hw750_clear_vsync_interrupt(1);
+		}
+	} else if (g_specId == SPC_SM768) {
+		if (hw768_check_vsync_interrupt(0)) {
+			/* Clear the panel VSync Interrupt */
+			drm_handle_vblank(dev, 0);
+			handled = 1;
+			hw768_clear_vsync_interrupt(0);
+		}
+		if (hw768_check_vsync_interrupt(1)) {
+			drm_handle_vblank(dev, 1);
+			handled = 1;
+			hw768_clear_vsync_interrupt(1);
+		}
+	}
+
+	if (handled)
+		return IRQ_HANDLED;
+	return IRQ_NONE;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+static int smi_dumb_create_align(struct drm_file *file, struct drm_device *dev,
+			     struct drm_mode_create_dumb *args)
+{
+	return drm_gem_vram_fill_create_dumb(file, dev, 0, 16, args);
+}
+#endif
+
+
+static const struct dev_pm_ops smi_pm_ops = {
+	.suspend = smi_pm_suspend,
+	.resume = smi_pm_resume,
+	.freeze = smi_pm_freeze,
+	.thaw = smi_pm_thaw,
+	.poweroff = smi_pm_poweroff,
+	.restore = smi_pm_resume,
+};
+
+static struct pci_driver smi_pci_driver = {
+	.name = DRIVER_NAME,
+	.id_table = pciidlist,
+	.probe = smi_pci_probe,
+	.remove = smi_pci_remove,
+	.driver.pm = &smi_pm_ops,
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+DEFINE_DRM_GEM_FOPS(smi_driver_fops);
+#else
+static const struct file_operations smi_driver_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	DRM_VRAM_MM_FILE_OPERATIONS,
+#else
+	.open = drm_open,
+	.release = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+	.mmap = smi_mmap,
+	.poll = drm_poll,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.read = drm_read,
+	.llseek = no_llseek,
+#endif
+	.owner = THIS_MODULE,
+};
+#endif
+
+static struct drm_driver driver = {
+	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC
+#if defined(PRIME) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+			   | DRIVER_PRIME
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
+			   | DRIVER_IRQ_SHARED
+#endif
+	,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+	.load = smi_driver_load,
+	.unload = smi_driver_unload,
+#endif
+	.fops = &smi_driver_fops,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESC,
+	.date = DRIVER_DATE,
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+	.debugfs_init             = drm_vram_mm_debugfs_init,
+	.dumb_create		  = smi_dumb_create_align,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	.dumb_map_offset		  = drm_gem_ttm_dumb_map_offset,
+#else
+	.dumb_map_offset		  = drm_gem_vram_driver_dumb_mmap_offset,
+#endif
+	.gem_prime_mmap		  = drm_gem_prime_mmap,
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	 DRM_GEM_VRAM_DRIVER,
+#else
+	.gem_free_object_unlocked = smi_gem_free_object,
+	.dumb_create = smi_dumb_create,
+	.dumb_map_offset = smi_dumb_mmap_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+	.enable_vblank = smi_enable_vblank,
+	.disable_vblank = smi_disable_vblank,
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+	.irq_preinstall = smi_irq_preinstall,
+	.irq_postinstall = smi_irq_postinstall,
+	.irq_uninstall = smi_irq_uninstall,
+	.irq_handler = smi_drm_interrupt,
+#endif
+	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	.gem_prime_import = drm_gem_prime_import,
+	.gem_prime_export = drm_gem_prime_export,
+	.gem_prime_vmap = smi_gem_prime_vmap,
+	.gem_prime_vunmap = smi_gem_prime_vunmap,
+	.gem_prime_pin = smi_gem_prime_pin,
+	.gem_prime_unpin = smi_gem_prime_unpin,
+	.gem_prime_get_sg_table = smi_gem_prime_get_sg_table,
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+	DRM_GEM_VRAM_DRIVER_PRIME,
+#endif
+	.gem_prime_import_sg_table = smi_gem_prime_import_sg_table,
+};
+
+static int __init smi_init(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
+        if (drm_firmware_drivers_only() && smi_modeset == -1)
+#else
+        if (vgacon_text_force() && smi_modeset == -1)
+#endif
+		return -EINVAL;
+
+	if (smi_modeset == 0)
+		return -EINVAL;
+	return pci_register_driver(&smi_pci_driver);
+}
+
+static void __exit smi_exit(void)
+{
+	pci_unregister_driver(&smi_pci_driver);
+}
+
+module_init(smi_init);
+module_exit(smi_exit);
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(_version_);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
+MODULE_IMPORT_NS(DMA_BUF);
+#endif
+
diff --git a/drivers/gpu/drm/smifb2/smi_drv.h b/drivers/gpu/drm/smifb2/smi_drv.h
new file mode 100644
index 000000000000..1e5c88c0d989
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_drv.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+#ifndef __SMI_DRV_H__
+#define __SMI_DRV_H__
+
+#include <linux/version.h>
+
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem.h>
+#include <video/vga.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+#include <drm/drmP.h>
+#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_memory.h>
+#include <drm/ttm/ttm_module.h>
+#include <drm/ttm/ttm_placement.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+#include <drm/drm_gem_vram_helper.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+#include <drm/drm_vram_mm_helper.h>
+#endif
+#endif
+
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c.h>
+
+#include "smi_priv.h"
+
+#define DRIVER_AUTHOR "SiliconMotion"
+
+#define DRIVER_NAME		"smifb"
+#define DRIVER_DESC		"SiliconMotion GPU DRM Driver"
+#define DRIVER_DATE		"20230201"
+
+#define DRIVER_MAJOR		2
+#define DRIVER_MINOR		2
+#define DRIVER_PATCHLEVEL	2
+
+#define SMIFB_CONN_LIMIT 3
+
+
+
+#define RELEASE_TYPE "Linux DRM Display Driver Release"
+#define SUPPORT_CHIP " SM750, SM768"
+
+
+#define _version_	"2.2.2.0"
+
+#undef  NO_WC
+
+#ifdef CONFIG_CPU_LOONGSON3
+#define NO_WC
+#endif
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_##x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#elif defined(__cplusplus)
+#define UNUSED(x)
+#else
+#define UNUSED(x) x
+#endif
+
+#define SMI_MAX_FB_HEIGHT 8192
+#define SMI_MAX_FB_WIDTH 8192
+
+#define smi_DPMS_CLEARED (-1)
+
+extern int g_specId;
+extern int smi_pat;
+extern int smi_bpp;
+extern int force_connect;
+extern int lvds_channel;
+extern int audio_en;
+extern int fixed_width;
+extern int fixed_height;
+extern int hwi2c_en;
+extern int swcur_en;
+extern int edid_mode;
+extern int lcd_scale;
+extern int pwm_ctrl;
+
+struct smi_750_register;
+struct smi_768_register;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+#endif
+
+
+struct smi_device {
+	struct drm_device *dev;
+	struct snd_card 		*card;	
+	unsigned long flags;
+
+	resource_size_t rmmio_base;
+	resource_size_t rmmio_size;
+	void __iomem *rmmio;
+
+	struct smi_mc mc;
+	struct smi_mode_info mode_info;
+
+	int num_crtc;
+	int fb_mtrr;
+	bool need_dma32;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	struct {
+		struct ttm_bo_device bdev;
+	} ttm;
+#endif
+	bool mm_inited;
+	union {
+		struct smi_750_register *regsave;
+		struct smi_768_register *regsave_768;
+	};
+#ifdef USE_HDMICHIP
+	struct edid si9022_edid[2];
+#endif
+	void *dvi_edid;
+	void *vga_edid;
+	void *hdmi_edid;
+	struct drm_display_mode *fixed_mode;
+	bool is_hdmi;
+	bool is_boot_gpu;
+};
+
+struct smi_encoder {
+	struct drm_encoder base;
+	int last_dpms;
+};
+
+struct smi_connector {
+	struct drm_connector base;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data bit_data;
+	unsigned char i2c_scl;
+	unsigned char i2c_sda;
+	unsigned char i2cNumber;
+	bool i2c_hw_enabled;
+};
+
+static inline struct smi_connector *to_smi_connector(struct drm_connector *connector)
+{
+	return container_of(connector, struct smi_connector, base);
+}
+
+#define MAX_CRTC 2
+#define MAX_ENCODER 3
+
+/* smi_main.c */
+int smi_device_init(struct smi_device *cdev, struct drm_device *ddev, struct pci_dev *pdev,
+		    uint32_t flags);
+void smi_device_fini(struct smi_device *cdev);
+int smi_driver_load(struct drm_device *dev, unsigned long flags);
+void smi_driver_unload(struct drm_device *dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+int smi_dumb_create(struct drm_file *file, struct drm_device *dev,
+		    struct drm_mode_create_dumb *args);
+int smi_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle,
+			 uint64_t *offset);
+int smi_dumb_destroy(struct drm_file *file, struct drm_device *dev, uint32_t handle);
+void smi_gem_free_object(struct drm_gem_object *obj);
+#endif
+
+/* smi_plane.c */
+struct drm_plane *smi_plane_init(struct smi_device *cdev, unsigned int possible_crtcs,
+				 enum drm_plane_type type);
+
+/* smi_mode.c */
+int smi_modeset_init(struct smi_device *cdev);
+void smi_modeset_fini(struct smi_device *cdev);
+int smi_calc_hdmi_ctrl(int m_connector);
+
+#define to_smi_crtc(x) container_of(x, struct smi_crtc, base)
+#define to_smi_encoder(x) container_of(x, struct smi_encoder, base)
+
+
+/* smi_ttm.c */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+struct smi_bo {
+	struct ttm_buffer_object bo;
+	struct ttm_placement placement;
+	struct ttm_bo_kmap_obj kmap;
+	struct drm_gem_object gem;
+	struct ttm_place placements[3];
+	int pin_count;
+};
+#define gem_to_smi_bo(gobj) container_of((gobj), struct smi_bo, gem)
+
+static inline struct smi_bo *smi_bo(struct ttm_buffer_object *bo)
+{
+	return container_of(bo, struct smi_bo, bo);
+}
+int smi_bo_create(struct drm_device *dev, int size, int align, uint32_t flags, struct sg_table *sg,
+		  struct reservation_object *resv, struct smi_bo **psmibo);
+void smi_ttm_placement(struct smi_bo *bo, int domain);
+void smi_bo_ttm_destroy(struct ttm_buffer_object *tbo);
+int smi_mmap(struct file *filp, struct vm_area_struct *vma);
+int smi_bo_pin(struct smi_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int smi_bo_unpin(struct smi_bo *bo);
+void *smi_bo_kmap(struct smi_bo *bo, bool map, bool *is_iomem);
+void smi_bo_kunmap(struct smi_bo *bo);
+#endif
+int smi_mm_init(struct smi_device *smi);
+void smi_mm_fini(struct smi_device *smi);
+
+/* smi_prime.c */
+struct sg_table *smi_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *smi_gem_prime_import_sg_table(struct drm_device *dev,
+						     struct dma_buf_attachment *attach,
+						     struct sg_table *sg);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+void *smi_gem_prime_vmap(struct drm_gem_object *obj);
+void smi_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int smi_gem_prime_pin(struct drm_gem_object *obj);
+void smi_gem_prime_unpin(struct drm_gem_object *obj);
+#endif
+
+
+int smi_audio_init(struct drm_device *dev);
+void smi_audio_remove(struct drm_device *dev);
+
+void smi_audio_suspend(void);
+void smi_audio_resume(void);
+
+#ifndef DRM_IRQ_ARGS
+#define DRM_IRQ_ARGS int irq, void *arg
+#endif
+
+irqreturn_t smi_drm_interrupt(DRM_IRQ_ARGS);
+
+
+
+#define smi_LUT_SIZE 256
+#define PALETTE_INDEX 0x8
+#define PALETTE_DATA 0x9
+
+#define USE_DVI 1
+#define USE_VGA (1 << 1)
+#define USE_HDMI (1 << 2)
+#define USE_DVI_VGA (USE_DVI | USE_VGA)
+#define USE_DVI_HDMI (USE_DVI | USE_HDMI)
+#define USE_VGA_HDMI (USE_VGA | USE_HDMI)
+#define USE_ALL (USE_DVI | USE_VGA | USE_HDMI)
+
+/* please use revision id to distinguish sm750le and sm750*/
+#define SPC_SM750 	0
+#define SPC_SM712 	1
+#define SPC_SM502   2
+#define SPC_SM768   3
+//#define SPC_SM750LE 8
+
+#define PCI_VENDOR_ID_SMI 	0x126f
+#define PCI_DEVID_LYNX_EXP	0x0750
+#define PCI_DEVID_SM768		0x0768
+
+
+#define BPP32_RED    0x00ff0000
+#define BPP32_GREEN  0x0000ff00
+#define BPP32_BLUE   0x000000ff
+#define BPP32_WHITE  0x00ffffff
+#define BPP32_GRAY   0x00808080
+#define BPP32_YELLOW 0x00ffff00
+#define BPP32_CYAN   0x0000ffff
+#define BPP32_PINK   0x00ff00ff
+#define BPP32_BLACK  0x00000000
+
+
+#define BPP16_RED    0x0000f800
+#define BPP16_GREEN  0x000007e0
+#define BPP16_BLUE   0x0000001f
+#define BPP16_WHITE  0x0000ffff
+#define BPP16_GRAY   0x00008410
+#define BPP16_YELLOW 0x0000ffe0
+#define BPP16_CYAN   0x000007ff
+#define BPP16_PINK   0x0000f81f
+#define BPP16_BLACK  0x00000000
+
+#endif				/* __SMI_DRV_H__ */
diff --git a/drivers/gpu/drm/smifb2/smi_main.c b/drivers/gpu/drm/smifb2/smi_main.c
new file mode 100644
index 000000000000..c4942a764098
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_main.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+#include "smi_drv.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+#include <drm/drm_pci.h>
+#else
+#include <linux/pci.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+#include <drm/drm_irq.h>
+#endif
+
+#include <drm/drm_vblank.h>
+#else
+#include <drm/drmP.h>
+#endif
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fourcc.h>
+#include <linux/dma-buf.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+#include <drm/drm_probe_helper.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
+#include <drm/drm_framebuffer.h>
+#endif
+
+#include "hw750.h"
+#include "hw768.h"
+#include "smi_dbg.h"
+
+#define MB(x) (x << 20) /* Macro for Mega Bytes */
+
+
+static int smi_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file,
+				      unsigned flags, unsigned color, struct drm_clip_rect *clips,
+				      unsigned num_clips);
+
+
+static struct drm_framebuffer *smi_user_framebuffer_create(struct drm_device *dev,
+							   struct drm_file *filp,
+							   const struct drm_mode_fb_cmd2 *mode_cmd);
+
+static const struct drm_framebuffer_funcs smi_fb_funcs = {
+	.create_handle = drm_gem_fb_create_handle,
+	.destroy = drm_gem_fb_destroy,
+	.dirty = smi_user_framebuffer_dirty,
+
+};
+
+static const struct drm_mode_config_helper_funcs smi_mode_config_helper_funcs = {
+	.atomic_commit_tail = drm_atomic_helper_commit_tail,
+};
+
+static const struct drm_mode_config_funcs smi_mode_config_funcs = {
+	.fb_create = smi_user_framebuffer_create,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static bool smi_merge_clips(struct drm_clip_rect *dst, struct drm_clip_rect *src,
+			    unsigned int num_clips, unsigned int flags, u32 max_width,
+			    u32 max_height)
+{
+	unsigned int i;
+
+	if (!src || !num_clips) {
+		dst->x1 = 0;
+		dst->x2 = max_width;
+		dst->y1 = 0;
+		dst->y2 = max_height;
+		return true;
+	}
+
+	dst->x1 = ~0;
+	dst->y1 = ~0;
+	dst->x2 = 0;
+	dst->y2 = 0;
+
+	for (i = 0; i < num_clips; i++) {
+		if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY)
+			i++;
+		dst->x1 = min(dst->x1, src[i].x1);
+		dst->x2 = max(dst->x2, src[i].x2);
+		dst->y1 = min(dst->y1, src[i].y1);
+		dst->y2 = max(dst->y2, src[i].y2);
+	}
+
+	if (dst->x2 > max_width || dst->y2 > max_height || dst->x1 >= dst->x2 ||
+	    dst->y1 >= dst->y2) {
+		DRM_DEBUG_KMS("Illegal clip: x1 = %u, x2 = %u, y1 = %u, y2 = %u\n", dst->x1,
+			      dst->x2, dst->y1, dst->y2);
+		dst->x1 = 0;
+		dst->x2 = max_width;
+		dst->y1 = 0;
+		dst->y2 = max_height;
+	}
+
+	return (dst->x2 - dst->x1) == max_width && (dst->y2 - dst->y1) == max_height;
+}
+
+static int smi_handle_damage(struct drm_framebuffer *fb, struct drm_clip_rect clip)
+{
+	bool kmap = false;
+	int i, ret = 0;
+	unsigned long offset = 0;
+	void *dst = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *dst_bo = NULL;
+#endif
+	struct drm_gem_object *obj = fb->obj[0];
+	void *src = NULL;
+	unsigned bytesPerPixel = fb->format->cpp[0];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
+	struct iosys_map src_map,dst_map;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+	struct dma_buf_map src_map,dst_map;
+#endif
+
+	if (!obj->import_attach) {
+		return (-EINVAL);
+	}
+
+	if (!src) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+		ret = dma_buf_vmap(obj->import_attach->dmabuf, &src_map);
+		if (ret) {
+				DRM_ERROR("Failed to vmap src buffer\n");
+				return (0);
+		}
+		src = src_map.vaddr;
+#else
+		src = dma_buf_vmap(obj->import_attach->dmabuf);
+		if (!src)
+			return (0);
+#endif
+
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	gbo = drm_gem_vram_of_gem(obj);
+	ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
+	if (ret)
+		return (0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+	ret = drm_gem_vram_vmap(gbo, &dst_map);
+				
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+	dst = drm_gem_vram_vmap(gbo);
+#else
+	dst = drm_gem_vram_kmap(gbo, false, NULL);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+	if (ret) {
+		DRM_ERROR("failed to map vram\n");
+		goto error;
+	}
+	dst = dst_map.vaddr;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+	if (IS_ERR(dst)) {
+
+		DRM_ERROR("failed to map vram\n");
+		goto error;
+	} else if (!dst) {
+		dst = drm_gem_vram_vmap(gbo);
+		if (IS_ERR(dst)) {
+			DRM_ERROR("failed to kmap vram\n");
+			goto error;
+		}
+	}        
+#else
+	if (IS_ERR(dst)) {
+
+		DRM_ERROR("failed to map vram\n");
+		goto error;
+	} else if (!dst) {
+		dst = drm_gem_vram_kmap(gbo, true, NULL);
+		if (IS_ERR(dst)) {
+			DRM_ERROR("failed to kmap vram\n");
+			goto error;
+		}
+		kmap = true;
+	}
+#endif
+
+
+
+#else
+	dst_bo = gem_to_smi_bo(obj);
+	if (!dst_bo->pin_count) {
+		ret = smi_bo_pin(dst_bo, TTM_PL_FLAG_VRAM, NULL);
+		if (ret)
+			return (0);
+	}
+
+	dst = smi_bo_kmap(dst_bo, false, NULL);
+	if (IS_ERR(dst)) {
+		DRM_ERROR("failed to kmap vram\n");
+		goto error;
+	} else if (!dst) {
+		dst = smi_bo_kmap(dst_bo, true, NULL);
+		if (IS_ERR(dst)) {
+			DRM_ERROR("failed to kmap vram\n");
+			goto error;
+		}
+		kmap = true;
+	}
+#endif
+
+	dbg_msg("src: %p, dst: %p, x=%d, y=%d, fbwidth=%d, fbheight=%d, "
+		"width=%d, height=%d, bpp = %u, pitch=%d\n",
+		src, dst, clip.x1, clip.y1, fb->width, fb->height, clip.x2 - clip.x1,
+		clip.y2 - clip.y1, (bytesPerPixel << 3), fb->pitches[0]);
+
+	for (i = clip.y1; i < clip.y2; i++) {
+		offset = i * fb->pitches[0] + (clip.x1 * bytesPerPixel);
+		memcpy_toio(dst + offset, src + offset, (clip.x2 - clip.x1) * bytesPerPixel);
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	if (kmap)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
+		drm_gem_vram_vunmap(gbo, dst);
+#else	
+		drm_gem_vram_kunmap(gbo);
+#endif
+#else
+	if (kmap)
+		smi_bo_kunmap(dst_bo);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)	
+	dma_buf_vunmap(obj->import_attach->dmabuf, &src_map);
+#else
+    dma_buf_vunmap(obj->import_attach->dmabuf, src);
+#endif
+
+error:
+	return (0);
+}
+
+static int smi_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file,
+				      unsigned flags, unsigned color, struct drm_clip_rect *clips,
+				      unsigned num_clips)
+{
+	struct drm_gem_object *obj = fb->obj[0];
+	struct drm_clip_rect clip;
+
+	drm_modeset_lock_all(fb->dev);
+
+	if (obj->import_attach) {
+		int ret = dma_buf_begin_cpu_access(obj->import_attach->dmabuf, DMA_FROM_DEVICE);
+		if (ret)
+			goto unlock;
+	}
+
+	smi_merge_clips(&clip, clips, num_clips, flags, fb->width, fb->height);
+	smi_handle_damage(fb, clip);
+
+	if (obj->import_attach) {
+		dma_buf_end_cpu_access(obj->import_attach->dmabuf, DMA_FROM_DEVICE);
+	}
+
+unlock:
+	drm_modeset_unlock_all(fb->dev);
+
+	return 0;
+}
+
+
+static struct drm_framebuffer *smi_user_framebuffer_create(struct drm_device *dev,
+							   struct drm_file *filp,
+							   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	return (drm_gem_fb_create_with_funcs(dev, filp, mode_cmd, &smi_fb_funcs));
+}
+
+/*
+ * Functions here will be called by the core once it's bound the driver to
+ * a PCI device
+ */
+int smi_driver_load(struct drm_device *dev, unsigned long flags)
+{
+	struct smi_device *cdev;
+	struct pci_dev *pdev; 
+	int r, nr;
+	
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+	cdev = kzalloc(sizeof(struct smi_device), GFP_KERNEL);
+	if (cdev == NULL)
+		return -ENOMEM;
+	dev->dev_private = (void *)cdev;
+
+	switch (pdev->device) {
+	case PCI_DEVID_LYNX_EXP:
+		g_specId = SPC_SM750;
+		break;
+	case PCI_DEVID_SM768:
+		g_specId = SPC_SM768;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	r = pci_enable_device(pdev);
+
+	r = smi_device_init(cdev, dev, pdev, flags);
+	if (r) {
+		dev_err(&pdev->dev, "Fatal error during GPU init: %d\n", r);
+		goto out;
+	}
+	if(g_specId == SPC_SM750)
+	{
+	    if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
+			cdev->is_boot_gpu = true;
+		}
+		ddk750_initChip();
+		ddk750_deInit();
+		
+#ifdef USE_HDMICHIP
+		if((r = sii9022xInitChip()) < 0)
+		{	
+			printk("Init HDMI-Tx chip failed!");
+			r = 0;	
+		}
+#endif
+#ifdef USE_EP952
+		EP_HDMI_Init(0);
+		EP_HDMI_Set_Video_Timing(1,0);
+#endif
+
+	}
+	else
+	{
+		ddk768_initChip();
+		ddk768_deInit();
+		hw768_init_hdmi();
+#ifdef USE_EP952
+		EP_HDMI_Init(1);
+		EP_HDMI_Set_Video_Timing(1,1);
+#endif
+		
+		if(audio_en)
+			smi_audio_init(dev);
+
+	}	
+	
+
+
+	r = smi_mm_init(cdev);
+	if (r) {
+		dev_err(&pdev->dev, "fatal err on mm init\n");
+		goto out;
+	}
+
+	drm_vblank_init(dev, dev->mode_config.num_crtc);
+
+	nr = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+	if (nr <= 0)
+		dev_err(&pdev->dev, "pci allocate irq failed\n");
+
+	pdev->irq = pci_irq_vector(pdev, 0);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+	r = drm_irq_install(dev, pdev->irq);
+#else
+	r = request_irq(pdev->irq, smi_drm_interrupt, IRQF_SHARED,
+				  KBUILD_MODNAME, dev);
+#endif
+	if (r)
+		DRM_ERROR("install irq failed , ret = %d\n", r);
+
+	dev->mode_config.funcs = (void *)&smi_mode_config_funcs;
+	r = smi_modeset_init(cdev);
+	if (r) {
+		DRM_ERROR("Fatal error during modeset init: %d\n", r);
+		goto out;
+	}
+
+	cdev->regsave = vmalloc(1024);
+	if (!cdev->regsave) {
+		DRM_ERROR("cannot allocate regsave\n");
+		//return -ENOMEM;
+	}
+
+	drm_kms_helper_poll_init(dev);
+
+	return 0;
+out:
+	if (r)
+		smi_driver_unload(dev);
+	return r;
+}
+
+void smi_driver_unload(struct drm_device *dev)
+{
+	struct smi_device *cdev = dev->dev_private;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
+	struct pci_dev *pdev = to_pci_dev(dev->dev);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+#else
+	free_irq(pdev->irq, dev);
+	/* Disable *all* interrupts */
+	if (g_specId == SPC_SM750) {
+		ddk750_disable_IntMask();
+	} else if (g_specId == SPC_SM768) {
+		ddk768_disable_IntMask();
+	}
+#endif
+
+	if (cdev == NULL)
+		return;
+
+	smi_modeset_fini(cdev);
+	smi_mm_fini(cdev);
+	smi_device_fini(cdev);
+
+	if(g_specId == SPC_SM768)
+	{
+		if(audio_en)
+			smi_audio_remove(dev);
+
+    }
+
+
+	vfree(cdev->regsave);
+	kfree(cdev);
+	dev->dev_private = NULL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+int smi_gem_create(struct drm_device *dev, u32 size, bool iskernel, struct drm_gem_object **obj)
+{
+	struct smi_bo *smibo;
+	int ret;
+
+	*obj = NULL;
+
+	size = roundup(size, PAGE_SIZE);
+	if (size == 0)
+		return (-EINVAL);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	ret = smi_bo_create(dev, size, 0, 0, NULL, NULL, &smibo);
+#endif
+
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object\n");
+		return (ret);
+	}
+
+	*obj = &smibo->gem;
+	return (0);
+}
+
+int smi_dumb_create(struct drm_file *file, struct drm_device *dev,
+		    struct drm_mode_create_dumb *args)
+{
+	int ret;
+	struct drm_gem_object *gobj;
+	u32 handle;
+
+	args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 16);
+
+	args->size = roundup(args->pitch * args->height, PAGE_SIZE);
+
+	ret = smi_gem_create(dev, args->size, false, &gobj);
+	if (ret)
+		return (ret);
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_put_unlocked(gobj);
+	if (ret)
+		return (ret);
+
+	args->handle = handle;
+	return (0);
+}
+
+static inline u64 smi_bo_mmap_offset(struct smi_bo *bo)
+{
+	return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+int smi_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle,
+			 uint64_t *offset)
+{
+	struct drm_gem_object *obj;
+	struct smi_bo *bo;
+	obj = drm_gem_object_lookup(file, handle);
+	if (obj == NULL)
+		return -ENOENT;
+
+	bo = gem_to_smi_bo(obj);
+	*offset = smi_bo_mmap_offset(bo);
+
+	drm_gem_object_put_unlocked(obj);
+	return 0;
+}
+
+void smi_bo_unref(struct smi_bo **bo)
+{
+	struct ttm_buffer_object *tbo;
+
+	if ((*bo) == NULL)
+		return;
+
+	tbo = &((*bo)->bo);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+	ttm_bo_put(tbo);
+#else
+	ttm_bo_unref(&tbo);
+	if (tbo == NULL)
+#endif
+	{
+		*bo = NULL;
+	}
+}
+
+void smi_gem_free_object(struct drm_gem_object *obj)
+{
+	struct smi_bo *smi_bo = gem_to_smi_bo(obj);
+
+	if (smi_bo) {
+		if (smi_bo->gem.import_attach)
+			drm_prime_gem_destroy(&smi_bo->gem, smi_bo->bo.sg);
+		smi_bo_unref(&smi_bo);
+	}
+}
+#endif
+
+/* Unmap the framebuffer from the core and release the memory */
+static void smi_vram_fini(struct smi_device *cdev)
+{
+	iounmap(cdev->rmmio);
+	cdev->rmmio = NULL;
+
+}
+
+/* Map the framebuffer from the card and configure the core */
+static int smi_vram_init(struct smi_device *cdev)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	struct pci_dev *pdev = to_pci_dev(cdev->dev->dev);
+	/* BAR 0 is VRAM */
+	cdev->mc.vram_base = pci_resource_start(pdev, 0);
+#else	
+	/* BAR 0 is VRAM */
+	cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
+#endif
+
+	/* VRAM Size */
+	if (g_specId == SPC_SM750)
+		cdev->mc.vram_size = ddk750_getFrameBufSize();
+	else
+		cdev->mc.vram_size = ddk768_getFrameBufSize();
+
+	return 0;
+}
+
+/*
+ * SMI Graphics has two sets of memory. One is video RAM and can
+ * simply be used as a linear framebuffer - the other provides mmio access
+ * to the display registers. The latter can also be accessed via IO port
+ * access, but we map the range and use mmio to program them instead
+ */
+
+int smi_device_init(struct smi_device *cdev, struct drm_device *ddev, struct pci_dev *pdev,
+		    uint32_t flags)
+{
+	int ret, dma_bits;
+
+	cdev->dev = ddev;
+	cdev->flags = flags;
+
+	/* Hardcode the number of CRTCs to 2 */
+	cdev->num_crtc = 2;
+
+	dma_bits = 40;
+	cdev->need_dma32 = false;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
+	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(dma_bits));
+#else
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_bits));
+#endif
+	if (ret) {
+		cdev->need_dma32 = true;
+		dma_bits = 32;
+		printk(KERN_WARNING "smifb: No suitable DMA available.\n");
+	}
+
+#if 0
+	ret = pci_set_consistent_dma_mask(cdev->dev->pdev, DMA_BIT_MASK(dma_bits));
+	if (ret) {
+		pci_set_consistent_dma_mask(cdev->dev->pdev, DMA_BIT_MASK(32));
+		printk(KERN_WARNING "smifb: No coherent DMA available.\n");
+	}
+#endif
+
+	/* BAR 0 is the framebuffer, BAR 1 contains registers */
+	cdev->rmmio_base = pci_resource_start(pdev, 1);
+	cdev->rmmio_size = pci_resource_len(pdev, 1);
+	cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size);
+
+	if (cdev->rmmio == NULL)
+		return -ENOMEM;
+
+	if (g_specId == SPC_SM750)
+		ddk750_set_mmio(cdev->rmmio, pdev->device, pdev->revision);
+	else
+		ddk768_set_mmio(cdev->rmmio, pdev->device, pdev->revision);
+
+	ret = smi_vram_init(cdev);
+	if (ret) {
+		return ret;
+	}
+
+	return 0;
+}
+
+void smi_device_fini(struct smi_device *cdev)
+{
+	smi_vram_fini(cdev);
+}
diff --git a/drivers/gpu/drm/smifb2/smi_mode.c b/drivers/gpu/drm/smifb2/smi_mode.c
new file mode 100644
index 000000000000..c5e1a72e9c4e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_mode.c
@@ -0,0 +1,1247 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+#include "smi_drv.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+#include <drm/drm_fourcc.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+#include <drm/drm_pci.h>
+#else
+#include <linux/pci.h>
+#endif
+#include <drm/drm_vblank.h>
+#else
+#include <drm/drmP.h>
+#endif
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+#include <drm/drm_probe_helper.h>
+#endif
+
+
+#include "hw750.h"
+#include "hw768.h"
+#include "ddk768/ddk768_video.h"
+#include "ddk768/ddk768_chip.h"
+#include "smi_dbg.h"
+
+
+struct smi_crtc * smi_crtc_tab[MAX_CRTC];
+struct drm_encoder * smi_enc_tab[MAX_ENCODER];
+
+//bit 0: DVI, bit 1: VGA, bit 2: HDMI.
+int g_m_connector = 0;
+
+int smi_calc_hdmi_ctrl(int m_connector)
+{
+		int smi_ctrl = 0;
+
+		if(m_connector==USE_DVI_HDMI) // //vga is empty, dvi is occupied , HDMI use ctrl 1;
+			smi_ctrl = 1;
+		else
+			smi_ctrl = 0;
+			
+		return smi_ctrl;
+
+}
+
+static int smi_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g,
+				u16 *b, uint32_t size,
+				struct drm_modeset_acquire_ctx *ctx)
+{
+	
+	struct smi_crtc *smi_crtc = to_smi_crtc(crtc); 
+	int i , max_index = 2, ctrl_index, dst_ctrl;
+	ctrl_index = 0;
+	dst_ctrl = 0;
+
+	if(g_specId == SPC_SM768)
+		max_index = MAX_ENCODER;
+
+		
+	for(i = 0;i < max_index; i++)
+	{
+		if(crtc == smi_enc_tab[i]->crtc)
+		{
+			ctrl_index = i;
+			break;
+		}
+	}
+	
+	dst_ctrl = (ctrl_index == SMI1_CTRL)?SMI1_CTRL:SMI0_CTRL;
+
+	if(ctrl_index > SMI1_CTRL)
+	{
+		dst_ctrl= smi_calc_hdmi_ctrl(g_m_connector);
+	}
+
+
+	for (i = 0; i < crtc->gamma_size; i++)
+	{
+		smi_crtc->lut_r[i] = r[i] >> 8;
+		smi_crtc->lut_g[i] = g[i] >> 8;
+		smi_crtc->lut_b[i] = b[i] >> 8;
+	}
+
+
+	if (g_specId == SPC_SM768) {
+		hw768_setgamma(dst_ctrl, true , lvds_channel);
+		hw768_load_lut(dst_ctrl, crtc->gamma_size, smi_crtc->lut_r, smi_crtc->lut_g, smi_crtc->lut_b);
+	
+	}else if(g_specId == SPC_SM750) {
+		hw750_setgamma(dst_ctrl, true);
+		hw750_load_lut(dst_ctrl, crtc->gamma_size, smi_crtc->lut_r, smi_crtc->lut_g, smi_crtc->lut_b);
+	}
+	
+	return 0;
+}
+
+/*
+ * The DRM core requires DPMS functions, but they make little sense in our
+ * case and so are just stubs
+ */
+
+static void smi_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	
+	struct drm_display_mode *mode;
+	struct smi_device *sdev = crtc->dev->dev_private;
+	logicalMode_t logicalMode;
+	unsigned long refresh_rate;
+	unsigned int need_to_scale = 0;
+	YUV_BUF_ADDR SrcAddr;
+	BLIT_BLK src;
+	BLIT_BLK dest;
+
+	ENTER();
+	
+	logicalMode.valid_edid = false;
+
+	if (WARN_ON(!crtc->state))
+		LEAVE();
+
+	mode = &crtc->state->adjusted_mode;
+	refresh_rate = drm_mode_vrefresh(mode);
+
+	dbg_msg("***crtc addr:%p\n", crtc);
+
+	dbg_msg("encode->crtc:[%p, %p, %p] \n", smi_enc_tab[0]->crtc, smi_enc_tab[1]->crtc,
+		smi_enc_tab[2] == NULL ? NULL : smi_enc_tab[2]->crtc);
+	dbg_msg("g_m_connector = %d,  DVI [%d], VGA[%d], HDMI[%d] \n", g_m_connector,
+		g_m_connector & 0x1, g_m_connector & 0x2, g_m_connector & 0x4);
+
+	dbg_msg("wxh:%dx%d@%ldHz\n", mode->hdisplay, mode->vdisplay, refresh_rate);
+
+	if (g_specId == SPC_SM750) {
+			if(crtc == smi_enc_tab[0]->crtc)
+		{
+			logicalMode.baseAddress = 0;
+			logicalMode.x = mode->hdisplay;
+			logicalMode.y = mode->vdisplay;
+			logicalMode.bpp = smi_bpp;
+			logicalMode.dispCtrl = SMI0_CTRL;
+			logicalMode.hz = refresh_rate;
+			logicalMode.pitch = 0;
+
+			setMode(&logicalMode);
+
+			setDisplayControl(SMI0_CTRL, DISP_ON);           /* Turn on Primary Control */
+			setPath(SMI0_PATH, SMI0_CTRL, DISP_ON);     /* Turn on Panel Path and use Primary data */
+			
+		}
+		if(crtc == smi_enc_tab[1]->crtc)
+		{
+			logicalMode.baseAddress = 0;
+			logicalMode.x = mode->hdisplay;
+			logicalMode.y = mode->vdisplay;
+			logicalMode.bpp = smi_bpp;
+			logicalMode.dispCtrl = SMI1_CTRL;
+			logicalMode.hz = refresh_rate;
+			logicalMode.pitch = 0;
+			setMode(&logicalMode);
+
+			setDisplayControl(SMI1_CTRL, DISP_ON);         /* Turn on Secondary control */
+			setPath(SMI1_PATH, SMI1_CTRL, DISP_ON);     /* Turn on CRT Path and use Secondary data */
+			
+		}
+		
+		swPanelPowerSequence(DISP_ON, 4);                   /* Turn on Panel */
+	    setDAC(DISP_ON);                                    /* Turn on DAC */
+
+#ifdef USE_HDMICHIP
+		printk("HDMI set mode\n");
+		sii9022xSetMode(5);
+#endif
+
+	}
+	else {
+		int i, ctrl_index, dst_ctrl;
+		ctrl_index = 0;
+		dst_ctrl = 0;
+		for(i = 0;i < MAX_ENCODER; i++)
+		{
+			if(crtc == smi_enc_tab[i]->crtc)
+			{
+				ctrl_index = i;
+				break;
+			}
+		}
+
+		dst_ctrl = (ctrl_index == SMI1_CTRL)?SMI1_CTRL:SMI0_CTRL;
+		
+		if(ctrl_index > SMI1_CTRL)
+		{
+			dst_ctrl=smi_calc_hdmi_ctrl(g_m_connector);
+			dbg_msg("hdmi use channel %d\n",dst_ctrl);
+	
+		}
+		
+		logicalMode.baseAddress = 0;
+		logicalMode.x = mode->hdisplay;
+		logicalMode.y = mode->vdisplay;
+		logicalMode.bpp = smi_bpp;
+		logicalMode.hz = refresh_rate;
+		logicalMode.pitch = 0;
+		logicalMode.dispCtrl = dst_ctrl;
+
+		switch (ctrl_index)
+		{
+			case 0:
+				if (sdev->dvi_edid && drm_edid_header_is_valid((u8 *)sdev->dvi_edid) == 8)
+					logicalMode.valid_edid = true;
+				break;
+			case 1:
+				if (sdev->vga_edid && drm_edid_header_is_valid((u8 *)sdev->vga_edid) == 8)
+					logicalMode.valid_edid = true;
+				break;
+			case 2:
+				if (sdev->hdmi_edid && drm_edid_header_is_valid((u8 *)sdev->hdmi_edid) == 8)
+					logicalMode.valid_edid = true;
+				break;
+			default:
+				break;
+		}
+		if(edid_mode == 0){
+			printk("Use Driver build-in mode timing\n");
+			logicalMode.valid_edid = false;
+		}
+
+		if(lcd_scale && (dst_ctrl == 0) && (mode->hdisplay != fixed_width) && (mode->vdisplay != fixed_height) ){
+			need_to_scale = 1;
+		}
+		
+		if(need_to_scale){
+				 logicalMode.x = fixed_width;
+				 logicalMode.y = fixed_height;
+				 logicalMode.valid_edid = false;
+		 }
+		
+		hw768_setMode(&logicalMode, *mode);
+		DisableDoublePixel(0);
+		DisableDoublePixel(1);
+
+		if(need_to_scale)
+		{
+			file_format srcFormat;
+			if(logicalMode.bpp==16)
+				srcFormat = FFT_RGB565;
+			if(logicalMode.bpp==32)
+				srcFormat = FFT_RGBx888;
+		
+			src.Width = mode->hdisplay;
+			src.Height = mode->vdisplay;
+			src.Pitch = logicalMode.pitch;
+			dest.Width = logicalMode.x;  
+			dest.Height = logicalMode.y; 
+			dest.Pitch = logicalMode.pitch;   
+			dest.x = 0;
+			dest.y = 0;
+		
+			SrcAddr.bufYAddr = logicalMode.baseAddress;
+			SrcAddr.bufCbAddr = 0;
+			SrcAddr.bufCrAddr = 0;		
+			SM768_setOverlay(logicalMode.dispCtrl, &src, &SrcAddr, &dest, srcFormat);
+		}else{
+			stopVideo(dst_ctrl);
+		}
+		setSingleViewOn(dst_ctrl);
+
+		initDisplay();		
+
+		if(need_to_scale)
+			ddk768_setDisplayPlaneDisableOnly(dst_ctrl);
+#ifdef USE_EP952
+		hw768_SetPixelClockFormat(dst_ctrl,1);
+#else
+		if (ddk768_getPixelType())
+			hw768_SetPixelClockFormat(dst_ctrl, 1);
+		else
+			hw768_SetPixelClockFormat(dst_ctrl,0);
+#endif
+		if((g_m_connector & USE_HDMI)&&(ctrl_index > SMI1_CTRL))
+		{
+			int ret = 0;
+			printk("Starting init SM768 HDMI! Use Channel [%d]\n", dst_ctrl);
+			if(dst_ctrl == 0)
+				hw768_SetPixelClockFormat(dst_ctrl,0);
+			ret=hw768_set_hdmi_mode(&logicalMode, *mode, sdev->is_hdmi);
+			if (ret != 0)
+			{
+				printk("HDMI Mode not supported!\n");
+			}
+		}
+		
+
+		if(lvds_channel == 1){
+			printk("Use Single Channel LVDS\n");
+			hw768_enable_lvds(1);
+		}
+		else if(lvds_channel == 2){
+			printk("Use Dual Channel LVDS\n");
+			hw768_enable_lvds(2);
+			EnableDoublePixel(0);
+		}		
+
+	
+	}
+
+	LEAVE();
+}
+
+/* Simple cleanup function */
+static void smi_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct smi_crtc *smi_crtc = to_smi_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	kfree(smi_crtc);
+}
+
+
+static void smi_crtc_atomic_flush(struct drm_crtc *crtc, 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+	struct drm_atomic_state *state)
+#else
+	struct drm_crtc_state *old_state)
+#endif
+{
+	
+	unsigned long flags;
+	ENTER();
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	if (crtc->state->event)
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+	crtc->state->event = NULL;
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+	LEAVE();
+}
+
+static void smi_crtc_atomic_enable(struct drm_crtc *crtc, 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+		struct drm_atomic_state *state)
+#else
+		struct drm_crtc_state *old_state)
+#endif
+{
+	ENTER();
+	LEAVE();
+}
+
+static void smi_crtc_atomic_disable(struct drm_crtc *crtc, 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+		struct drm_atomic_state *state)
+#else
+		struct drm_crtc_state *old_state)
+#endif
+{
+	ENTER();
+	LEAVE();
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+static int smi_enable_vblank(struct drm_crtc *crtc)
+{
+	if (g_specId == SPC_SM750) {
+		hw750_en_dis_interrupt(1);
+	} else if (g_specId == SPC_SM768) {
+		hw768_en_dis_interrupt(1);
+	}
+	return 0;
+}
+
+static void smi_disable_vblank(struct drm_crtc *crtc)
+{
+	if (g_specId == SPC_SM750) {
+		hw750_en_dis_interrupt(0);
+	} else if (g_specId == SPC_SM768) {
+		hw768_en_dis_interrupt(0);
+	}
+}
+#endif
+
+
+
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs smi_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = smi_crtc_destroy,
+	.gamma_set = smi_crtc_gamma_set,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+	.enable_vblank = smi_enable_vblank,
+	.disable_vblank = smi_disable_vblank,
+#endif
+};
+
+static const struct drm_crtc_helper_funcs smi_crtc_helper_funcs = {
+	.mode_set_nofb = smi_crtc_mode_set_nofb,
+	.atomic_flush = smi_crtc_atomic_flush,
+	.atomic_enable = smi_crtc_atomic_enable,
+	.atomic_disable = smi_crtc_atomic_disable
+};
+
+
+/* CRTC setup */
+static struct smi_crtc *smi_crtc_init(struct drm_device *dev, int crtc_id)
+{
+	struct smi_device *cdev = dev->dev_private;
+	struct smi_crtc *smi_crtc;
+	struct drm_plane *primary = NULL, *cursor = NULL;
+	int r, i;
+
+	smi_crtc = kzalloc(sizeof(struct smi_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
+	if (smi_crtc == NULL)
+		return NULL;
+
+	primary = smi_plane_init(cdev, 1 << crtc_id, DRM_PLANE_TYPE_PRIMARY);
+
+	if (IS_ERR(primary)) {
+		r = -ENOMEM;
+		goto free_mem;
+	}
+
+	if(swcur_en)
+		cursor = NULL;
+	else{
+		cursor = smi_plane_init(cdev, 1 << crtc_id, DRM_PLANE_TYPE_CURSOR);
+		if (IS_ERR(cursor)) {
+			r = -ENOMEM;
+			goto clean_primary;
+		}
+	}
+	smi_crtc->CursorOffset = 0;
+
+	r = drm_crtc_init_with_planes(dev, &smi_crtc->base, primary, cursor, &smi_crtc_funcs, NULL);
+
+	if (r) {
+		goto clean_cursor;
+	}
+
+	drm_mode_crtc_set_gamma_size(&smi_crtc->base, 256);
+	
+	for (i = 0; i < smi_crtc->base.gamma_size; i++)
+	{
+		smi_crtc->lut_r[i] = smi_crtc->lut_g[i] = smi_crtc->lut_b[i] = i;
+	}
+	drm_crtc_helper_add(&smi_crtc->base, &smi_crtc_helper_funcs);
+	return smi_crtc;
+
+
+clean_cursor:
+	if (cursor) {
+		drm_plane_cleanup(cursor);
+		kfree(cursor);
+	}
+
+clean_primary:
+	drm_plane_cleanup(primary);
+	kfree(primary);
+free_mem:
+	kfree(smi_crtc);
+	return NULL;
+}
+
+
+
+static void smi_encoder_mode_set(struct drm_encoder *encoder,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void smi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	int index =0;
+	ENTER();
+	if (encoder->encoder_type  == DRM_MODE_ENCODER_LVDS)
+		index =  0;
+	else if (encoder->encoder_type  == DRM_MODE_ENCODER_DAC)
+		index =  1;
+	else if (encoder->encoder_type  == DRM_MODE_ENCODER_TMDS)
+		index = 2;
+	
+
+	dbg_msg("The current connect group = [%d], we deal with con=[%d], mode=[%s]\n", g_m_connector,index, (mode == DRM_MODE_DPMS_OFF)?"Off":"ON");
+	if(g_specId == SPC_SM750)
+	{	
+		if (mode == DRM_MODE_DPMS_OFF) {
+			dbg_msg("disable dpms, index=%d\n",index);
+			setDisplayControl(index, DISP_OFF); 
+		}else
+		{
+			setDisplayControl(index, DISP_ON); 
+			swPanelPowerSequence(DISP_ON, 4); 
+			dbg_msg("enable dpms ,index=%d\n",index);
+		}
+	}else if(g_specId == SPC_SM768)
+	{
+
+		if(encoder->encoder_type  == DRM_MODE_ENCODER_LVDS) 
+		{
+			if(g_m_connector == USE_VGA_HDMI||g_m_connector==USE_HDMI)
+			{
+				dbg_msg("DVI connector off\n");
+				LEAVE();
+			}
+			dbg_msg("DVI connector: index=%d\n",index);
+	
+		}
+		else if(encoder->encoder_type  == DRM_MODE_ENCODER_DAC)
+		{
+			if(g_m_connector == USE_DVI_HDMI)
+			{
+				dbg_msg("VGA connector off\n");
+				LEAVE();
+			}
+			dbg_msg("VGA connector: index=%d\n",index);
+		}
+		else if(encoder->encoder_type  == DRM_MODE_ENCODER_TMDS)
+		{	
+			if (mode == DRM_MODE_DPMS_OFF)	
+				hw768_HDMI_Disable_Output();
+			else
+				hw768_HDMI_Enable_Output();
+			if(g_m_connector == USE_DVI_HDMI){
+				index = SMI1_CTRL;
+			 	dbg_msg("HDMI connector: index=%d\n",index);
+			}
+			else if(g_m_connector == USE_VGA_HDMI || g_m_connector==USE_HDMI){
+				index = SMI0_CTRL;
+			 	dbg_msg("HDMI connector: index=%d\n",index);
+			}else{
+				dbg_msg("HDMI connector not set dpms\n");
+				LEAVE();
+			}
+		}
+		
+		if (mode == DRM_MODE_DPMS_OFF){
+			setDisplayDPMS(index, DISP_DPMS_OFF);
+			ddk768_swPanelPowerSequence(index, 0, 4);
+		}else{
+			setDisplayDPMS(index, DISP_DPMS_ON);
+			ddk768_swPanelPowerSequence(index, 1, 4);
+		}
+		
+		if(lvds_channel == 2)
+			EnableDoublePixel(0);
+
+	}
+	
+	LEAVE();
+}
+
+static void smi_encoder_prepare(struct drm_encoder *encoder)
+{
+	smi_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+}
+
+static void smi_encoder_commit(struct drm_encoder *encoder)
+{
+	smi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+}
+
+void smi_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct smi_encoder *smi_encoder = to_smi_encoder(encoder);
+	drm_encoder_cleanup(encoder);
+	kfree(smi_encoder);
+}
+
+static const struct drm_encoder_helper_funcs smi_encoder_helper_funcs = {
+	.dpms = smi_encoder_dpms,
+	.mode_set = smi_encoder_mode_set,
+	.prepare = smi_encoder_prepare,
+	.commit = smi_encoder_commit,
+};
+
+
+
+static const struct drm_encoder_funcs smi_encoder_encoder_funcs = {
+	.destroy = smi_encoder_destroy,
+};
+
+static struct drm_encoder *smi_encoder_init(struct drm_device *dev, int index)
+{
+	struct drm_encoder *encoder;
+	struct smi_encoder *smi_encoder;
+
+	smi_encoder = kzalloc(sizeof(struct smi_encoder), GFP_KERNEL);
+	if (!smi_encoder)
+		return NULL;
+
+	encoder = &smi_encoder->base;
+	encoder->possible_crtcs = (1 << index);
+
+	switch (index)
+	{
+		case 0:
+			//DVI,LVDS
+			drm_encoder_init(dev, encoder, &smi_encoder_encoder_funcs, DRM_MODE_ENCODER_LVDS, NULL);
+			break;
+		case 1:
+			//VGA
+			drm_encoder_init(dev, encoder, &smi_encoder_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL);
+			break;
+		case 2:
+			//HDMI
+            encoder->possible_crtcs = 0x3;
+			drm_encoder_init(dev, encoder, &smi_encoder_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
+			break;
+		default:
+			printk(KERN_ERR "Wrong connector index\n");
+	}
+
+	drm_encoder_helper_add(encoder, &smi_encoder_helper_funcs);
+ 	return encoder;
+}
+
+
+int smi_connector_get_modes(struct drm_connector *connector)
+{
+#ifdef USE_HDMICHIP
+	int ret = 0;
+#endif
+	int count = 0;
+	void *edid_buf = NULL;
+	struct smi_device *sdev = connector->dev->dev_private;
+	struct smi_connector *smi_connector = to_smi_connector(connector);
+
+	ENTER();
+	dbg_msg("print connector type: [%d], DVI=%d, VGA=%d, HDMI=%d\n",
+			connector->connector_type, DRM_MODE_CONNECTOR_DVII, DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTOR_HDMIA);
+
+	if(!fixed_width || !fixed_height){
+		fixed_width = 1024;
+		fixed_height = 768;
+	}
+	
+	
+	if(g_specId == SPC_SM750)
+	{
+		if(connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+		{
+#ifdef USE_HDMICHIP
+
+			edid_buf = sdev->si9022_edid;
+			if(ddk750_GetDDC_9022Access())
+				ret = ddk750_edidReadMonitorEx(SMI0_CTRL, edid_buf, 256, 0, 30, 31);
+			ddk750_Release9022DDC();
+			if(ret){
+              	drm_connector_update_edid_property(connector, sdev->si9022_edid);
+                count = drm_add_edid_modes(connector, sdev->si9022_edid);
+	
+            }
+                if (ret == 0 || count == 0)
+                {
+	
+                        drm_connector_update_edid_property(connector, NULL);
+                        count = drm_add_modes_noedid(connector, 1920, 1080);
+                        drm_set_preferred_mode(connector, fixed_width, fixed_height);
+                }
+
+
+#else
+			edid_buf = drm_get_edid(connector, &smi_connector->adapter);
+
+			if(edid_buf)
+			{
+				dbg_msg("DVI get edid success.\n");
+				sdev->dvi_edid = edid_buf;
+				drm_connector_update_edid_property(connector, sdev->dvi_edid);
+				count = drm_add_edid_modes(connector, sdev->dvi_edid);
+			}
+			if (edid_buf == NULL || count == 0)
+			{
+				drm_connector_update_edid_property(connector, NULL);
+				count = drm_add_modes_noedid(connector, 1920, 1080);
+				drm_set_preferred_mode(connector, fixed_width, fixed_height);
+			}
+				
+#endif
+		}
+		if(connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+		{
+			edid_buf = drm_get_edid(connector, &smi_connector->adapter);
+
+		
+			
+		
+
+			if(edid_buf){
+			    dbg_msg("VGA get edid success.\n");
+				sdev->vga_edid = edid_buf;
+			
+				drm_connector_update_edid_property(connector, sdev->vga_edid); 
+
+				count = drm_add_edid_modes(connector, sdev->vga_edid);
+			}
+			if (edid_buf == NULL || count == 0)
+			{
+
+				drm_connector_update_edid_property(connector, NULL);
+
+				count = drm_add_modes_noedid(connector, 1920, 1080);
+				drm_set_preferred_mode(connector, fixed_width, fixed_height);
+			}
+				
+		}
+	}
+	else 
+	{ //SM768 Part
+
+		if(connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+		{
+			if(lvds_channel){
+
+				drm_connector_update_edid_property(connector, NULL);
+
+				count = drm_add_modes_noedid(connector, fixed_width, fixed_height);
+				drm_set_preferred_mode(connector, fixed_width, fixed_height);
+			}else{
+			
+				edid_buf = drm_get_edid(connector, &smi_connector->adapter);
+
+
+
+				if(edid_buf){
+					dbg_msg("DVI get edid success.\n");
+					sdev->dvi_edid = edid_buf;
+
+					drm_connector_update_edid_property(connector, sdev->dvi_edid); 
+
+					count = drm_add_edid_modes(connector, sdev->dvi_edid);
+				}
+		
+				if (edid_buf == NULL || count == 0)
+				{
+
+					drm_connector_update_edid_property(connector, NULL);
+
+					count = drm_add_modes_noedid(connector, 1920, 1080);
+					drm_set_preferred_mode(connector, fixed_width, fixed_height);
+				}
+			}
+
+		}
+		if(connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+		{
+			edid_buf = drm_get_edid(connector, &smi_connector->adapter);
+
+			if (edid_buf)
+			{
+				dbg_msg("VGA get edid success.\n");
+				sdev->vga_edid = edid_buf;
+				drm_connector_update_edid_property(connector, sdev->vga_edid);
+				count = drm_add_edid_modes(connector, sdev->vga_edid);
+			}
+			if (edid_buf == NULL || count == 0)
+			{
+
+				drm_connector_update_edid_property(connector, NULL);
+				count = drm_add_modes_noedid(connector, 1920, 1080);
+				drm_set_preferred_mode(connector, fixed_width, fixed_height);
+			}
+
+		}
+		if(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		{
+			edid_buf = drm_get_edid(connector, &smi_connector->adapter);
+
+            //hw768_get_hdmi_edid(tmpedid);   // Too Slow..
+			if (edid_buf)
+			{
+				dbg_msg("HDMIA get edid success.\n");
+				sdev->hdmi_edid = edid_buf;
+				drm_connector_update_edid_property(connector, sdev->hdmi_edid);		
+				count = drm_add_edid_modes(connector, sdev->hdmi_edid);
+				sdev->is_hdmi = drm_detect_hdmi_monitor(sdev->hdmi_edid);
+                dbg_msg("HDMI connector is %s\n",(sdev->is_hdmi ? "HDMI monitor" : "DVI monitor"));
+			}
+			if (edid_buf == NULL || count == 0)
+			{
+				drm_connector_update_edid_property(connector, NULL);
+				count = drm_add_modes_noedid(connector, 1920, 1080);
+				drm_set_preferred_mode(connector, fixed_width, fixed_height);
+				sdev->is_hdmi = true;
+			}
+
+		}
+
+	}
+	
+	LEAVE(count);
+}
+
+static enum drm_mode_status smi_connector_mode_valid(struct drm_connector *connector,
+				 struct drm_display_mode *mode)
+{
+	u32 vrefresh = drm_mode_vrefresh(mode);	
+	
+	if ((vrefresh < 29) || (vrefresh > 61) || (vrefresh > 31 && vrefresh < 59)){  
+		if(!edid_mode)
+			return MODE_NOCLOCK;
+	}
+
+	if ((mode->hdisplay > 3840) || (mode->vdisplay > 2160) || (mode->clock > 297000))
+		 return MODE_NOMODE;
+	
+	
+	if(mode->hdisplay > 1920) {
+		if ((g_m_connector == USE_DVI_HDMI) || (g_m_connector == USE_VGA_HDMI)||(g_specId == SPC_SM750))
+			return MODE_NOMODE;
+	}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0))	
+	if ((mode->hdisplay == 1366) && (mode->vdisplay == 768))
+		return MODE_NOMODE;
+#endif
+
+	if(lvds_channel && (!lcd_scale)){
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) {              
+				if ((mode->hdisplay == fixed_width) && (mode->vdisplay == fixed_height))                
+					return MODE_OK;    
+				else                
+					return MODE_NOMODE;
+		}
+	}
+	return MODE_OK;
+
+}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+struct drm_encoder *smi_connector_best_encoder(struct drm_connector *connector)
+{
+	int enc_id = connector->encoder_ids[0];
+	if (enc_id)
+		return drm_encoder_find(connector->dev, NULL, enc_id);
+
+	return NULL;
+}
+#endif
+
+
+static enum drm_connector_status smi_connector_detect(struct drm_connector
+														  *connector,
+													  bool force)
+{
+	struct smi_connector *smi_connector = to_smi_connector(connector);
+#ifdef USE_HDMICHIP
+	int ret = 0;
+	void *edid_buf;
+#endif
+
+	if (g_specId == SPC_SM750)
+	{
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+		{
+
+			if (force_connect & USE_DVI){
+					g_m_connector = g_m_connector | USE_DVI;
+					return connector_status_connected;
+			}else if(force_connect){
+					g_m_connector = g_m_connector & (~USE_DVI);
+					return connector_status_disconnected;
+			}
+#ifdef USE_HDMICHIP	
+			if (ddk750_GetDDC_9022Access())
+				ret = ddk750_edidReadMonitorEx(SMI0_CTRL, edid_buf, 128, 0, 30, 31);
+			ddk750_Release9022DDC();
+			if (ret)
+			{
+				dbg_msg("detect sii9022 HDMI connected.\n");
+				return connector_status_connected;
+			}
+			else
+			{
+				dbg_msg("detect sii9022 HDMI disconnected.\n");
+				return connector_status_disconnected;
+			}
+#endif
+
+
+
+			if (!drm_probe_ddc(&smi_connector->adapter))
+
+			{
+				dbg_msg("detect DVI/Panel DO NOT connected.\n");
+				return connector_status_disconnected;
+			}
+			else
+			{
+				dbg_msg("detect DVI/Panel connected.\n");
+				return connector_status_connected;
+			}
+		}
+		else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+		{
+			if (force_connect & USE_VGA){
+					g_m_connector = g_m_connector | USE_VGA;
+					return connector_status_connected;
+			}else if(force_connect){
+					g_m_connector = g_m_connector & (~USE_VGA);
+					return connector_status_disconnected;
+			}
+
+#if 0
+			if(ddk750_detectCRTMonitor(0, 0, 0) == 0)
+			{	
+				dbg_msg("detect CRT connected.\n");
+				return connector_status_connected;
+			}
+			else
+			{	
+				dbg_msg("detect CRT DO NOT connected.\n");
+				return connector_status_disconnected;
+			}
+
+#else
+			if(!drm_probe_ddc(&smi_connector->adapter))
+			{
+				dbg_msg("detect CRT DO NOT connected.\n");
+				return connector_status_disconnected;
+			}
+			else
+			{
+				dbg_msg("detect CRT connected.\n");
+				return connector_status_connected;
+			}
+#endif	
+			
+		}
+		else
+			return connector_status_unknown;
+	}
+	else  //SM768 Part
+	{
+		if(connector->connector_type == DRM_MODE_CONNECTOR_DVII)
+		{
+			if ((force_connect & USE_DVI) || (lvds_channel)){
+				g_m_connector = g_m_connector | USE_DVI;
+				return connector_status_connected;
+			}else if(force_connect){
+					g_m_connector = g_m_connector & (~USE_DVI);
+					return connector_status_disconnected;
+			}
+
+			if (!drm_probe_ddc(&smi_connector->adapter))
+			{
+				dbg_msg("detect DVI DO NOT connected. \n");
+				g_m_connector = g_m_connector & (~USE_DVI);
+				return connector_status_disconnected; 
+			}
+			else
+			{
+				dbg_msg("detect DVI connected(GPIO30,31)\n");
+				g_m_connector =g_m_connector |USE_DVI;
+				return connector_status_connected;
+			}
+
+		}
+		else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+		{
+			if (force_connect & USE_VGA){
+				g_m_connector = g_m_connector | USE_VGA;
+				return connector_status_connected;
+			}else if(force_connect){
+					g_m_connector = g_m_connector & (~USE_VGA);
+					return connector_status_disconnected;
+			}
+
+			if (!drm_probe_ddc(&smi_connector->adapter))
+			{
+				dbg_msg("detect CRT DO NOT connected. \n");
+				g_m_connector =g_m_connector&(~USE_VGA);
+				return connector_status_disconnected;
+			}
+			else
+			{
+				dbg_msg("detect CRT connected(GPIO 6, 7)\n");
+				g_m_connector = g_m_connector|USE_VGA;
+				return connector_status_connected;
+			}
+		
+		}
+		else if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+		{
+
+			if ((g_m_connector == USE_DVI_VGA) || (g_m_connector == USE_ALL))
+			{
+				hw768_HDMI_Disable_Output();
+				dbg_msg("set HDMI connector_status_disconnected because of VGA+DVI\n");
+				g_m_connector = g_m_connector&(~USE_HDMI);
+				return connector_status_disconnected;  //If VGA and DVI are both connected, disable HDMI
+			}
+
+			if (force_connect & USE_HDMI){
+				g_m_connector = g_m_connector | USE_HDMI;
+				return connector_status_connected;
+			}else if(force_connect){
+					g_m_connector = g_m_connector & (~USE_HDMI);
+					return connector_status_disconnected;
+			}
+
+#if 0//ndef AUDIO_EN
+			if (hdmi_hotplug_detect())
+#else
+			if (drm_probe_ddc(&smi_connector->adapter))
+#endif
+			{
+				dbg_msg("detect HDMI connected(GPIO 8,9) \n");
+				g_m_connector = g_m_connector|USE_HDMI;
+				return connector_status_connected; 
+			}
+			else if(HDMI_connector_detect())
+			{
+			    dbg_msg("detect HDMI connected(HPG pull high) \n");
+				g_m_connector = g_m_connector|USE_HDMI;
+				return connector_status_connected; 
+			}
+			else
+			{
+				dbg_msg("detect HDMI DO NOT connected. \n");
+				g_m_connector = g_m_connector&(~USE_HDMI);
+				return connector_status_disconnected;
+			}
+		
+		}
+		else
+			return connector_status_unknown;
+	}
+}
+
+static void smi_connector_destroy(struct drm_connector *connector)
+{
+	struct smi_device *sdev = connector->dev->dev_private;
+	if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA && sdev->hdmi_edid)
+	{
+		kfree(sdev->hdmi_edid);
+		sdev->hdmi_edid = NULL;
+	}
+	else if (connector->connector_type == DRM_MODE_CONNECTOR_DVII && sdev->dvi_edid)
+	{
+		kfree(sdev->dvi_edid);
+		sdev->dvi_edid = NULL;
+	}
+	else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA && sdev->vga_edid)
+	{
+		kfree(sdev->vga_edid);
+		sdev->vga_edid = NULL;
+	}
+
+	if(g_specId == SPC_SM768)
+	{
+		hw768_AdaptI2CCleanBus(connector);
+	}
+	else
+	{
+		hw750_AdaptI2CCleanBus(connector);
+	}
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+	kfree(connector);
+}
+
+
+static const struct drm_connector_helper_funcs smi_vga_connector_helper_funcs = {
+	.get_modes = smi_connector_get_modes,
+	.mode_valid = smi_connector_mode_valid,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0)
+	.best_encoder = smi_connector_best_encoder,
+#endif
+};
+
+static const struct drm_connector_funcs smi_vga_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = smi_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = smi_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_connector *smi_connector_init(struct drm_device *dev, int index)
+{
+	struct drm_connector *connector;
+	struct smi_connector *smi_connector;
+
+	smi_connector = kzalloc(sizeof(struct smi_connector), GFP_KERNEL);
+	if (!smi_connector)
+		return NULL;
+
+	connector = &smi_connector->base;
+	smi_connector->i2c_hw_enabled = false;
+
+	switch (index)
+	{
+		case 0:
+			drm_connector_init(dev, connector, &smi_vga_connector_funcs, DRM_MODE_CONNECTOR_DVII);
+			break;
+		case 1:
+			drm_connector_init(dev, connector, &smi_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+			break;
+		case 2:
+			drm_connector_init(dev, connector, &smi_vga_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
+			break;
+		default:
+			printk("error index of Connector\n");
+	}
+
+	if (g_specId == SPC_SM750) 
+	{
+		hw750_AdaptI2CInit(smi_connector);
+	}
+	else
+	{
+		hw768_AdaptI2CInit(smi_connector);
+	}
+
+	drm_connector_helper_add(connector, &smi_vga_connector_helper_funcs);
+	connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+
+	drm_connector_register(connector);
+	
+	return connector;
+}
+
+
+int smi_modeset_init(struct smi_device *cdev)
+{
+	int index, max_index = 2;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct smi_crtc *smi_crtc;
+	
+	if(!lvds_channel)
+		lcd_scale = 0;
+
+	if(lcd_scale)
+		swcur_en = 1;
+
+	if(smi_bpp >= 24)
+		smi_bpp = 32;
+
+	if(g_specId == SPC_SM750)
+		smi_bpp = 16;
+
+#ifdef PRIME
+	smi_bpp = 32;
+#endif
+
+	drm_mode_config_init(cdev->dev);
+	cdev->mode_info.mode_config_initialized = true;
+
+	cdev->dev->mode_config.min_width = 0;
+	cdev->dev->mode_config.min_height = 0;
+	cdev->dev->mode_config.max_width = SMI_MAX_FB_WIDTH;
+	cdev->dev->mode_config.max_height = SMI_MAX_FB_HEIGHT;
+
+	if (g_specId == SPC_SM750) { // limit to maximum size supported+		
+		cdev->dev->mode_config.max_width = 3840;
+		cdev->dev->mode_config.max_height = 2160;
+	}
+	cdev->dev->mode_config.cursor_width = 64;
+	cdev->dev->mode_config.cursor_height = 64;
+
+	cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
+	cdev->dev->mode_config.preferred_depth = smi_bpp;
+	cdev->dev->mode_config.prefer_shadow = 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	cdev->dev->mode_config.prefer_shadow_fbdev = 1;
+#endif
+
+
+	for(index = 0; index < MAX_CRTC ; index ++)
+	{
+		smi_crtc = smi_crtc_init(cdev->dev, index);
+		smi_crtc->crtc_index = index;
+		smi_crtc_tab[index] = smi_crtc;
+		dbg_msg("******smi_crtc_tab[%d]:%p******\n",index, smi_crtc_tab[index]);
+
+	}
+	
+	if(g_specId == SPC_SM768)
+		max_index = MAX_ENCODER;
+	
+	for(index = 0; index < max_index ; index ++)
+	{
+		encoder = smi_encoder_init(cdev->dev, index);
+		if (!encoder) {
+			DRM_ERROR("smi_encoder_tmds_init failed\n");
+			return -1;
+		}
+		smi_enc_tab[index] = encoder;
+
+		connector = smi_connector_init(cdev->dev, index);
+		if (!connector) {
+			DRM_ERROR("smi_%s_init failed\n", index?"VGA":"DVI");
+			return -1;
+		}
+		
+		drm_connector_attach_encoder(connector, encoder);
+
+	}
+
+	drm_mode_config_reset(cdev->dev);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
+	if ((g_specId == SPC_SM750 && (cdev->dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) || g_specId == SPC_SM768) {
+		int ret = 0;
+		ret = drm_fbdev_generic_setup(cdev->dev, cdev->dev->mode_config.preferred_depth);
+		if (ret) {
+			DRM_ERROR("smi_fbdev_init failed\n");
+			return ret;
+		}
+	}
+#endif
+	return 0;
+}
+
+void smi_modeset_fini(struct smi_device *cdev)
+{
+
+	if (cdev->mode_info.mode_config_initialized) {
+		drm_atomic_helper_shutdown(cdev->dev);
+		drm_mode_config_cleanup(cdev->dev);
+		cdev->mode_info.mode_config_initialized = false;
+	}
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/smi_plane.c b/drivers/gpu/drm/smifb2/smi_plane.c
new file mode 100644
index 000000000000..eb0489144fa3
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_plane.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+#include "smi_drv.h"
+
+#include <drm/drm_crtc_helper.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+#include <drm/drmP.h>
+#endif
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
+#include <linux/iosys-map.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+#include <linux/dma-buf-map.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
+#include <drm/drm_framebuffer.h>
+#endif
+
+#include "smi_dbg.h"
+
+#include "hw750.h"
+#include "hw768.h"
+
+extern struct smi_crtc * smi_crtc_tab[MAX_CRTC];
+extern struct drm_encoder * smi_enc_tab[MAX_ENCODER];
+
+//bit 0: DVI, bit 1: VGA, bit 2: HDMI.
+extern int g_m_connector;
+
+__attribute__((unused)) static void colorcur2monocur(void *data);
+
+static const uint32_t smi_cursor_plane_formats[] = { DRM_FORMAT_RGB565, DRM_FORMAT_BGR565,
+						     DRM_FORMAT_ARGB8888 };
+
+static const uint32_t smi_formats[] = { DRM_FORMAT_RGB565,   DRM_FORMAT_BGR565,
+					DRM_FORMAT_RGB888,
+					DRM_FORMAT_XRGB8888,
+					DRM_FORMAT_RGBA8888,
+					DRM_FORMAT_ARGB8888};
+
+
+int smi_cursor_atomic_check(struct drm_plane *plane, 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)  
+				struct drm_plane_state *state
+#else
+				struct drm_atomic_state *atom_state
+#endif
+)
+{
+#if KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(atom_state, plane);
+#endif
+	struct drm_crtc *crtc = state->crtc;
+	int src_w, src_h;
+
+	if (!crtc || !state->fb)
+		return 0;
+
+	src_w = (state->src_w >> 16);
+	src_h = (state->src_h >> 16);
+	if (src_w > 64 || src_h > 64) {
+		DRM_ERROR("Invalid cursor size (%dx%d)\n", src_w, src_h);
+		return -EINVAL;
+	}
+
+	dbg_msg("(%dx%d)@(%dx%d)\n", state->crtc_w, state->crtc_h, state->crtc_x, state->crtc_y);
+	return 0;
+}
+
+static void smi_cursor_atomic_update(struct drm_plane *plane, 
+#if KERNEL_VERSION(5, 13, 0) >  LINUX_VERSION_CODE
+				 struct drm_plane_state *old_state
+#else
+				struct drm_atomic_state *atom_state
+#endif
+)
+{
+#if KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(atom_state, plane);
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(atom_state, plane);
+#else
+	struct drm_plane_state *new_state = plane->state;
+#endif
+	
+	struct drm_crtc *crtc = new_state->crtc;
+	struct drm_framebuffer *fb = new_state->fb;
+	void *plane_addr;
+	u64 cursor_offset;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *bo;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
+	struct iosys_map map;
+	int ret;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+	struct dma_buf_map map;
+	int ret;
+#endif
+
+	int x, y;
+	disp_control_t disp_ctrl;
+	int i, ctrl_index = 0, max_enc = 0;	
+
+	if (!crtc || !fb)
+		return;
+
+
+	if(g_specId == SPC_SM750)
+		max_enc = MAX_CRTC;
+	else
+		max_enc = MAX_ENCODER;
+
+	for(i = 0;i < max_enc; i++)
+	{
+		if(crtc == smi_enc_tab[i]->crtc)
+		{
+			ctrl_index = i;
+			break;
+		}
+	}
+	disp_ctrl = (ctrl_index == SMI1_CTRL)?SMI1_CTRL:SMI0_CTRL;
+
+	if(ctrl_index >= MAX_CRTC)  //calc which path should we use for HDMI.
+	{
+		disp_ctrl = (disp_control_t)smi_calc_hdmi_ctrl(g_m_connector);
+	}
+
+
+	if (fb != old_state->fb) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		gbo = drm_gem_vram_of_gem(fb->obj[0]);
+
+		if (drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM) < 0) {
+			dbg_msg("vram_pin failed\n");
+			LEAVE();
+		}
+
+		cursor_offset = drm_gem_vram_offset(gbo);
+		if (cursor_offset < 0) {
+			dbg_msg("get gpu_addr failed\n");
+			drm_gem_vram_unpin(gbo);
+			LEAVE();
+		}
+		if (g_specId == SPC_SM750) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+			ret = drm_gem_vram_vmap(gbo, &map);
+			
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+			plane_addr = drm_gem_vram_vmap(gbo);
+#else
+			plane_addr = drm_gem_vram_kmap(gbo, true, NULL);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+			if (ret) {				
+#else
+			if (IS_ERR(plane_addr)) {
+#endif
+				dbg_msg("failed to map fbcon\n");
+			} else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)			
+				plane_addr = map.vaddr;		
+#endif
+				ddk750_initCursor(disp_ctrl, (u32)cursor_offset, BPP16_BLACK,
+						  BPP16_WHITE, BPP16_BLUE);
+				colorcur2monocur(plane_addr);
+				
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+				drm_gem_vram_vunmap(gbo, &map);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+				drm_gem_vram_vunmap(gbo, plane_addr);	
+#else
+				drm_gem_vram_kunmap(gbo);
+#endif
+				ddk750_enableCursor(disp_ctrl, 1);
+			}
+		} else {
+			ddk768_initCursor(disp_ctrl, (u32)cursor_offset, BPP32_BLACK, BPP32_WHITE,
+					  BPP32_BLUE);
+			ddk768_enableCursor(disp_ctrl, 3);
+		}
+		drm_gem_vram_unpin(gbo);
+#else
+		bo = gem_to_smi_bo(fb->obj[0]);
+		if (smi_bo_pin(bo, TTM_PL_FLAG_VRAM, &cursor_offset) < 0) {
+			dbg_msg("smi_bo_pin failed\n");
+			LEAVE();
+		}
+		if (g_specId == SPC_SM750) {
+			plane_addr = smi_bo_kmap(bo, true, NULL);
+			if (IS_ERR(plane_addr))
+				dbg_msg("failed to kmap fbcon\n");
+			else {
+				ddk750_initCursor(disp_ctrl, (u32)cursor_offset, BPP16_BLACK,
+						  BPP16_WHITE, BPP16_BLUE);
+				colorcur2monocur(bo->kmap.virtual);
+				smi_bo_kunmap(bo);
+				ddk750_enableCursor(disp_ctrl, 1);
+			}
+		} else if (g_specId == SPC_SM768) {
+			ddk768_initCursor(disp_ctrl, (u32)cursor_offset, BPP32_BLACK, BPP32_WHITE,
+					  BPP32_BLUE);
+			ddk768_enableCursor(disp_ctrl, 3);
+		}
+		smi_bo_unpin(bo);
+#endif
+	}
+
+	x = new_state->crtc_x;
+	y = new_state->crtc_y;
+
+	if (g_specId == SPC_SM750) {
+		ddk750_setCursorPosition(disp_ctrl, x < 0 ? -x : x, y < 0 ? -y : y, y < 0 ? 1 : 0,
+					 x < 0 ? 1 : 0);
+	} else if (g_specId == SPC_SM768) {
+		ddk768_setCursorPosition(disp_ctrl, x < 0 ? -x : x, y < 0 ? -y : y, y < 0 ? 1 : 0,
+					 x < 0 ? 1 : 0);
+	}
+}
+
+void smi_cursor_atomic_disable(struct drm_plane *plane, 
+#if KERNEL_VERSION(5, 13, 0) >  LINUX_VERSION_CODE
+				struct drm_plane_state *old_state
+#else
+				struct drm_atomic_state *atom_state
+#endif
+)
+{
+#if KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(atom_state, plane);
+#endif
+	disp_control_t disp_ctrl;
+	int i, ctrl_index = 0, max_enc = 0;	
+	
+	if (!old_state || !old_state->crtc) {
+		dbg_msg("drm plane:%d not enabled\n", plane->base.id);
+		return;
+	}
+
+	
+	if(g_specId == SPC_SM750)
+		max_enc = MAX_CRTC;
+	else
+		max_enc = MAX_ENCODER;
+
+	for(i = 0;i < max_enc; i++)
+	{
+		if(old_state->crtc == smi_enc_tab[i]->crtc)
+		{
+			ctrl_index = i;
+			break;
+		}
+	}
+	disp_ctrl = (ctrl_index == SMI1_CTRL)?SMI1_CTRL:SMI0_CTRL;
+
+	if(ctrl_index >= MAX_CRTC)  //calc which path should we use for HDMI.
+	{
+		disp_ctrl = (disp_control_t)smi_calc_hdmi_ctrl(g_m_connector);
+	}
+
+	
+	if (g_specId == SPC_SM750) {
+		ddk750_enableCursor(disp_ctrl, 0);
+	} else {
+		ddk768_enableCursor(disp_ctrl, 0);
+	}
+}
+
+
+static const struct drm_plane_helper_funcs smi_cursor_helper_funcs = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+	.prepare_fb = drm_gem_vram_plane_helper_prepare_fb,
+	.cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb,
+#endif
+	.atomic_check = smi_cursor_atomic_check,
+	.atomic_update = smi_cursor_atomic_update,
+	.atomic_disable = smi_cursor_atomic_disable,
+};
+
+
+__attribute__((unused)) static int smi_primary_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state)
+{
+
+	size_t i;
+	int ret;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *bo;
+#endif
+
+	ENTER();
+	if (!new_state->fb)
+		LEAVE(0);
+
+	for (i = 0; i < ARRAY_SIZE(new_state->fb->obj); ++i) {
+		if (!new_state->fb->obj[i])
+			continue;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		gbo = drm_gem_vram_of_gem(new_state->fb->obj[i]);
+		ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM);
+		if (ret < 0)
+			goto err_drm_gem_vram_unpin;
+#else
+		bo = gem_to_smi_bo(new_state->fb->obj[i]);
+		ret = smi_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+		if (ret)
+			goto err_smi_bo_unpin;
+#endif
+	}
+
+	LEAVE(0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+err_drm_gem_vram_unpin:
+	while (i) {
+		--i;
+		DRM_INFO("drm_gem_vram_pin failed!");
+		gbo = drm_gem_vram_of_gem(new_state->fb->obj[i]);
+		drm_gem_vram_unpin(gbo);
+	}
+#else
+err_smi_bo_unpin:
+	while (i) {
+		--i;
+		bo = gem_to_smi_bo(new_state->fb->obj[i]);
+		smi_bo_unpin(bo);
+	}
+#endif
+	LEAVE(ret);
+
+}
+
+__attribute__((unused)) static void smi_primary_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state)
+{
+	size_t i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *bo;
+#endif
+
+	ENTER();
+	if (!old_state->fb)
+		LEAVE();
+
+	for (i = 0; i < ARRAY_SIZE(old_state->fb->obj); ++i) {
+		if (!old_state->fb->obj[i])
+			continue;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+		gbo = drm_gem_vram_of_gem(old_state->fb->obj[i]);
+		drm_gem_vram_unpin(gbo);
+#else
+		bo = gem_to_smi_bo(old_state->fb->obj[i]);
+		smi_bo_unpin(bo);
+#endif
+	}
+	LEAVE();
+}
+
+static void smi_primary_plane_atomic_update(struct drm_plane *plane,
+#if KERNEL_VERSION(5, 13, 0) >  LINUX_VERSION_CODE
+				 struct drm_plane_state *old_state
+#else
+				struct drm_atomic_state *atom_state
+#endif
+)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(atom_state,
+									   plane);
+#else
+	struct drm_plane_state *state = plane->state;
+#endif
+	disp_control_t disp_ctrl;
+	struct drm_framebuffer *fb = state->fb;
+	u64 plane_addr;
+	uint32_t w, h, x, y;
+	uint32_t dst_x, dst_y;
+	uint32_t offset;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *bo;
+#endif
+	int i, ctrl_index = 0, max_enc = 0;	
+
+	ENTER();
+	if (!state->crtc || !state->fb)
+		LEAVE();
+
+	dbg_msg("source: (%u, %u) - (%u, %u)\n", (state->src_x >> 16),
+		(state->src_y >> 16), (state->src_w >> 16),
+		(state->src_h >> 16));
+	dbg_msg("dest: (%d, %d) - (%d, %d)\n", state->crtc_x, state->crtc_y,
+		state->crtc_w, state->crtc_h);
+
+	if (!state->visible)
+		LEAVE();
+
+	
+
+	if(g_specId == SPC_SM750)
+		max_enc = MAX_CRTC;
+	else
+		max_enc = MAX_ENCODER;
+
+	for(i = 0;i < max_enc; i++)
+	{
+		if(state->crtc == smi_enc_tab[i]->crtc)
+		{
+			ctrl_index = i;
+			break;
+		}
+	}
+	disp_ctrl = (ctrl_index == SMI1_CTRL)?SMI1_CTRL:SMI0_CTRL;
+
+	if(ctrl_index >= MAX_CRTC)  //calc which path should we use for HDMI.
+	{
+		disp_ctrl = (disp_control_t)smi_calc_hdmi_ctrl(g_m_connector);
+	}
+
+
+	x = (state->src_x >> 16);
+	y = (state->src_y >> 16);
+	w = (state->src_w >> 16);
+	h = (state->src_h >> 16);
+	dst_x = (state->crtc_x >> 16);
+	dst_y = (state->crtc_y >> 16);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	gbo = drm_gem_vram_of_gem(fb->obj[0]);
+	plane_addr = drm_gem_vram_offset(gbo);
+#else
+	bo = gem_to_smi_bo(fb->obj[0]);
+	smi_bo_pin(bo, TTM_PL_FLAG_VRAM, &plane_addr);
+#endif
+
+	fb->pitches[0] = (fb->pitches[0] + 15) & ~15;
+
+	offset = plane_addr + y * fb->pitches[0] + x * fb->format->cpp[0];
+	if (g_specId == SPC_SM750) {
+		hw750_set_base(disp_ctrl, fb->pitches[0], offset);
+	} else if (g_specId == SPC_SM768) {
+		hw768_set_base(disp_ctrl, fb->pitches[0], offset);
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	smi_bo_unpin(bo);
+#endif
+	LEAVE();
+}
+
+static int smi_primary_plane_atomic_check(struct drm_plane *plane, 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)
+	struct drm_plane_state *state
+#else
+	struct drm_atomic_state *atom_state
+#endif
+)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0)
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(atom_state, plane);
+#endif
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+
+	ENTER();
+	
+	if (!crtc)
+		LEAVE(0);
+	
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0)
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+#else
+	crtc_state = drm_atomic_get_crtc_state(atom_state, crtc);
+#endif	
+	if (IS_ERR(crtc_state))
+		LEAVE(PTR_ERR(crtc_state));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
+	LEAVE(drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_NO_SCALING,
+						  DRM_PLANE_NO_SCALING, false, true));
+#else
+	LEAVE(drm_atomic_helper_check_plane_state(state, crtc_state, DRM_PLANE_HELPER_NO_SCALING,
+						  DRM_PLANE_HELPER_NO_SCALING, false, true));
+#endif
+}
+
+static const struct drm_plane_helper_funcs smi_primary_plane_helper_funcs = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+	.prepare_fb = drm_gem_vram_plane_helper_prepare_fb,
+#else
+	.prepare_fb = smi_primary_plane_prepare_fb,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+	.cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb,
+#else
+	.cleanup_fb = smi_primary_plane_cleanup_fb,
+#endif
+	.atomic_check = smi_primary_plane_atomic_check,
+	.atomic_update = smi_primary_plane_atomic_update,
+};
+
+static const struct drm_plane_funcs smi_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.reset = drm_atomic_helper_plane_reset,
+	.destroy = drm_plane_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state
+};
+
+struct drm_plane *smi_plane_init(struct smi_device *cdev, unsigned int possible_crtcs,
+				 enum drm_plane_type type)
+{
+	int err;
+	int num_formats;
+	const uint32_t *formats;
+	struct drm_plane *plane;
+	const struct drm_plane_funcs *funcs;
+	const struct drm_plane_helper_funcs *helper_funcs;
+
+	switch (type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		funcs = &smi_plane_funcs;
+		formats = smi_formats;
+		num_formats = ARRAY_SIZE(smi_formats);
+		helper_funcs = &smi_primary_plane_helper_funcs;
+		break;
+	case DRM_PLANE_TYPE_CURSOR:
+		funcs = &smi_plane_funcs;
+		formats = smi_cursor_plane_formats;
+		num_formats = ARRAY_SIZE(smi_cursor_plane_formats);
+		helper_funcs = &smi_cursor_helper_funcs;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+	if (!plane)
+		return ERR_PTR(-ENOMEM);
+
+	err = drm_universal_plane_init(cdev->dev, plane, possible_crtcs, funcs, formats,
+				       num_formats, NULL, type, NULL);
+
+	if (err)
+		goto free_plane;
+
+	drm_plane_helper_add(plane, helper_funcs);
+
+	return plane;
+
+free_plane:
+	kfree(plane);
+	return ERR_PTR(-EINVAL);
+}
+
+__attribute__((unused)) static void colorcur2monocur(void *data)
+{
+	unsigned int *col = (unsigned int *)data;
+	unsigned char *mono = (unsigned char *)data;
+	unsigned char pixel = 0;
+	char bit_values;
+
+	int i;
+	for (i = 0; i < 64 * 64; i++) {
+		if (*col >> 24 < 0xe0) {
+			bit_values = 0;
+		} else {
+			int val = *col & 0xff;
+
+			if (val < 0x80) {
+				bit_values = 1;
+			} else {
+				bit_values = 2;
+			}
+		}
+		col++;
+		/* Copy bits into cursor byte */
+		switch (i & 3) {
+		case 0:
+			pixel = bit_values;
+			break;
+
+		case 1:
+			pixel |= bit_values << 2;
+			break;
+
+		case 2:
+			pixel |= bit_values << 4;
+			break;
+
+		case 3:
+			pixel |= bit_values << 6;
+			*mono = pixel;
+			mono++;
+			pixel = 0;
+			break;
+		}
+	}
+}
diff --git a/drivers/gpu/drm/smifb2/smi_prime.c b/drivers/gpu/drm/smifb2/smi_prime.c
new file mode 100644
index 000000000000..987f785fd6ea
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_prime.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+#include "smi_dbg.h"
+#include "smi_drv.h"
+
+#include <linux/dma-buf.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+#include <drm/drmP.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+
+struct sg_table *smi_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+	struct smi_bo *bo = gem_to_smi_bo(obj);
+	int npages = bo->bo.num_pages;
+
+	return drm_prime_pages_to_sg(bo->bo.ttm->pages, npages);
+}
+
+
+void *smi_gem_prime_vmap(struct drm_gem_object *obj)
+{
+	struct smi_bo *bo = gem_to_smi_bo(obj);
+	int ret;
+	void *base;
+
+	ret = smi_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret)
+		return (NULL);
+
+	base = smi_bo_kmap(bo, true, NULL);
+	if (IS_ERR(base)) {
+		smi_bo_unpin(bo);
+		return (NULL);
+	}
+
+	return (base);
+}
+
+void smi_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+	struct smi_bo *bo = gem_to_smi_bo(obj);
+
+	smi_bo_kunmap(bo);
+	smi_bo_unpin(bo);
+}
+
+int smi_gem_prime_pin(struct drm_gem_object *obj)
+{
+	struct smi_bo *bo = gem_to_smi_bo(obj);
+	int ret = 0;
+	ENTER();
+
+	/* pin buffer into GTT */
+	ret = smi_bo_pin(bo, TTM_PL_FLAG_SYSTEM, NULL);
+	LEAVE(ret);
+}
+
+void smi_gem_prime_unpin(struct drm_gem_object *obj)
+{
+	struct smi_bo *bo = gem_to_smi_bo(obj);
+
+	smi_bo_unpin(bo);
+}
+#endif
+
+struct drm_gem_object *smi_gem_prime_import_sg_table(struct drm_device *dev,
+						     struct dma_buf_attachment *attach,
+						     struct sg_table *sg)
+{
+	struct smi_device *UNUSED(sdev) = dev->dev_private;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	struct drm_gem_vram_object *gbo;
+#else
+	struct smi_bo *bo;
+#endif
+	int ret = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+	gbo = drm_gem_vram_create(dev, attach->dmabuf->size, PAGE_SIZE);
+#else
+	gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, attach->dmabuf->size, PAGE_SIZE, false);
+#endif
+	if (IS_ERR(gbo)) {
+		ret = PTR_ERR(gbo);
+	}
+
+#else
+	struct reservation_object *resv = attach->dmabuf->resv;
+
+	ww_mutex_lock(&resv->lock, NULL);
+	ret = smi_bo_create(dev, attach->dmabuf->size, PAGE_SIZE, 0, sg, resv, &bo);
+	ww_mutex_unlock(&resv->lock);
+#endif
+	if (ret) {
+		return (ERR_PTR(ret));
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+	return (&gbo->bo.base);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+	return (&gbo->gem);
+#else
+	return (&bo->gem);
+#endif
+}
diff --git a/drivers/gpu/drm/smifb2/smi_priv.h b/drivers/gpu/drm/smifb2/smi_priv.h
new file mode 100644
index 000000000000..63c93204eb1d
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_priv.h
@@ -0,0 +1,24 @@
+#ifndef __SMI_PRIV_H__
+#define __SMI_PRIV_H__
+
+struct smi_mode_info {
+	bool mode_config_initialized;
+	struct smi_crtc *crtc;
+	/* pointer to fbdev info structure */
+};
+
+struct smi_crtc {
+	struct drm_crtc base;
+	u8 lut_r[256], lut_g[256], lut_b[256];
+	int last_dpms;
+	bool enabled;
+	int crtc_index;
+	int CursorOffset;
+};
+
+struct smi_mc {
+	resource_size_t vram_size;
+	resource_size_t vram_base;
+};
+
+#endif
\ No newline at end of file
diff --git a/drivers/gpu/drm/smifb2/smi_snd.c b/drivers/gpu/drm/smifb2/smi_snd.c
new file mode 100644
index 000000000000..62b6355d3908
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_snd.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (C) 2016 SiliconMotion Inc.
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include "smi_drv.h"
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+
+
+
+#include "smi_snd.h"
+#include "ddk768/uda1345.h"
+#include "ddk768/wm8978.h"
+#include "ddk768/ddk768_reg.h"
+#include "ddk768/ddk768_iis.h"
+#include "ddk768/ddk768_intr.h"
+#include "ddk768/ddk768_power.h"
+#include "ddk768/ddk768_chip.h"
+
+
+
+//#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+
+#include "hw768.h"
+
+#include "smi_dbg.h"
+
+struct sm768chip *chip_irq_id=NULL;/*chip_irq_id is use for request and free irq*/
+int use_wm8978 = 0;
+
+static int SM768_AudioInit(unsigned long wordLength, unsigned long sampleRate)
+{
+	// Set up I2S and GPIO registers to transmit/receive data.
+    iisOpen(wordLength, sampleRate);
+    //Set I2S to DMA 256 DWord from SRAM starting at location 0 of SRAM
+    iisTxDmaSetup(0,SRAM_SECTION_SIZE);
+
+
+	// Init audio codec
+	if(use_wm8978){
+		printk("Use WM8978 Codec\n");
+		if (WM8978_Init())
+		{			
+			printk("Init WM8978 Codec failed\n");
+			WM8978_DeInit();
+			
+		}
+	}else{
+		printk("Use UDA1345 Codec\n");
+		if(uda1345_init())
+		 {   
+		   printk("Init UDA1345 Codec failed\n");
+		   uda1345_deinit();
+		 }
+	}
+
+    return 0;
+}
+
+
+/*
+ * This function call iis driver interface iisStart() to start play audio. 
+ */
+static int SM768_AudioStart(void)
+{
+
+	
+	if(use_wm8978){
+  
+	}else{
+	    uda1345_setpower(ADCOFF_DACON);
+		uda1345_setmute(NO_MUTE);
+	}
+
+	HDMI_Audio_Unmute();
+
+	iisStart();
+	
+    return 0;
+}
+
+/*
+ * Stop audio. 
+ */
+static int SM768_AudioStop(void)
+{
+
+	if(use_wm8978){
+	}else{
+		uda1345_setmute(MUTE);
+		uda1345_setpower(ADCOFF_DACOFF);
+	}
+
+	HDMI_Audio_Mute();
+	
+	iisStop();
+	
+    return 0;
+}
+
+
+
+static int SM768_AudioDeinit(void)
+{
+
+	iisStop();
+	iisClose();
+
+	if(use_wm8978)
+		WM8978_DeInit();
+	else
+		uda1345_deinit();
+	
+	sb_IRQMask(SB_IRQ_VAL_I2S);		
+	iisClearRawInt();
+    ddk768_enableI2S(0); 
+
+	return 0;
+}
+
+
+
+
+
+static u8  VolAuDrvToCodec(u16 audrv)
+{
+	u8 codecdb,map;
+    if(audrv == 0x8000)
+        return 0x3b;
+
+    codecdb = (audrv >> 8);
+
+    if(codecdb < 0x80)
+        map = (0x1f - (codecdb >> 2));
+    else
+        map = (0x5f - (codecdb >> 2));
+    return map;
+}
+
+
+static int snd_falconi2s_info_hw_volume(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	dbg_msg("snd_falconi2s_info_hw_volume\n");
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0x1f;
+	return 0;
+}
+
+static int snd_falconi2s_get_hw_play_volume(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct sm768chip *chip = kcontrol->private_data;
+	dbg_msg("snd_falconi2s_get_hw_volume\n");
+	
+	ucontrol->value.integer.value[0] = chip->playback_vol;
+	
+	return 0;
+}
+static int snd_falconi2s_put_hw_play_volume(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct sm768chip *chip = kcontrol->private_data;
+	int changed = 0;
+	u8 vol;
+	dbg_msg("snd_falconi2s_put_hw_volume:%ld\n", ucontrol->value.integer.value[0]);
+
+	if (chip->playback_vol!= ucontrol->value.integer.value[0]) {
+		vol = chip->playback_vol = ucontrol->value.integer.value[0];
+
+		if(use_wm8978){
+			WM8978_HPvol_Set(VolAuDrvToCodec(vol), VolAuDrvToCodec(vol));
+			WM8978_SPKvol_Set(VolAuDrvToCodec(vol));
+		}else{
+			uda1345_setvolume(VolAuDrvToCodec(vol));
+		}
+		changed = 1;
+	}
+
+	return changed;
+
+}
+
+
+static int snd_falconi2s_get_hw_capture_volume(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct sm768chip *chip = kcontrol->private_data;
+	dbg_msg("snd_falconi2s_get_hw_volume\n");
+	
+	ucontrol->value.integer.value[0] = chip->capture_vol;
+	
+	return 0;
+}
+static int snd_falconi2s_put_hw_capture_volume(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct sm768chip *chip = kcontrol->private_data;
+	int changed = 0;
+	u8 vol;
+	dbg_msg("snd_falconi2s_put_hw_volume:%ld\n", ucontrol->value.integer.value[0]);
+
+
+	if (chip->capture_vol!= ucontrol->value.integer.value[0]) {
+		vol = chip->capture_vol = ucontrol->value.integer.value[0];
+
+		if(use_wm8978){
+					WM8978_HPvol_Set(VolAuDrvToCodec(vol), VolAuDrvToCodec(vol));
+					WM8978_SPKvol_Set(VolAuDrvToCodec(vol));
+		}else{
+					uda1345_setvolume(VolAuDrvToCodec(vol));
+		}
+
+		changed = 1;
+	}
+
+	return changed;
+	
+}
+
+
+static struct snd_kcontrol_new falconi2s_vol[] = {
+ {
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Playback Volume",
+		.info = snd_falconi2s_info_hw_volume,
+		.get = snd_falconi2s_get_hw_play_volume,
+		.put = snd_falconi2s_put_hw_play_volume,
+		.private_value = 0,
+
+},
+{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Volume",
+		.info = snd_falconi2s_info_hw_volume,
+		.get = snd_falconi2s_get_hw_capture_volume,
+		.put = snd_falconi2s_put_hw_capture_volume,
+		.private_value = 0,
+},
+};
+  
+/* hardware definition */
+static struct snd_pcm_hardware snd_falconi2s_playback_hw = {
+	.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	//this value means both of 44100 and 48000 can work
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	//actually total length should less than 4096*1024.
+	.buffer_bytes_max = P_PERIOD_BYTE * P_PERIOD_MAX,
+	.period_bytes_min = P_PERIOD_BYTE,
+	.period_bytes_max = P_PERIOD_BYTE,
+	.periods_min =	  P_PERIOD_MIN,
+	.periods_max =	  P_PERIOD_MAX,
+};
+
+/* hardware definition */
+static struct snd_pcm_hardware snd_falconi2s_capture_hw = {
+	.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	//actually total length should less than 4096*1024.
+	.buffer_bytes_max = P_PERIOD_BYTE * P_PERIOD_MAX,
+	.period_bytes_min = P_PERIOD_BYTE,
+	.period_bytes_max = P_PERIOD_BYTE,
+	.periods_min =	  P_PERIOD_MIN,
+	.periods_max =	  P_PERIOD_MAX,
+
+};
+
+  /* open callback */
+static int snd_falconi2s_playback_open(struct snd_pcm_substream *substream)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	dbg_msg("snd_falconi2s_playback_open\n");
+
+	
+	runtime->hw = snd_falconi2s_playback_hw;
+	/* set the pointer value of substream field in the chip record at 
+	 * open callback to hold the current running substream pointer */
+	chip->play_substream = substream;
+	
+	return 0;
+}
+
+  /* close callback */
+static int snd_falconi2s_playback_close(struct snd_pcm_substream *substream)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	/* the hardware-specific codes will be here */
+	dbg_msg("snd_falconi2s_playback_close\n");
+	/* reset the pointer value of substream field in the chip record at close callback */
+	chip->play_substream = NULL;			 
+	return 0;
+
+}
+
+  /* open callback */
+static int snd_falconi2s_capture_open(struct snd_pcm_substream *substream)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	runtime->hw = snd_falconi2s_capture_hw;
+
+	/* set the pointer value of substream field in the chip record at open callback to hold the current running substream pointer */
+	chip->capture_substream = substream;
+
+	
+	return 0;
+}
+
+  /* close callback */
+static int snd_falconi2s_capture_close(struct snd_pcm_substream *substream)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	/* the hardware-specific codes will be here */
+	/* reset the pointer value of substream field in the chip record at close callback */
+	chip->capture_substream = NULL;
+	return 0;
+
+}
+
+  /* hw_params callback */
+static int snd_falconi2s_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *hw_params)
+{
+	dbg_msg("snd_falconi2s_pcm_hw_params,malloc:%d\n",params_buffer_bytes(hw_params));
+	   
+	return snd_pcm_lib_malloc_pages(substream,
+                                     params_buffer_bytes(hw_params));
+}
+
+  /* hw_free callback */
+static int snd_falconi2s_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	dbg_msg("snd_falconi2s_pcm_hw_free\n");
+	return snd_pcm_lib_free_pages(substream);
+}
+
+  /* prepare callback */
+static int snd_falconi2s_pcm_prepare(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime __attribute__((unused)) = substream->runtime;
+
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	dbg_msg("snd_falconi2s_pcm_prepare\n");
+
+	
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		chip->ppointer = 0;
+	else
+		chip->cpointer = 0;
+	
+
+	dbg_msg("runtime->rate:%d\n",runtime->rate);
+	dbg_msg("runtime->buffer_size:%ld\n",runtime->buffer_size);
+	dbg_msg("runtime->periods:%d\n",runtime->periods);
+	dbg_msg("runtime->period_size:%ld\n",runtime->period_size);
+	dbg_msg("runtime->frame_bits:%d\n",runtime->frame_bits);
+	dbg_msg("runtime->dma_bytes:%ld\n",runtime->dma_bytes);
+
+	return 0;
+}
+
+/* trigger callback */
+static int snd_falconi2s_pcm_playback_trigger(struct snd_pcm_substream *substream,
+                                    int cmd)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	dbg_msg("snd_falconi2s_pcm_trigger\n");
+	dbg_msg("substream:%p\n",substream);
+
+	
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:			
+		dbg_msg("PLAY SNDRV_PCM_TRIGGER_START\n");
+		memset_io(chip->pvReg + SRAM_OUTPUT_BASE, 0, SRAM_OUTPUT_SIZE);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dbg_msg("PLAY SNDRV_PCM_TRIGGER_STOP\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	
+	return 0;
+}
+
+
+ static int snd_falconi2s_pcm_capture_trigger(struct snd_pcm_substream *substream,
+									  int cmd)
+ {
+  	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	dbg_msg("snd_falconi2s_pcm_trigger\n");
+	dbg_msg("substream:%p\n",substream);
+
+	
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:		
+		dbg_msg("CAPTURE SNDRV_PCM_TRIGGER_START\n");
+		memset_io(chip->pvReg + SRAM_INPUT_BASE, 0, SRAM_INPUT_SIZE);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dbg_msg("CAPTURE SNDRV_PCM_TRIGGER_STOP\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	
+	return 0;
+ }
+
+ static int snd_falconi2s_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+ {
+	 
+	  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		  return snd_falconi2s_pcm_playback_trigger(substream, cmd);
+	  else
+		  return snd_falconi2s_pcm_capture_trigger(substream, cmd);
+ }
+
+
+
+  /* pointer callback */
+  static snd_pcm_uframes_t
+snd_falconi2s_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct sm768chip *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_uframes_t value = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		value = bytes_to_frames(substream->runtime, chip->ppointer);
+	else
+		value = bytes_to_frames(substream->runtime, chip->cpointer);
+	
+	return value;
+}
+
+  /* operators */
+static struct snd_pcm_ops snd_falconi2s_playback_ops = {
+          .open =        snd_falconi2s_playback_open,
+          .close =       snd_falconi2s_playback_close,
+          .ioctl =       snd_pcm_lib_ioctl,
+          .hw_params =   snd_falconi2s_pcm_hw_params,
+          .hw_free =     snd_falconi2s_pcm_hw_free,
+          .prepare =     snd_falconi2s_pcm_prepare,
+          .trigger =     snd_falconi2s_pcm_trigger,
+          .pointer =     snd_falconi2s_pcm_pointer,
+  };
+
+  /* operators */
+static struct snd_pcm_ops snd_falconi2s_capture_ops = {
+          .open =        snd_falconi2s_capture_open,
+          .close =       snd_falconi2s_capture_close,
+          .ioctl =       snd_pcm_lib_ioctl,
+          .hw_params =   snd_falconi2s_pcm_hw_params,
+          .hw_free =     snd_falconi2s_pcm_hw_free,
+          .prepare =     snd_falconi2s_pcm_prepare,
+          .trigger =     snd_falconi2s_pcm_trigger,
+          .pointer =     snd_falconi2s_pcm_pointer,
+  };
+
+
+
+
+static int snd_falconi2s_free(struct sm768chip *chip)
+{
+	/* will be implemented later... */
+	dbg_msg("snd_falconi2s_free!\n");
+
+	return 0;
+}
+
+/* component-destructor
+* (see "Management of Cards and Components")
+*/
+static int snd_falconi2s_dev_free(struct snd_device *device)
+{
+	return snd_falconi2s_free(device->device_data);
+}
+
+
+static int snd_smi_play_copy_data(struct sm768chip *chip,int sramTxSection)
+{
+		
+	struct snd_pcm_runtime *play_runtime;
+	struct snd_pcm_substream *play_substream;
+
+	play_substream = chip->play_substream;
+
+	if(play_substream == NULL)
+		memset_io(chip->pvReg + SRAM_OUTPUT_BASE + SRAM_SECTION_SIZE * sramTxSection, 0x00, P_PERIOD_BYTE);
+	else{
+		play_runtime = play_substream->runtime;
+
+		if (play_runtime->dma_area == NULL) 
+			return 0;
+
+		memcpy_toio(chip->pvReg + SRAM_OUTPUT_BASE + SRAM_SECTION_SIZE * sramTxSection, play_runtime->dma_area + chip->ppointer, P_PERIOD_BYTE);
+		chip->ppointer+= P_PERIOD_BYTE;
+		chip->ppointer%= ((play_runtime->periods) * (P_PERIOD_BYTE));
+		snd_pcm_period_elapsed(play_substream);
+	}
+	return 0;
+}
+
+static int snd_smi_capture_copy_data(struct sm768chip *chip,int sramTxSection)
+{
+		
+	struct snd_pcm_runtime *capture_runtime;
+	struct snd_pcm_substream *capture_substream;
+
+	capture_substream = chip->capture_substream;
+
+	if(capture_substream == NULL)	
+		memset_io(chip->pvReg + SRAM_INPUT_BASE + SRAM_SECTION_SIZE * sramTxSection, 0x00,  P_PERIOD_BYTE);
+		
+	else{
+		capture_runtime = capture_substream->runtime;
+
+		if (capture_runtime->dma_area == NULL) 
+			return 0;
+
+		memcpy_fromio(capture_runtime->dma_area + chip->cpointer, chip->pvReg + SRAM_INPUT_BASE + SRAM_SECTION_SIZE * sramTxSection,  P_PERIOD_BYTE);
+		chip->cpointer+= P_PERIOD_BYTE;
+		chip->cpointer%= ((capture_runtime->periods) * (P_PERIOD_BYTE));		
+		snd_pcm_period_elapsed(capture_substream);
+	}
+	return 0;
+}
+
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t snd_smi_interrupt(int irq, void *dev_id)
+{
+	
+	struct sm768chip *chip = dev_id;
+
+	int sramTxSection = 0; 
+
+	if(hw768_check_iis_interrupt())
+	{
+		unsigned long iParameter = 0;
+		iisClearRawInt(); //clear int
+
+		iParameter = iisDmaPointer();
+		
+		//SRAM is logically divided into 2 portions (1024 byte each)
+		//Check I2S DMA pointer to find out which portion is active.
+		if(iParameter >= 255)
+			//Fill top half SRAM if lower half is active
+			sramTxSection = 0;
+		else
+			//Fill lower half SRAM if top half is active
+			sramTxSection = 1;
+
+		snd_smi_play_copy_data(chip,sramTxSection);   
+		snd_smi_capture_copy_data(chip,sramTxSection);
+
+		return IRQ_HANDLED;
+	}
+	else
+		return IRQ_NONE;
+}
+
+  /* chip-specific constructor
+   * (see "Management of Cards and Components")
+   */
+static int snd_falconi2s_create(struct snd_card *card,
+                                         struct drm_device *dev,
+                                         struct sm768chip **smichip)
+{
+	int err;
+	int sample_rate = 44100;
+	struct pci_dev *pdev;
+	struct smi_device *smi_device = dev->dev_private;
+	struct sm768chip *chip;
+	static struct snd_device_ops ops = {
+		.dev_free = snd_falconi2s_dev_free,
+	};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+	*smichip = NULL;
+
+	/* allocate a chip-specific data with zero filled */
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	chip->card = card;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		snd_falconi2s_free(chip);
+		return err;
+	}
+	
+	//map register
+	chip->vidreg_start = smi_device->rmmio_base;
+	chip->vidreg_size = smi_device->rmmio_size;
+	dbg_msg("Audio MMIO phyAddr = 0x%lx\n",chip->vidreg_start);
+
+	chip->pvReg = smi_device->rmmio;
+	dbg_msg("Audio MMIO virtual addr = %p\n",chip->pvReg);
+	
+
+	//map video memory. 
+	chip->vidmem_start = smi_device->mc.vram_base;
+	chip->vidmem_size = 0x200000;   // change the video memory temperarily
+	dbg_msg("video memory phyAddr = 0x%lx, size = (Dec)%ld bytes\n",
+		chip->vidmem_start,chip->vidmem_size);
+
+#ifdef NO_WC
+	chip->pvMem = ioremap(chip->vidmem_start,chip->vidmem_size);
+#else
+	chip->pvMem = ioremap_wc(chip->vidmem_start,chip->vidmem_size);
+#endif
+
+
+	if(!chip->pvMem){
+		dev_err(&pdev->dev, "Map memory failed\n");
+		snd_falconi2s_free(chip);
+		err = -EFAULT;
+		return err;
+	}else{
+		dbg_msg("Audio video memory virtual addr = %p\n",chip->pvMem);
+	}
+	//above 
+
+	chip->irq = pdev->irq;
+
+	dbg_msg("Audio pci irq :%d\n",chip->irq);
+	
+	if (ddk768_getCrystalType())
+		sample_rate = 48000;
+	else
+		sample_rate = 44100;
+
+	if(SM768_AudioInit(SAMPLE_BITS, sample_rate)) {
+		dev_err(&pdev->dev, "Audio init failed!\n");
+		snd_falconi2s_free(chip);
+		return -1;
+	}
+	SM768_AudioStart();
+
+	//clear SRAM
+	memset_io(chip->pvReg + SRAM_OUTPUT_BASE, 0, SRAM_TOTAL_SIZE);
+	
+	chip_irq_id=chip;/*Record chip_irq_id which will use in free_irq*/
+	dbg_msg("chip_irq_id=%p\n", chip_irq_id);
+
+	iisClearRawInt();//clear int
+
+	//Setup ISR. The ISR will move more data from DDR to SRAM.
+	
+	if (request_irq(pdev->irq, snd_smi_interrupt, IRQF_SHARED,
+		KBUILD_MODNAME, chip_irq_id)) {
+		dev_err(&pdev->dev, "unable to grab IRQ %d\n", pdev->irq);
+		snd_falconi2s_free(chip);
+		return -EBUSY;
+	}
+	sb_IRQUnmask(SB_IRQ_VAL_I2S); 
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,18,0)
+	snd_card_set_dev(card, &pdev->dev);
+#endif
+
+	*smichip = chip;
+	return 0;
+}
+
+
+
+int smi_audio_init(struct drm_device *dev)
+{
+	int idx, err;
+	struct pci_dev *pdev;
+	struct smi_device *sdev = dev->dev_private;
+	struct snd_pcm *pcm;
+	struct snd_card *card;
+	struct sm768chip *chip;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+	if(audio_en == 1)
+		use_wm8978 = 0;
+	else if(audio_en == 2)
+		use_wm8978 = 1;
+	
+	err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &card); 
+
+
+	
+	if (err < 0)
+		return err;
+
+	err = snd_falconi2s_create(card, dev, &chip);
+	if (err < 0) {
+		snd_card_free(card);
+      		return err;
+	}
+
+	strcpy(card->driver, "smi-audio");
+	strcpy(card->shortname, "smi-audio");
+	strcpy(card->longname, "SiliconMotion Audio");
+
+	snd_pcm_new(card,"smiaudio_pcm",0,1,1,&pcm);
+	pcm->private_data = chip;
+
+      
+	/* set operators */
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                          &snd_falconi2s_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                          &snd_falconi2s_capture_ops);
+	  
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+					      &pdev->dev,
+#else
+					      snd_dma_pci_data(pdev),
+#endif
+						P_PERIOD_BYTE*P_PERIOD_MIN, P_PERIOD_BYTE*P_PERIOD_MAX);
+
+	strcpy(card->mixername, "SiliconMotion Audio Mixer Control");
+	
+	for (idx = 0; idx < ARRAY_SIZE(falconi2s_vol); idx++) {
+		if ((err = snd_ctl_add(card,snd_ctl_new1(&falconi2s_vol[idx], chip))) < 0)
+		{
+			return err;
+		}
+	}
+
+	
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	sdev->card = card;
+
+	return 0;
+
+}
+
+void smi_audio_remove(struct drm_device *dev)
+{
+	struct pci_dev *pdev;
+	struct smi_device *sdev = dev->dev_private;
+	struct snd_card *card = sdev->card;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+	
+	dbg_msg("perpare to free irq, pci irq:%u, chip_irq_id=0x%p\n", pdev->irq, chip_irq_id);
+	if(pdev->irq){				
+		free_irq(pdev->irq, chip_irq_id);
+		dbg_msg("free irq\n");
+	}
+	SM768_AudioStop();
+	SM768_AudioDeinit();
+
+	snd_card_free(card);
+	
+	iounmap(chip_irq_id->pvMem);
+}
+
+void smi_audio_resume()
+{
+
+	int sample_rate = 44100;
+	
+	if (ddk768_getCrystalType())
+			sample_rate = 48000;
+		else
+			sample_rate = 44100;
+	
+	SM768_AudioInit(SAMPLE_BITS, sample_rate);
+	SM768_AudioStart();
+
+	sb_IRQUnmask(SB_IRQ_VAL_I2S);
+}
+
+
+void smi_audio_suspend()
+{
+	SM768_AudioStop();
+	SM768_AudioDeinit();
+}
+
+
diff --git a/drivers/gpu/drm/smifb2/smi_snd.h b/drivers/gpu/drm/smifb2/smi_snd.h
new file mode 100644
index 000000000000..5af9e9e31b0e
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_snd.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 SiliconMotion Inc.
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef __SMI_SOUND_H__
+#define __SMI_SOUND_H__
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+/* definition of the chip-specific record */
+struct sm768chip {
+	struct snd_card *card;
+	int irq;
+
+	struct snd_pcm_substream *play_substream;
+	struct snd_pcm_substream *capture_substream;
+	unsigned long ppointer;
+	unsigned long cpointer;
+	
+	volatile unsigned char __iomem *pvReg;
+	unsigned char __iomem *pvMem;
+
+	unsigned long vidreg_start;
+	unsigned long vidreg_size;	
+	unsigned long vidmem_start;
+	unsigned long vidmem_size;
+
+	spinlock_t lock;
+
+	//master playback volume and capture volume
+	u8 playback_vol;//only record one channel, right=left
+	u8 capture_vol;
+	u8 playback_switch;//only record one channel, right=left
+	u8 capture_switch;
+	
+};
+
+#if 0
+struct sm768_runtime_data_father{
+	struct sm768_runtime_data * play_data;
+	struct sm768_runtime_data * capture_data;
+};
+
+struct sm768_runtime_data {
+	spinlock_t lock;
+	struct sm768chip *params;
+	struct snd_pcm_substream *psubstream;
+	unsigned long ppointer; /* playback pointer in bytes */
+	struct snd_pcm_substream *csubstream;
+	unsigned long cpointer; /* capture buffer pointer in bytes */
+};
+#endif
+
+/* For playback hw parameter*/
+#define P_PERIOD_BYTE 		  1024
+#define P_PERIOD_MIN 		  16
+#define P_PERIOD_MAX 		  256
+
+#define FEATURES	          2/* 1:only output; 2:output and input */
+#define SRAM_TOTAL_SIZE	  	  0x1000
+#define SAMPLE_BITS		  	  32
+#define SECTIONS_NUM	  	  2
+#define STEREO			  	  2
+#define MONO				  1
+
+#define SRAM_OUTPUT_SIZE	  (SRAM_TOTAL_SIZE/FEATURES)
+#define SRAM_INPUT_SIZE	  	  (SRAM_TOTAL_SIZE/FEATURES)
+#define SRAM_SECTION_SIZE     (SRAM_OUTPUT_SIZE/OUTPUT_SRAM_SECTIONS_NUM)
+#define SRAM_SECTION_SIZE_DWORDS  ((SRAM_SECTION_SIZE/4)-1)
+#define OUTPUT_SRAM_SECTIONS_NUM  SECTIONS_NUM
+
+
+#endif				/* __SMI_DRV_H__ */
diff --git a/drivers/gpu/drm/smifb2/smi_sysfs.c b/drivers/gpu/drm/smifb2/smi_sysfs.c
new file mode 100644
index 000000000000..84a8044a458c
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_sysfs.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * smi_sysfs.c
+ *
+ * Copyright (c) 2020 
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pci.h>
+#include <drm/drm_print.h>
+#include "smi_drv.h"
+#include "ddk768/ddk768_pwm.h"
+
+extern int pwm_ctrl;
+extern int smi_debug;
+extern int force_connect;
+
+static ssize_t pwm_ctrl_store(__always_unused struct device *dev,
+			      __always_unused struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	unsigned int ctrl = pwm_ctrl;
+	unsigned int val;
+
+
+	if (kstrtouint(buf, 10, &val)) {
+		pr_err("Unable to parse %u\n", val);
+		return -EINVAL;
+	}
+
+	if(val == ctrl) {
+		pr_info("Nothing to do with %u\n", val);
+		return count;
+	} 
+
+	if(ctrl) {
+		if((val & 0xf) != (ctrl & 0xf)) {
+			ddk768_pwmClose(ctrl & 0xf);
+		} 
+	
+		if((val & ~0xf) != (ctrl & ~0xf)) {
+			ddk768_pwmStop(ctrl & 0xf);
+		}
+	}
+
+	if (val) {
+		unsigned long pwm, divider, highCounter, lowCounter;
+
+		pwm = val & 0xf;
+		divider = (val & 0xf0) >> 4;
+		highCounter = (val & 0xfff00) >> 8;
+		lowCounter = (val & 0xfff00000) >> 20;
+
+		if((val & 0xf) != (ctrl & 0xf)) {
+			ddk768_pwmOpen(pwm);
+		}
+
+		if((val & ~0xf) != (ctrl & ~0xf)) {
+			ddk768_pwmStart(pwm, divider, highCounter, lowCounter, 0);
+		}
+	}
+
+	pwm_ctrl = val;
+	pr_info("Setting pwm_ctrl to %u\n", val);
+	return count;
+}
+
+static ssize_t pwm_ctrl_show(__always_unused struct device *dev,
+			     __always_unused struct device_attribute *attr,
+			     char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", pwm_ctrl);
+}
+
+static ssize_t smi_debug_store(__always_unused struct device *dev,
+			      __always_unused struct device_attribute *attr,
+			      const char *buf, size_t count) 
+{
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val)) {
+		pr_err("Unable to parse %u\n", val);
+		return -EINVAL;
+	}
+	
+
+	pr_info("Setting smi_debug to %u\n", val);
+	smi_debug = val;
+	return count;
+}
+
+static ssize_t smi_debug_show(__always_unused struct device *dev,
+			     __always_unused struct device_attribute *attr,
+			     char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", smi_debug);
+}
+
+static ssize_t nopnp_store(__always_unused struct device *dev,
+			     __always_unused struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val)) {
+		pr_err("Unable to parse %u\n", val);
+		return -EINVAL;
+	}
+	
+
+	pr_info("Setting force_connect to %u\n", val);
+	force_connect = val;
+	return count;
+}
+
+static ssize_t nopnp_show(__always_unused struct device *dev,
+			     __always_unused struct device_attribute *attr,
+			     char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", force_connect);
+}
+
+
+// pwm: pwm_ctrl
+// debug: smi_debug
+// nopnp: force_connect
+
+static struct device_attribute smi_device_attributes[] = {
+	__ATTR_RW(pwm_ctrl),
+	__ATTR_RW(smi_debug),
+	__ATTR_RW(nopnp)
+};
+
+void smi_sysfs_init(struct kobject *obj)
+{
+	int i;
+	int ret;
+
+	if (PTR_ERR_OR_ZERO(obj)) {
+		pr_err("SMI obj is NULL\n");
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(smi_device_attributes); i++) {
+		if((ret = sysfs_create_file(obj, &smi_device_attributes[i].attr)) < 0) {
+			pr_err("Create SMI sysfs failed: %d\n", ret);
+		}
+	}
+
+}
+
+void smi_sysfs_deinit(struct kobject *obj)
+{
+        int i;
+        if (PTR_ERR_OR_ZERO(obj))
+                return;
+
+        for (i = 0; i < ARRAY_SIZE(smi_device_attributes); i++)
+                sysfs_remove_file(obj, &smi_device_attributes[i].attr);
+
+}
+
diff --git a/drivers/gpu/drm/smifb2/smi_sysfs.h b/drivers/gpu/drm/smifb2/smi_sysfs.h
new file mode 100644
index 000000000000..aee6b8f2c15f
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_sysfs.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * smi_sysfs.h
+ *
+ * Copyright (c) 2020 
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SMI_SYSFS_H_
+#define _SMI_SYSFS_H_
+
+struct device;
+
+void smi_sysfs_init(struct kobject *);
+void smi_sysfs_deinit(struct kobject *);
+
+#endif
diff --git a/drivers/gpu/drm/smifb2/smi_ttm.c b/drivers/gpu/drm/smifb2/smi_ttm.c
new file mode 100644
index 000000000000..6d2cef0c31e8
--- /dev/null
+++ b/drivers/gpu/drm/smifb2/smi_ttm.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2016 SiliconMotion Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ */
+
+#include "smi_dbg.h"
+#include "smi_drv.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
+#include<drm/drm_backport.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
+#include <drm/drm_pci.h>
+#else
+#include <linux/pci.h>
+#endif
+#else
+#include <drm/drmP.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+#include <drm/ttm/ttm_page_alloc.h>
+
+static inline struct smi_device *smi_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct smi_device, ttm.bdev);
+}
+
+void smi_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct smi_bo *bo;
+
+	bo = container_of(tbo, struct smi_bo, bo);
+
+	drm_gem_object_release(&bo->gem);
+	kfree(bo);
+}
+
+bool smi_ttm_bo_is_smi_bo(struct ttm_buffer_object *bo)
+{
+	if (bo->destroy == &smi_bo_ttm_destroy)
+		return true;
+	return false;
+}
+
+static int smi_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+				struct ttm_mem_type_manager *man)
+{
+	switch (type) {
+	case TTM_PL_SYSTEM:
+		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_MASK_CACHING;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
+		man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
+#ifdef NO_WC
+		man->available_caching = TTM_PL_FLAG_UNCACHED;
+		man->default_caching = TTM_PL_FLAG_UNCACHED;
+#else
+		man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+		man->default_caching = TTM_PL_FLAG_WC;
+#endif
+		break;
+	default:
+		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void smi_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+	struct smi_bo *smibo = smi_bo(bo);
+
+	if (!smi_ttm_bo_is_smi_bo(bo))
+		return;
+
+	smi_ttm_placement(smibo, TTM_PL_FLAG_SYSTEM);
+	*pl = smibo->placement;
+}
+
+static int smi_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+	struct smi_device *smi = smi_bdev(bdev);
+
+	mem->bus.addr = NULL;
+	mem->bus.offset = 0;
+	mem->bus.size = mem->num_pages << PAGE_SHIFT;
+	mem->bus.base = 0;
+	mem->bus.is_iomem = false;
+	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+		return -EINVAL;
+	switch (mem->mem_type) {
+	case TTM_PL_SYSTEM:
+		/* system memory */
+		return 0;
+	case TTM_PL_VRAM:
+		mem->bus.offset = mem->start << PAGE_SHIFT;
+		mem->bus.base = pci_resource_start(smi->dev->pdev, 0);
+		mem->bus.is_iomem = true;
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	return 0;
+}
+
+static void smi_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static void smi_ttm_backend_destroy(struct ttm_tt *tt)
+{
+	ttm_tt_fini(tt);
+	kfree(tt);
+}
+
+static struct ttm_backend_func smi_tt_backend_func = {
+	.destroy = &smi_ttm_backend_destroy,
+};
+
+static void smi_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+	if (slave)
+		return;
+
+	ttm_pool_unpopulate(ttm);
+}
+
+static inline u64 smi_bo_gpu_offset(struct smi_bo *bo)
+{
+	return bo->bo.offset;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+static int smi_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+	struct smi_bo *smibo = smi_bo(bo);
+	return drm_vma_node_verify_access(&smibo->gem.vma_node, filp->private_data);
+}
+
+struct ttm_tt *smi_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
+{
+	struct ttm_tt *tt;
+
+	tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+	if (tt == NULL)
+		return NULL;
+	tt->func = &smi_tt_backend_func;
+	if (ttm_tt_init(tt, bo, page_flags)) {
+		kfree(tt);
+		return NULL;
+	}
+	return tt;
+}
+
+static int smi_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
+{
+	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+	if (ttm->state != tt_unpopulated)
+		return 0;
+
+	if (slave && ttm->sg) {
+		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, NULL, ttm->num_pages);
+		ttm->state = tt_unbound;
+		return 0;
+	}
+
+	return ttm_pool_populate(ttm, ctx);
+}
+
+struct ttm_bo_driver smi_bo_driver = {
+	.ttm_tt_create = smi_ttm_tt_create,
+	.ttm_tt_populate = smi_ttm_tt_populate,
+	.ttm_tt_unpopulate = smi_ttm_tt_unpopulate,
+	.init_mem_type = smi_bo_init_mem_type,
+	.evict_flags = smi_bo_evict_flags,
+	.eviction_valuable = ttm_bo_eviction_valuable,
+	.move = NULL,
+	.verify_access = smi_bo_verify_access,
+	.io_mem_reserve = &smi_ttm_io_mem_reserve,
+	.io_mem_free = &smi_ttm_io_mem_free,
+};
+#endif
+
+int smi_mm_init(struct smi_device *smi)
+{
+	int ret;
+	struct pci_dev *pdev;
+	struct drm_vram_mm *vmm __attribute__((unused));
+	struct drm_device *dev = smi->dev;
+	unsigned long vram_size = smi->mc.vram_size;
+
+#ifdef PRIME
+	if (g_specId == SPC_SM750)
+		vram_size = 0xa000000;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	struct ttm_bo_device *bdev = &smi->ttm.bdev;
+
+	ret = ttm_bo_device_init(&smi->ttm.bdev,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
+				 &smi_bo_driver, dev->anon_inode->i_mapping, smi->need_dma32
+#else
+				 &smi_bo_driver, dev->anon_inode->i_mapping, DRM_FILE_PAGE_OFFSET,
+				 smi->need_dma32
+#endif
+	);
+	if (ret) {
+		DRM_ERROR("Error initialising bo driver; %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT);
+
+	if (ret) {
+		DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+#else
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)	
+	vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(pdev, 0),
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+				       vram_size);
+#else
+				       vram_size, &drm_gem_vram_mm_funcs);
+#endif
+	if (IS_ERR(vmm)) {
+		ret = PTR_ERR(vmm);
+
+#else
+		ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0),
+				    vram_size);
+		if (ret) {
+#endif
+			DRM_ERROR("Error initializing VRAM MM; %d\n", ret);
+			return ret;
+	}
+#endif
+
+	arch_io_reserve_memtype_wc(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+
+	smi->fb_mtrr =
+		arch_phys_wc_add(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+
+	smi->mm_inited = true;
+	return 0;
+}
+
+void smi_mm_fini(struct smi_device *smi)
+{
+	struct pci_dev *pdev;
+	struct drm_device *dev = smi->dev;
+	
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)
+	pdev = to_pci_dev(dev->dev);
+#else
+	pdev = dev->pdev;
+#endif
+
+	if (!smi->mm_inited)
+		return;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+	ttm_bo_device_release(&smi->ttm.bdev);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
+	drm_vram_helper_release_mm(dev);
+#endif
+
+	arch_io_free_memtype_wc(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+
+	arch_phys_wc_del(smi->fb_mtrr);
+
+	smi->fb_mtrr = 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
+void smi_ttm_placement(struct smi_bo *bo, int domain)
+{
+	u32 c = 0;
+	unsigned i;
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+#ifdef NO_WC
+		bo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+#else
+		bo->placements[c++].flags =
+			TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+#endif
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+	if (!c)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+	bo->placement.num_placement = c;
+	bo->placement.num_busy_placement = c;
+	for (i = 0; i < c; ++i) {
+		bo->placements[i].fpfn = 0;
+		bo->placements[i].lpfn = 0;
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
+int smi_bo_create(struct drm_device *dev, int size, int align, uint32_t flags, struct sg_table *sg,
+		  struct reservation_object *resv, struct smi_bo **psmibo)
+#else
+int smi_bo_create(struct drm_device *dev, int size, int align, uint32_t flags, struct sg_table *sg,
+		  struct dma_resv *resv, struct smi_bo **psmibo)
+#endif
+{
+	struct smi_device *smi = dev->dev_private;
+	struct smi_bo *smibo;
+	size_t acc_size;
+	enum ttm_bo_type type;
+	int ret;
+
+	*psmibo = NULL;
+
+	if (sg) {
+		type = ttm_bo_type_sg;
+	} else {
+		type = ttm_bo_type_device;
+	}
+
+	smibo = kzalloc(sizeof(struct smi_bo), GFP_KERNEL);
+	if (!smibo)
+		return -ENOMEM;
+
+	ret = drm_gem_object_init(dev, &smibo->gem, size);
+	if (ret)
+		goto error;
+
+	smibo->bo.bdev = &smi->ttm.bdev;
+	smi_ttm_placement(smibo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&smi->ttm.bdev, size, sizeof(struct smi_bo));
+
+	ret = ttm_bo_init(&smi->ttm.bdev, &smibo->bo, size, type, &smibo->placement,
+			  align >> PAGE_SHIFT, false, acc_size, sg, resv, smi_bo_ttm_destroy);
+	if (ret)
+		goto error;
+
+	*psmibo = smibo;
+	return 0;
+
+error:
+	kfree(smibo);
+	return ret;
+}
+
+static int smi_bo_reserve(struct smi_bo *bo, bool no_wait)
+{
+	int ret;
+	ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
+	if (ret) {
+		if (ret != -ERESTARTSYS && ret != -EBUSY)
+			DRM_ERROR("reserve failed %p\n", bo);
+		return ret;
+	}
+	return 0;
+}
+
+static void smi_bo_unreserve(struct smi_bo *bo)
+{
+	ttm_bo_unreserve(&bo->bo);
+}
+
+int smi_bo_pin(struct smi_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+	int i, ret;
+	struct ttm_operation_ctx ctx = { false, false };
+
+	ret = smi_bo_reserve(bo, false);
+	if (unlikely(ret < 0))
+		return ret;
+
+	if (bo->pin_count)
+		goto out;
+
+	if (pl_flag)
+		smi_ttm_placement(bo, pl_flag);
+
+	for (i = 0; i < bo->placement.num_placement; i++)
+		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
+	if (ret < 0)
+		goto err_smi_bo_unreserve;
+
+out:
+	++bo->pin_count;
+	if (gpu_addr)
+		*gpu_addr = smi_bo_gpu_offset(bo);
+	smi_bo_unreserve(bo);
+	return 0;
+
+err_smi_bo_unreserve:
+	smi_bo_unreserve(bo);
+	return ret;
+}
+
+int smi_bo_unpin(struct smi_bo *bo)
+{
+	int i, ret;
+	struct ttm_operation_ctx ctx = { false, false };
+
+	ret = smi_bo_reserve(bo, false);
+	if (unlikely(ret < 0))
+		return ret;
+
+	if (!bo->pin_count)
+		goto out;
+
+	--bo->pin_count;
+	if (bo->pin_count)
+		goto out;
+
+	for (i = 0; i < bo->placement.num_placement; i++)
+		bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
+	if (ret < 0)
+		goto err_smi_bo_unreserve;
+
+out:
+	smi_bo_unreserve(bo);
+	return 0;
+
+err_smi_bo_unreserve:
+	smi_bo_unreserve(bo);
+	return ret;
+}
+
+int smi_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct smi_device *smi;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
+	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+		return -EINVAL;
+#endif
+
+	file_priv = filp->private_data;
+	smi = file_priv->minor->dev->dev_private;
+
+	return ttm_bo_mmap(filp, vma, &smi->ttm.bdev);
+}
+
+void *smi_bo_kmap(struct smi_bo *bo, bool map, bool *is_iomem)
+{
+	int ret;
+	struct ttm_bo_kmap_obj *kmap = &bo->kmap;
+
+	if (kmap->virtual || !map)
+		goto out;
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, kmap);
+	if (ret)
+		return ERR_PTR(ret);
+
+out:
+	if (!is_iomem)
+		return kmap->virtual;
+	if (!kmap->virtual) {
+		*is_iomem = false;
+		return NULL;
+	}
+	return ttm_kmap_obj_virtual(kmap, is_iomem);
+}
+
+void smi_bo_kunmap(struct smi_bo *bo)
+{
+	struct ttm_bo_kmap_obj *kmap = &bo->kmap;
+
+	if (!kmap->virtual)
+		return;
+
+	ttm_bo_kunmap(kmap);
+	kmap->virtual = NULL;
+}
+#endif
\ No newline at end of file
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index fa04e62202c1..8327e9651719 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -326,6 +326,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
 	if (ret)
 		return ret;
 
+#if 0
 	if (num_pages == 1 && ttm->caching == ttm_cached) {
 		/*
 		 * We're mapping a single page, and the desired
@@ -335,7 +336,9 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
 		map->bo_kmap_type = ttm_bo_map_kmap;
 		map->page = ttm->pages[start_page];
 		map->virtual = kmap(map->page);
-	} else {
+	} else 
+#endif
+	{
 		/*
 		 * We need to use vmap to get the desired page protection
 		 * or to make the buffer object look contiguous.
diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c
index b3fffe7b5062..f910f22827ac 100644
--- a/drivers/gpu/drm/ttm/ttm_module.c
+++ b/drivers/gpu/drm/ttm/ttm_module.c
@@ -63,7 +63,7 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp)
 {
 	/* Cached mappings need no adjustment */
 	if (caching == ttm_cached)
-		return tmp;
+		caching = ttm_write_combined;
 
 #if defined(__i386__) || defined(__x86_64__)
 	if (caching == ttm_write_combined)
@@ -74,7 +74,8 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp)
 #endif /* CONFIG_UML */
 #endif /* __i386__ || __x86_64__ */
 #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \
-	defined(__powerpc__) || defined(__mips__) || defined(__loongarch__)
+	defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) || \
+	defined(__riscv)
 	if (caching == ttm_write_combined)
 		tmp = pgprot_writecombine(tmp);
 	else
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 3287032a2f8e..b9db55d9c1ec 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -186,7 +186,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo,
 	res->bus.addr = NULL;
 	res->bus.offset = 0;
 	res->bus.is_iomem = false;
-	res->bus.caching = ttm_cached;
+	res->bus.caching = ttm_write_combined;
 	res->bo = bo;
 
 	man = ttm_manager_type(bo->bdev, place->mem_type);
@@ -672,16 +672,18 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io,
 
 		iter_io->needs_unmap = true;
 		memset(&iter_io->dmap, 0, sizeof(iter_io->dmap));
-		if (mem->bus.caching == ttm_write_combined)
+		if (mem->bus.caching == ttm_write_combined || mem->bus.caching == ttm_cached)
 			iosys_map_set_vaddr_iomem(&iter_io->dmap,
 						  ioremap_wc(mem->bus.offset,
 							     bus_size));
+#if 0
 		else if (mem->bus.caching == ttm_cached)
 			iosys_map_set_vaddr(&iter_io->dmap,
 					    memremap(mem->bus.offset, bus_size,
 						     MEMREMAP_WB |
 						     MEMREMAP_WT |
 						     MEMREMAP_WC));
+#endif
 
 		/* If uncached requested or if mapping cached or wc failed */
 		if (iosys_map_is_null(&iter_io->dmap))
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index d505603930a7..c5b7647f1315 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -136,7 +136,7 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm,
 			       unsigned long extra_pages)
 {
 	ttm->num_pages = (PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT) + extra_pages;
-	ttm->caching = ttm_cached;
+	ttm->caching = ttm_write_combined;
 	ttm->page_flags = page_flags;
 	ttm->dma_address = NULL;
 	ttm->swap_storage = NULL;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index d84bdb69f56b..41a8201cb665 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -699,6 +699,20 @@ config MMC_SDHCI_SPRD
 
 	  If unsure, say N.
 
+config MMC_SDHCI_SOPHGO
+	tristate "Sophgo/BitMain SDIO host Controller"
+	depends on MMC_SDHCI_PLTFM
+	help
+	  This selects the SDIO Host Controller in Sophgo/BitMain
+	  SoCs.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sdhci-sophgo.
+
 config MMC_TMIO_CORE
 	tristate
 
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4e4ceb32c4b4..9cfc239cb293 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32)	+= sdhci-pic32.o
 obj-$(CONFIG_MMC_SDHCI_BRCMSTB)		+= sdhci-brcmstb.o
 obj-$(CONFIG_MMC_SDHCI_OMAP)		+= sdhci-omap.o
 obj-$(CONFIG_MMC_SDHCI_SPRD)		+= sdhci-sprd.o
+obj-$(CONFIG_MMC_SDHCI_SOPHGO)		+= sdhci-sophgo.o
 obj-$(CONFIG_MMC_CQHCI)			+= cqhci.o
 cqhci-y					+= cqhci-core.o
 cqhci-$(CONFIG_MMC_CRYPTO)		+= cqhci-crypto.o
diff --git a/drivers/mmc/host/sdhci-sophgo.c b/drivers/mmc/host/sdhci-sophgo.c
new file mode 100644
index 000000000000..8200ccaa68f6
--- /dev/null
+++ b/drivers/mmc/host/sdhci-sophgo.c
@@ -0,0 +1,619 @@
+/*
+ * Sophgo SDHCI Platform driver
+ *
+ * Copyright (c) 2013-2014, 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/mmc.h>
+#include <linux/slab.h>
+#include <linux/reset.h>
+#include "sdhci-pltfm.h"
+#include "sdhci-sophgo.h"
+
+#define DRIVER_NAME "bm"
+
+#define BM_SDHCI_VENDOR_OFFSET		0x500
+#define BM_SDHCI_VENDOR_MSHC_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x8)
+#define BM_SDHCI_VENDOR_A_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x40)
+#define BM_SDHCI_VENDOR_A_STAT_R (BM_SDHCI_VENDOR_OFFSET + 0x44)
+
+static void bm_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
+{
+	sdhci_writel(host, 0x0, BM_SDHCI_VENDOR_MSHC_CTRL_R);
+	sdhci_writel(host, 0x18, BM_SDHCI_VENDOR_A_CTRL_R);
+	sdhci_writel(host, tap, BM_SDHCI_VENDOR_A_STAT_R);
+}
+
+static int sdhci_bm_execute_software_tuning(struct sdhci_host *host, u32 opcode)
+{
+	unsigned int maxwidth = 0;
+	unsigned int tuntap;
+	struct {
+		unsigned int start;
+		unsigned int end;
+		unsigned int width;
+	} tunlist[4];
+	unsigned int listcount;
+	unsigned int listsel;
+
+	unsigned int tun = 0;
+	unsigned int max = 256;
+	int i;
+
+	listcount = 0;
+	for (i = 0; i < ARRAY_SIZE(tunlist); i++) {
+		while (tun < max) {
+			bm_sdhci_set_tap(host, tun);
+			if (!mmc_send_tuning(host->mmc, opcode, NULL))
+				break;
+			tun++;
+		}
+		tunlist[i].start = tun;
+		tun++;
+		while (tun < max) {
+			bm_sdhci_set_tap(host, tun);
+			if (mmc_send_tuning(host->mmc, opcode, NULL))
+				break;
+			tun++;
+		}
+		tunlist[i].end = tun-1;
+		tunlist[i].width = tunlist[i].end - tunlist[i].start;
+		listcount++;
+		tun++;
+		pr_info("%s id:%d start:%d end:%d width:%d\n", mmc_hostname(host->mmc),
+			i, tunlist[i].start, tunlist[i].end, tunlist[i].width);
+		if (tun >= max)
+			break;
+	}
+
+	//find maxwidth
+	listsel = 0;
+	for (i = 0; i < listcount; i++) {
+		if (tunlist[i].width > maxwidth) {
+			maxwidth = tunlist[i].width;
+			listsel = i;
+		}
+	}
+	tuntap = tunlist[listsel].start + (tunlist[listsel].width/2);
+
+	/* The TRM states the ideal tap value is at 75% in the passing range. */
+	bm_sdhci_set_tap(host, tuntap);
+	pr_info("%s listsel:%d tuntap:%d\n",
+		mmc_hostname(host->mmc), listsel, tuntap);
+
+	return mmc_send_tuning(host->mmc, opcode, NULL);
+}
+
+static int sdhci_bm_select_drive_strength(struct mmc_card *card,
+		unsigned int max_dtr, int host_drv,
+		int card_drv, int *drv_type)
+{
+	struct sdhci_host *host = mmc_priv(card->host);
+	struct mmc_host *mmc = host->mmc;
+	uint32_t reg;
+	int driver_type;
+
+	pr_info("%s max_dtr %d, host_drv %d, card_drv %d, drv_type %d\n",
+		mmc_hostname(mmc),
+		max_dtr, host_drv, card_drv, *drv_type);
+
+	driver_type = MMC_SET_DRIVER_TYPE_C;
+	*drv_type = MMC_SET_DRIVER_TYPE_C;
+
+	reg = (1 << PHY_CNFG_PHY_PWRGOOD) | (0xe << PHY_CNFG_PAD_SP) |
+		(0xe << PHY_CNFG_PAD_SN) | (1 << PHY_CNFG_PHY_RSTN);
+	sdhci_writel(host, reg, SDHCI_P_PHY_CNFG);
+
+	return driver_type;
+}
+
+static void sdhci_bm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+	struct mmc_host *mmc = host->mmc;
+	u16 ctrl_2;
+
+	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	/* Select Bus Speed Mode for host */
+	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+	switch (uhs) {
+	case MMC_TIMING_UHS_SDR12:
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+		break;
+	case MMC_TIMING_UHS_SDR25:
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+		break;
+	case MMC_TIMING_UHS_SDR50:
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+		break;
+	case MMC_TIMING_MMC_HS200:
+	case MMC_TIMING_UHS_SDR104:
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+		break;
+	case MMC_TIMING_UHS_DDR50:
+	case MMC_TIMING_MMC_DDR52:
+		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+		break;
+	}
+
+	/*
+	 * When clock frequency is less than 100MHz, the feedback clock must be
+	 * provided and DLL must not be used so that tuning can be skipped. To
+	 * provide feedback clock, the mode selection can be any value less
+	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
+	 */
+	if (host->clock <= 100000000 &&
+	    (uhs == MMC_TIMING_MMC_HS400 ||
+	     uhs == MMC_TIMING_MMC_HS200 ||
+	     uhs == MMC_TIMING_UHS_SDR104))
+		ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+
+	dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
+		mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
+	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
+static unsigned int bm_sdhci_get_min_clock(struct sdhci_host *host)
+{
+	return 200 * 1000;
+}
+
+static unsigned int bm_sdhci_get_max_clock(struct sdhci_host *host)
+{
+	return 50 * 1000 * 1000;
+}
+
+#if 0 // FIXME, SD card not working after this.
+static void bm_sdhci_hw_reset(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_bm_host *bm_host;
+	struct mmc_host *mmc = host->mmc;
+
+	pltfm_host = sdhci_priv(host);
+	bm_host = sdhci_pltfm_priv(pltfm_host);
+
+	pr_info("%s hardware reset\n", mmc_hostname(mmc));
+	reset_control_assert(bm_host->reset);
+	udelay(10);
+	reset_control_deassert(bm_host->reset);
+}
+#endif
+
+void bm_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+#if 0 // FIXME, SD card not working after this.
+	bm_sdhci_hw_reset(host);
+#endif
+	sdhci_reset(host, mask);
+
+	if (mask & SDHCI_RESET_ALL)
+		bm_sdhci_phy_init(host);
+}
+
+int bm_sdhci_phy_init(struct sdhci_host *host)
+{
+	// Asset reset of phy
+	sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) & ~(1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG);
+
+	// Set PAD_SN PAD_SP
+	sdhci_writel(host,
+		     (1 << PHY_CNFG_PHY_PWRGOOD) | (0x9 << PHY_CNFG_PAD_SP) | (0x8 << PHY_CNFG_PAD_SN),
+		     SDHCI_P_PHY_CNFG);
+
+	// Set CMDPAD
+	sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+			(0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_CMDPAD_CNFG);
+
+	// Set DATAPAD
+	sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+			(0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_DATPAD_CNFG);
+
+	// Set CLKPAD
+	sdhci_writew(host,
+		     (0x2 << PAD_CNFG_RXSEL) | (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N),
+		     SDHCI_P_CLKPAD_CNFG);
+
+	// Set STB_PAD
+	sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (0x2 << PAD_CNFG_WEAKPULL_EN) |
+			(0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_STBPAD_CNFG);
+
+	// Set RSTPAD
+	sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+			(0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_RSTNPAD_CNFG);
+
+	// Set SDCLKDL_CNFG, EXTDLY_EN = 1, fix delay
+	sdhci_writeb(host, (1 << SDCLKDL_CNFG_EXTDLY_EN), SDHCI_P_SDCLKDL_CNFG);
+
+	// Add 10 * 70ps = 0.7ns for output delay
+	sdhci_writeb(host, 10, SDHCI_P_SDCLKDL_DC);
+
+	//if (host->index == 1) {
+	//	 Set SMPLDL_CNFG, Bypass
+	sdhci_writeb(host, (1 << SMPLDL_CNFG_BYPASS_EN), SDHCI_P_SMPLDL_CNFG);
+	//}
+	//else {
+	//	Set SMPLDL_CNFG, INPSEL_CNFG = 0x2
+	//sdhci_writeb(host, (0x2 << SMPLDL_CNFG_INPSEL_CNFG), SDHCI_P_SMPLDL_CNFG);
+	//}
+
+	// Set ATDL_CNFG, tuning clk not use for init
+	sdhci_writeb(host, (2 << ATDL_CNFG_INPSEL_CNFG), SDHCI_P_ATDL_CNFG);
+
+	// deasset reset of phy
+	sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) | (1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG);
+
+	return 0;
+}
+
+void bm_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	sdhci_set_clock(host, clock);
+
+	if (clock == 0)
+		// forward tx
+		sdhci_writeb(host, 0x0, SDHCI_P_SDCLKDL_DC);
+	else
+		// revert tx
+		sdhci_writeb(host, 0x10, SDHCI_P_SDCLKDL_DC);
+}
+
+/*
+ * If DMA addr spans 128MB boundary, we split the DMA transfer into two
+ * so that each DMA transfer doesn't exceed the boundary.
+ */
+#define BOUNDARY_OK(addr, len) \
+	((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
+
+static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
+				    dma_addr_t addr, int len, unsigned int cmd)
+{
+	int tmplen, offset;
+
+	if (likely(!len || BOUNDARY_OK(addr, len))) {
+		sdhci_adma_write_desc(host, desc, addr, len, cmd);
+		return;
+	}
+
+	offset = addr & (SZ_128M - 1);
+	tmplen = SZ_128M - offset;
+	sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
+
+	addr += tmplen;
+	len -= tmplen;
+	sdhci_adma_write_desc(host, desc, addr, len, cmd);
+}
+
+
+/* ------------- bm palludium sdcard --------------- */
+static const struct sdhci_ops sdhci_bm_pldm_sd_ops = {
+	.reset = bm_sdhci_reset,
+	.set_clock = bm_sdhci_set_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.set_uhs_signaling = sdhci_bm_set_uhs_signaling,
+	.get_max_clock = bm_sdhci_get_max_clock,
+	.get_min_clock = bm_sdhci_get_min_clock,
+	.adma_write_desc = dwcmshc_adma_write_desc,
+};
+
+static const struct sdhci_pltfm_data sdhci_bm_pldm_sd_pdata = {
+	.ops = &sdhci_bm_pldm_sd_ops,
+	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_INVERTED_WRITE_PROTECT,
+	.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
+};
+
+static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
+{
+	return cmd->data || cmd->flags & MMC_RSP_BUSY;
+}
+
+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
+{
+	if (sdhci_data_line_cmd(mrq->cmd))
+		del_timer(&host->data_timer);
+	else
+		del_timer(&host->timer);
+}
+
+int bm_platform_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+	u16 ctrl;
+	int tuning_loop_counter = 0;
+	int err = 0;
+	unsigned long flags;
+	unsigned int tuning_count = 0;
+	bool hs400_tuning;
+	int hit = 0;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	hs400_tuning = host->flags & SDHCI_HS400_TUNING;
+	host->flags &= ~SDHCI_HS400_TUNING;
+
+	if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+		tuning_count = host->tuning_count;
+
+	switch (host->timing) {
+	/* HS400 tuning is done in HS200 mode */
+	case MMC_TIMING_MMC_HS400:
+		err = -EINVAL;
+		goto out_unlock;
+
+	case MMC_TIMING_MMC_HS200:
+		/*
+		 * Periodic re-tuning for HS400 is not expected to be needed, so
+		 * disable it here.
+		 */
+		if (hs400_tuning)
+			tuning_count = 0;
+		break;
+
+	case MMC_TIMING_UHS_SDR104:
+	case MMC_TIMING_UHS_DDR50:
+		break;
+
+	case MMC_TIMING_UHS_SDR50:
+		if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
+			break;
+
+	default:
+		goto out_unlock;
+	}
+
+	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	ctrl |= SDHCI_CTRL_EXEC_TUNING;
+
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+	sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+
+	sdhci_writew(host, 0x704b | (0x3<<4) | (0x1<<3), SDHCI_HOST_CONTROL2);/*drv_strength | 1.8v*/
+
+	sdhci_writel(host, 0, SDHCI_DMA_ADDRESS);/*sdmasa*/
+	sdhci_writel(host, 0, SDHCI_MSHC_CTRL);
+
+	sdhci_writel(host, 0x18, SDHCI_AT_CTRL);
+
+	sdhci_writew(host, 0x0, SDHCI_BLOCK_COUNT);
+	sdhci_writew(host, 0x1040, SDHCI_BLOCK_SIZE);
+	sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+	do {
+		struct mmc_command cmd = {0};
+		struct mmc_request mrq = {NULL};
+
+		cmd.opcode = opcode;
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		cmd.retries = 0;
+		cmd.data = NULL;
+		cmd.mrq = &mrq;
+		cmd.error = 0;
+
+		sdhci_writel(host, tuning_loop_counter, SDHCI_AT_STAT);
+		mrq.cmd = &cmd;
+		sdhci_send_command(host, &cmd);
+
+		host->cmd = NULL;
+		sdhci_del_timer(host, &mrq);
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		/* Wait for Buffer Read Ready interrupt */
+		wait_event_timeout(host->buf_ready_int,
+					(host->tuning_done == 1),
+					msecs_to_jiffies(10));
+
+		spin_lock_irqsave(&host->lock, flags);
+		if (host->tuning_done == 1) {
+			u16 stat;
+
+			stat = sdhci_readw(host, SDHCI_ERR_INT_STATUS) & 0x3F;
+			if (stat == 0)
+				hit = tuning_loop_counter;
+		}
+
+		host->tuning_done = 0;
+		tuning_loop_counter++;
+		sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS);
+		sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS);
+		sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET);
+	} while (tuning_loop_counter < MAX_TUNING_STEP);
+
+	if (tuning_loop_counter >= MAX_TUNING_STEP) {
+		ctrl &= ~(SDHCI_CTRL_TUNED_CLK | SDHCI_CTRL_EXEC_TUNING);
+		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+	}
+
+	sdhci_writel(host, 0, SDHCI_AT_CTRL);
+	sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS);/*clear normal int*/
+	sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS);/*clear error int*/
+	sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) | (0x1<<4), SDHCI_AT_CTRL);/*en sw_tuning_en bit*/
+	sdhci_writel(host, (sdhci_readl(host, SDHCI_AT_STAT) & (~0xFF)) | hit, SDHCI_AT_STAT);/*center_ph_code*/
+	sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) & (~(0x1<<4)), SDHCI_AT_CTRL);/*dis sw_tuning_en bit*/
+	sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET);
+
+	if (tuning_count)
+		err = 0;
+
+	host->mmc->retune_period = err ? 0 : tuning_count;
+
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+out_unlock:
+	spin_unlock_irqrestore(&host->lock, flags);
+	return err;
+}
+
+/* ------------- bm palludium emmc --------------- */
+static const struct sdhci_ops sdhci_bm_pldm_emmc_ops = {
+	.reset = sdhci_reset,
+	.set_clock = sdhci_set_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.set_uhs_signaling = sdhci_bm_set_uhs_signaling,
+	.get_max_clock = bm_sdhci_get_max_clock,
+	.get_min_clock = bm_sdhci_get_min_clock,
+	.platform_execute_tuning = bm_platform_execute_tuning,
+	.adma_write_desc = dwcmshc_adma_write_desc,
+};
+
+static const struct sdhci_pltfm_data sdhci_bm_pldm_emmc_pdata = {
+	.ops = &sdhci_bm_pldm_emmc_ops,
+	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+};
+
+/* ------------ bm asic ------------ */
+static const struct sdhci_ops sdhci_bm_ops = {
+	.reset = bm_sdhci_reset,
+	.set_clock = sdhci_set_clock,
+	.set_bus_width = sdhci_set_bus_width,
+	.set_uhs_signaling = sdhci_bm_set_uhs_signaling,
+	.platform_execute_tuning = sdhci_bm_execute_software_tuning,
+	.adma_write_desc = dwcmshc_adma_write_desc,
+};
+
+static const struct sdhci_pltfm_data sdhci_bm_emmc_pdata = {
+	.ops = &sdhci_bm_ops,
+	.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT,
+	.quirks2 = 0,
+};
+
+static const struct sdhci_pltfm_data sdhci_bm_sd_pdata = {
+	.ops = &sdhci_bm_ops,
+	.quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT,
+	.quirks2 = 0,
+};
+
+static const struct of_device_id sdhci_bm_dt_match[] = {
+	{.compatible = "bitmain,bm-pldm-sdcard", .data = &sdhci_bm_pldm_sd_pdata},
+	{.compatible = "bitmain,bm-pldm-emmc", .data = &sdhci_bm_pldm_emmc_pdata},
+	{.compatible = "bitmain,bm-emmc", .data = &sdhci_bm_emmc_pdata},
+	{.compatible = "bitmain,bm-sd", .data = &sdhci_bm_sd_pdata},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sdhci_bm_dt_match);
+
+static int sdhci_bm_probe(struct platform_device *pdev)
+{
+	struct sdhci_host *host;
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_bm_host *bm_host;
+	const struct of_device_id *match;
+	const struct sdhci_pltfm_data *pdata;
+	int ret;
+
+	match = of_match_device(sdhci_bm_dt_match, &pdev->dev);
+	if (!match)
+		return -EINVAL;
+
+	pdata = match->data;
+
+	host = sdhci_pltfm_init(pdev, pdata, sizeof(*bm_host));
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+	bm_host = sdhci_pltfm_priv(pltfm_host);
+	bm_host->mmc = host->mmc;
+	bm_host->pdev = pdev;
+	bm_host->core_mem = host->ioaddr;
+
+	ret = mmc_of_parse(host->mmc);
+	if (ret)
+		goto pltfm_free;
+
+	sdhci_get_of_property(pdev);
+
+	if (host->mmc->caps2 & MMC_CAP2_NO_SD) {
+		bm_host->reset = devm_reset_control_get(&pdev->dev, "emmc");
+		if (IS_ERR(bm_host->reset)) {
+			ret = PTR_ERR(bm_host->reset);
+			goto pltfm_free;
+		}
+
+		bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_emmc");
+		if (IS_ERR(bm_host->clkaxi))
+			dev_err(&pdev->dev, "get emmc clk axi failed\n");
+		else
+			clk_prepare_enable(bm_host->clkaxi);
+		bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_emmc");
+		if (IS_ERR(bm_host->clk))
+			dev_err(&pdev->dev, "get emmc clk failed\n");
+		else
+			clk_prepare_enable(bm_host->clk);
+		bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_emmc");
+		if (IS_ERR(bm_host->clk100k))
+			dev_err(&pdev->dev, "get emmc clk 100k failed\n");
+		else
+			clk_prepare_enable(bm_host->clk100k);
+	} else if (host->mmc->caps2 & MMC_CAP2_NO_MMC) {
+		bm_host->reset = devm_reset_control_get(&pdev->dev, "sdio");
+		if (IS_ERR(bm_host->reset)) {
+			ret = PTR_ERR(bm_host->reset);
+			goto pltfm_free;
+		}
+
+		bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_sd");
+		if (IS_ERR(bm_host->clkaxi))
+			dev_err(&pdev->dev, "get sd clk axi failed\n");
+		else
+			clk_prepare_enable(bm_host->clkaxi);
+		bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_sd");
+		if (IS_ERR(bm_host->clk))
+			dev_err(&pdev->dev, "get sd clk failed\n");
+		else
+			clk_prepare_enable(bm_host->clk);
+		bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_sd");
+		if (IS_ERR(bm_host->clk100k))
+			dev_err(&pdev->dev, "get sd clk 100k failed\n");
+		else
+			clk_prepare_enable(bm_host->clk100k);
+	}
+
+	host->mmc_host_ops.select_drive_strength = sdhci_bm_select_drive_strength;
+
+	ret = sdhci_add_host(host);
+	if (ret)
+		goto err_add_host;
+
+	return 0;
+
+err_add_host:
+pltfm_free:
+	sdhci_pltfm_free(pdev);
+	return ret;
+}
+
+static int sdhci_bm_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
+	sdhci_pltfm_free(pdev);
+	return 0;
+}
+
+static struct platform_driver sdhci_bm_driver = {
+	.probe = sdhci_bm_probe,
+	.remove = sdhci_bm_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = sdhci_bm_dt_match,
+	},
+};
+
+module_platform_driver(sdhci_bm_driver);
+MODULE_DESCRIPTION("BitMain Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/sdhci-sophgo.h b/drivers/mmc/host/sdhci-sophgo.h
new file mode 100644
index 000000000000..956a74db023c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-sophgo.h
@@ -0,0 +1,122 @@
+/*
+ * drivers/mmc/host/sdhci-bm.c - BitMain SDHCI Platform driver
+ *
+ * Copyright (c) 2013-2014, 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.
+ *
+ */
+
+#ifndef __SDHCI_BM_H
+#define __SDHCI_BM_H
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/mmc.h>
+#include <linux/slab.h>
+
+/*register macro */
+#define P_VENDOR_SPECIFIC_AREA		0xE8
+#define P_VENDOR2_SPECIFIC_AREA		0xEA
+#define VENDOR_EMMC_CTRL		0x2C
+#define SW_RST_R			0x2F
+#define SDHCI_NORMAL_INT_STATUS		0x30
+#define SDHCI_ERR_INT_STATUS		0x32
+#define SDHCI_ERR_INT_STATUS_EN		0x36
+#define SDHCI_HOST_CTRL2_R		0x3E
+#define SDHCI_MSHC_CTRL			0x508
+#define SDHCI_AT_CTRL			0x540
+#define SDHCI_AT_STAT			0x544
+
+/* PHY register */
+#define SDHCI_PHY_R_OFFSET			0x300
+
+#define SDHCI_P_PHY_CNFG           (SDHCI_PHY_R_OFFSET + 0x00)
+#define SDHCI_P_CMDPAD_CNFG        (SDHCI_PHY_R_OFFSET + 0x04)
+#define SDHCI_P_DATPAD_CNFG        (SDHCI_PHY_R_OFFSET + 0x06)
+#define SDHCI_P_CLKPAD_CNFG        (SDHCI_PHY_R_OFFSET + 0x08)
+#define SDHCI_P_STBPAD_CNFG        (SDHCI_PHY_R_OFFSET + 0x0A)
+#define SDHCI_P_RSTNPAD_CNFG       (SDHCI_PHY_R_OFFSET + 0x0C)
+#define SDHCI_P_PADTEST_CNFG       (SDHCI_PHY_R_OFFSET + 0x0E)
+#define SDHCI_P_PADTEST_OUT        (SDHCI_PHY_R_OFFSET + 0x10)
+#define SDHCI_P_PADTEST_IN         (SDHCI_PHY_R_OFFSET + 0x12)
+#define SDHCI_P_COMMDL_CNFG        (SDHCI_PHY_R_OFFSET + 0x1C)
+#define SDHCI_P_SDCLKDL_CNFG       (SDHCI_PHY_R_OFFSET + 0x1D)
+#define SDHCI_P_SDCLKDL_DC         (SDHCI_PHY_R_OFFSET + 0x1E)
+#define SDHCI_P_SMPLDL_CNFG        (SDHCI_PHY_R_OFFSET + 0x20)
+#define SDHCI_P_ATDL_CNFG          (SDHCI_PHY_R_OFFSET + 0x21)
+#define SDHCI_P_DLL_CTRL           (SDHCI_PHY_R_OFFSET + 0x24)
+#define SDHCI_P_DLL_CNFG1          (SDHCI_PHY_R_OFFSET + 0x25)
+#define SDHCI_P_DLL_CNFG2          (SDHCI_PHY_R_OFFSET + 0x26)
+#define SDHCI_P_DLLDL_CNFG         (SDHCI_PHY_R_OFFSET + 0x28)
+#define SDHCI_P_DLL_OFFST          (SDHCI_PHY_R_OFFSET + 0x29)
+#define SDHCI_P_DLLMST_TSTDC       (SDHCI_PHY_R_OFFSET + 0x2A)
+#define SDHCI_P_DLLLBT_CNFG        (SDHCI_PHY_R_OFFSET + 0x2C)
+#define SDHCI_P_DLL_STATUS         (SDHCI_PHY_R_OFFSET + 0x2E)
+#define SDHCI_P_DLLDBG_MLKDC       (SDHCI_PHY_R_OFFSET + 0x30)
+#define SDHCI_P_DLLDBG_SLKDC       (SDHCI_PHY_R_OFFSET + 0x32)
+
+#define PHY_CNFG_PHY_RSTN               0
+#define PHY_CNFG_PHY_PWRGOOD            1
+#define PHY_CNFG_PAD_SP                 16
+#define PHY_CNFG_PAD_SP_MSK             0xf
+#define PHY_CNFG_PAD_SN                 20
+#define PHY_CNFG_PAD_SN_MSK             0xf
+
+#define PAD_CNFG_RXSEL                  0
+#define PAD_CNFG_RXSEL_MSK              0x7
+#define PAD_CNFG_WEAKPULL_EN            3
+#define PAD_CNFG_WEAKPULL_EN_MSK        0x3
+#define PAD_CNFG_TXSLEW_CTRL_P          5
+#define PAD_CNFG_TXSLEW_CTRL_P_MSK      0xf
+#define PAD_CNFG_TXSLEW_CTRL_N          9
+#define PAD_CNFG_TXSLEW_CTRL_N_MSK      0xf
+
+#define COMMDL_CNFG_DLSTEP_SEL          0
+#define COMMDL_CNFG_DLOUT_EN            1
+
+#define SDCLKDL_CNFG_EXTDLY_EN          0
+#define SDCLKDL_CNFG_BYPASS_EN          1
+#define SDCLKDL_CNFG_INPSEL_CNFG        2
+#define SDCLKDL_CNFG_INPSEL_CNFG_MSK    0x3
+#define SDCLKDL_CNFG_UPDATE_DC          4
+
+#define SMPLDL_CNFG_EXTDLY_EN           0
+#define SMPLDL_CNFG_BYPASS_EN           1
+#define SMPLDL_CNFG_INPSEL_CNFG         2
+#define SMPLDL_CNFG_INPSEL_CNFG_MSK     0x3
+#define SMPLDL_CNFG_INPSEL_OVERRIDE     4
+
+#define ATDL_CNFG_EXTDLY_EN             0
+#define ATDL_CNFG_BYPASS_EN             1
+#define ATDL_CNFG_INPSEL_CNFG           2
+#define ATDL_CNFG_INPSEL_CNFG_MSK       0x3
+
+#define MAX_TUNING_STEP                           128
+
+struct sdhci_bm_host {
+	struct platform_device *pdev;
+	void __iomem *core_mem; /* bm SDCC mapped address */
+	struct clk *clk;    /* main SD/MMC bus clock */
+	struct clk *clk100k;
+	struct clk *clkaxi;
+	struct mmc_host *mmc;
+	struct reset_control *reset;
+
+	struct reset_control *clk_rst_axi_emmc_ctrl;
+	struct reset_control *clk_rst_emmc_ctrl;
+	struct reset_control *clk_rst_100k_emmc_ctrl;
+};
+
+int bm_sdhci_phy_init(struct sdhci_host *host);
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
+#endif
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ad73d528a1bd..f992bd3a162a 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -49,8 +49,6 @@ static unsigned int debug_quirks2;
 
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
-
 void sdhci_dumpregs(struct sdhci_host *host)
 {
 	SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
@@ -1641,7 +1639,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
 	__sdhci_finish_data(host, false);
 }
 
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	int flags;
 	u32 mask;
@@ -1732,6 +1730,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(sdhci_send_command);
 
 static bool sdhci_present_error(struct sdhci_host *host,
 				struct mmc_command *cmd, bool present)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 5ce7cdcc192f..b44bdac6b73b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -818,5 +818,5 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
 void sdhci_switch_external_dma(struct sdhci_host *host, bool en);
 void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable);
 void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
-
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
 #endif /* __SDHCI_HW_H */
diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig
index ca45dcd3ffe8..d2138370f1fc 100644
--- a/drivers/mtd/spi-nor/controllers/Kconfig
+++ b/drivers/mtd/spi-nor/controllers/Kconfig
@@ -16,3 +16,14 @@ config SPI_NXP_SPIFI
 	  SPIFI is a specialized controller for connecting serial SPI
 	  Flash. Enable this option if you have a device with a SPIFI
 	  controller and want to access the Flash as a mtd device.
+
+config SPI_SOPHGO_SPIFMC
+	tristate "Sophgo SPI Flash Master Controller (SPIFMC)"
+	depends on ARCH_SOPHGO || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  Enable support for the Sophgo SPI Flash Master controller.
+
+	  SPIFMC is a master controller to control serial SPI Flash.
+	  Enable this option if you have a device with a SPIFMC controller
+	  and want to access the Flash as a mtd device.
diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile
index 0b8e1d530913..627ac8850ab1 100644
--- a/drivers/mtd/spi-nor/controllers/Makefile
+++ b/drivers/mtd/spi-nor/controllers/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
 obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
+obj-$(CONFIG_SPI_SOPHGO_SPIFMC) += sophgo-spifmc.o
diff --git a/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c b/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c
new file mode 100644
index 000000000000..f7d85cc03137
--- /dev/null
+++ b/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SPI Flash Master Controller (SPIFMC)
+ *
+ * Copyright (c) 2023 Sophgo.
+ */
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+/* Hardware register definitions */
+#define SPIFMC_CTRL	0x00
+#define SPIFMC_CTRL_CPHA	BIT(12)
+#define SPIFMC_CTRL_CPOL	BIT(13)
+#define SPIFMC_CTRL_HOLD_OL	BIT(14)
+#define SPIFMC_CTRL_WP_OL	BIT(15)
+#define SPIFMC_CTRL_LSBF	BIT(20)
+#define SPIFMC_CTRL_SRST	BIT(21)
+#define SPIFMC_CTRL_SCK_DIV_SHIFT	0
+#define SPIFMC_CTRL_FRAME_LEN_SHIFT	16
+
+#define SPIFMC_CE_CTRL	0x04
+#define SPIFMC_CE_CTRL_CEMANUAL	BIT(0)
+#define SPIFMC_CE_CTRL_CEMANUAL_EN	BIT(1)
+
+#define SPIFMC_DLY_CTRL	0x08
+#define SPIFMC_CTRL_FM_INTVL_MASK	0x000f
+#define SPIFMC_CTRL_FM_INTVL	BIT(0)
+#define SPIFMC_CTRL_CET_MASK	0x0f00
+#define SPIFMC_CTRL_CET	BIT(8)
+
+#define SPIFMC_DMMR	0x0c
+
+#define SPIFMC_TRAN_CSR	0x10
+#define SPIFMC_TRAN_CSR_TRAN_MODE_MASK	0x0003
+#define SPIFMC_TRAN_CSR_TRAN_MODE_RX	BIT(0)
+#define SPIFMC_TRAN_CSR_TRAN_MODE_TX	BIT(1)
+#define SPIFMC_TRAN_CSR_CNTNS_READ	BIT(2)
+#define SPIFMC_TRAN_CSR_FAST_MODE	BIT(3)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT	(0x00 << 4)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT	(0x01 << 4)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT	(0x02 << 4)
+#define SPIFMC_TRAN_CSR_DMA_EN	BIT(6)
+#define SPIFMC_TRAN_CSR_MISO_LEVEL	BIT(7)
+#define SPIFMC_TRAN_CSR_ADDR_BYTES_MASK	0x0700
+#define SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT	8
+#define SPIFMC_TRAN_CSR_WITH_CMD	BIT(11)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK	0x3000
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE	(0x00 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_2_BYTE	(0x01 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE	(0x02 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE	(0x03 << 12)
+#define SPIFMC_TRAN_CSR_GO_BUSY	BIT(15)
+
+#define SPIFMC_TRAN_NUM	0x14
+#define SPIFMC_FIFO_PORT	0x18
+#define SPIFMC_FIFO_PT	0x20
+
+#define SPIFMC_INT_STS	0x28
+#define SPIFMC_INT_TRAN_DONE	BIT(0)
+#define SPIFMC_INT_RD_FIFO	BIT(2)
+#define SPIFMC_INT_WR_FIFO	BIT(3)
+#define SPIFMC_INT_RX_FRAME	BIT(4)
+#define SPIFMC_INT_TX_FRAME	BIT(5)
+
+#define SPIFMC_INT_EN	0x2c
+#define SPIFMC_INT_TRAN_DONE_EN	BIT(0)
+#define SPIFMC_INT_RD_FIFO_EN	BIT(2)
+#define SPIFMC_INT_WR_FIFO_EN	BIT(3)
+#define SPIFMC_INT_RX_FRAME_EN	BIT(4)
+#define SPIFMC_INT_TX_FRAME_EN	BIT(5)
+
+#define SPIFMC_MAX_FIFO_DEPTH	8
+
+struct sophgo_spifmc {
+	struct device *dev;
+	struct clk *clk;
+	void __iomem *io_base;
+	struct spi_nor nor;
+};
+
+static inline int sophgo_spifmc_wait_int(struct sophgo_spifmc *spifmc,
+		u8 int_type)
+{
+	u32 stat;
+
+	return readl_poll_timeout(spifmc->io_base + SPIFMC_INT_STS, stat,
+			(stat & int_type), 0, 0);
+}
+
+static inline u32 sophgo_spifmc_init_reg(struct sophgo_spifmc *spifmc)
+{
+	u32 reg;
+
+	reg = readl(spifmc->io_base + SPIFMC_TRAN_CSR);
+	reg &= ~(SPIFMC_TRAN_CSR_TRAN_MODE_MASK
+			| SPIFMC_TRAN_CSR_CNTNS_READ
+			| SPIFMC_TRAN_CSR_FAST_MODE
+			| SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT
+			| SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT
+			| SPIFMC_TRAN_CSR_DMA_EN
+			| SPIFMC_TRAN_CSR_ADDR_BYTES_MASK
+			| SPIFMC_TRAN_CSR_WITH_CMD
+			| SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK);
+
+	return reg;
+}
+
+/*
+ * sophgo_spifmc_read_reg is a workaround function:
+ * AHB bus could only do 32-bit access to SPIFMC fifo,
+ * so cmd without 3-byte addr will leave 3-byte data in fifo.
+ * Set TX to mark that these 3-byte data would be sent out.
+ */
+static int sophgo_spifmc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+				 size_t len)
+{
+	struct sophgo_spifmc *spifmc = nor->priv;
+	u32 reg;
+	int ret, i;
+
+	reg = sophgo_spifmc_init_reg(spifmc);
+	reg |= SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT;
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+	reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX | SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+	writeb(opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	for (i = 0; i < len; i++)
+		writeb(0, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_INT_STS);
+	writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+	ret = sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+	if (ret)
+		return ret;
+
+	while (len--)
+		*buf++ = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	return 0;
+}
+
+static int sophgo_spifmc_write_reg(struct spi_nor *nor, u8 opcode,
+				  const u8 *buf, size_t len)
+{
+	struct sophgo_spifmc *spifmc = nor->priv;
+	u32 reg;
+	int i;
+
+	reg = sophgo_spifmc_init_reg(spifmc);
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+
+	/*
+	 * If write values to the Status Register,
+	 * configure TRAN_CSR register as the same as sophgo_spifmc_read_reg.
+	 */
+	if (opcode == SPINOR_OP_WRSR) {
+		reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX | SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+		writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+	}
+
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+	writeb(opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	for (i = 0; i < len; i++)
+		writeb(buf[i], spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_INT_STS);
+	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+	sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	return 0;
+}
+
+static ssize_t sophgo_spifmc_read(struct spi_nor *nor, loff_t from,
+		size_t len, u_char *buf)
+{
+	struct sophgo_spifmc *spifmc = nor->priv;
+	u32 reg;
+	int xfer_size, offset;
+	int i;
+
+	reg = sophgo_spifmc_init_reg(spifmc);
+	reg |= (nor->addr_nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+	reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+	writeb(nor->read_opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	for (i = nor->addr_nbytes - 1; i >= 0; i--)
+		writeb((from >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_INT_STS);
+	writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+	sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_RD_FIFO);
+
+	offset = 0;
+	while (offset < len) {
+		xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset);
+
+		while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != xfer_size)
+			;
+
+		for (i = 0; i < xfer_size; i++)
+			buf[i + offset] = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
+
+		offset += xfer_size;
+	}
+
+	sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	return len;
+}
+
+static ssize_t sophgo_spifmc_write(struct spi_nor *nor, loff_t to,
+		size_t len, const u_char *buf)
+{
+	struct sophgo_spifmc *spifmc = nor->priv;
+	u32 reg;
+	int i, offset;
+	int xfer_size, wait;
+
+	reg = sophgo_spifmc_init_reg(spifmc);
+	reg |= nor->addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+	reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+	writeb(nor->program_opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	for (i = nor->addr_nbytes - 1; i >= 0; i--)
+		writeb((to >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_INT_STS);
+	writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+	while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != 0)
+		;
+
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	offset = 0;
+	while (offset < len) {
+		xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset);
+
+		wait = 0;
+		while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != 0) {
+			wait++;
+			udelay(10);
+			if (wait > 30000) {
+				dev_warn(spifmc->dev, "Wait to write FIFO timeout.\n");
+				return -1;
+			}
+		}
+
+		for (i = 0; i < xfer_size; i++)
+			writeb(buf[i + offset], spifmc->io_base + SPIFMC_FIFO_PORT);
+
+		offset += xfer_size;
+	}
+
+	sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	return len;
+}
+
+static int sophgo_spifmc_erase(struct spi_nor *nor, loff_t offs)
+{
+	struct sophgo_spifmc *spifmc = nor->priv;
+	u32 reg;
+	int i;
+
+	reg = sophgo_spifmc_init_reg(spifmc);
+	reg |= nor->addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+	writeb(nor->erase_opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	for (i = nor->addr_nbytes - 1; i >= 0; i--)
+		writeb((offs >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+	writel(0, spifmc->io_base + SPIFMC_INT_STS);
+	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+	sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+	return 0;
+}
+
+static const struct spi_nor_controller_ops sophgo_spifmc_controller_ops = {
+	.read_reg  = sophgo_spifmc_read_reg,
+	.write_reg = sophgo_spifmc_write_reg,
+	.read  = sophgo_spifmc_read,
+	.write = sophgo_spifmc_write,
+	.erase = sophgo_spifmc_erase,
+};
+
+static void sophgo_spifmc_init(struct sophgo_spifmc *spifmc)
+{
+	u32 reg;
+
+	/* disable DMMR (Direct Memory Mapping Read) */
+	writel(0, spifmc->io_base + SPIFMC_DMMR);
+	/* soft reset */
+	writel(readl(spifmc->io_base + SPIFMC_CTRL) | SPIFMC_CTRL_SRST | 0x3,
+			spifmc->io_base + SPIFMC_CTRL);
+	/* hardware CE contrl, soft reset cannot change the register */
+	writel(0, spifmc->io_base + SPIFMC_CE_CTRL);
+	reg = spifmc->nor.addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE;
+	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+}
+
+static int sophgo_spifmc_register(struct device_node *np,
+				struct sophgo_spifmc *spifmc)
+{
+	/* TODO: support DUAL and QUAD operations */
+	const struct spi_nor_hwcaps hwcaps = {
+		.mask = SNOR_HWCAPS_READ |
+			SNOR_HWCAPS_PP,
+	};
+	int ret;
+
+	spifmc->nor.dev = spifmc->dev;
+	spi_nor_set_flash_node(&spifmc->nor, np);
+	spifmc->nor.priv = spifmc;
+	spifmc->nor.controller_ops = &sophgo_spifmc_controller_ops;
+
+	ret = spi_nor_scan(&spifmc->nor, NULL, &hwcaps);
+	if (ret) {
+		dev_err(spifmc->dev, "Device scan failed.\n");
+		return ret;
+	}
+
+	ret = mtd_device_register(&spifmc->nor.mtd, NULL, 0);
+	if (ret) {
+		dev_err(spifmc->dev, "mtd device parse failed.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int sophgo_spifmc_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct sophgo_spifmc *spifmc;
+	int ret;
+
+	spifmc = devm_kzalloc(&pdev->dev, sizeof(*spifmc), GFP_KERNEL);
+	if (!spifmc)
+		return -ENOMEM;
+
+	spifmc->io_base = devm_platform_ioremap_resource_byname(pdev, "memory");
+	if (IS_ERR(spifmc->io_base))
+		return PTR_ERR(spifmc->io_base);
+
+	spifmc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(spifmc->clk)) {
+		dev_err(&pdev->dev, "AHB clock not found.\n");
+		return PTR_ERR(spifmc->clk);
+	}
+
+	ret = clk_prepare_enable(spifmc->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to enable AHB clock.\n");
+		return ret;
+	}
+
+	spifmc->dev = &pdev->dev;
+	platform_set_drvdata(pdev, spifmc);
+	sophgo_spifmc_init(spifmc);
+
+	np = of_get_next_available_child(pdev->dev.of_node, NULL);
+	if (!np) {
+		dev_err(&pdev->dev, "No SPI flash device to configure.\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	ret = sophgo_spifmc_register(np, spifmc);
+	of_node_put(np);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to register spifmc.\n");
+		goto fail;
+	}
+
+	return ret;
+fail:
+	clk_disable_unprepare(spifmc->clk);
+	return ret;
+}
+
+static int sophgo_spifmc_remove(struct platform_device *pdev)
+{
+	struct sophgo_spifmc *spifmc = platform_get_drvdata(pdev);
+
+	mtd_device_unregister(&spifmc->nor.mtd);
+	clk_disable_unprepare(spifmc->clk);
+
+	return 0;
+}
+
+static const struct of_device_id sophgo_spifmc_match[] = {
+	{.compatible = "sophgo,spifmc"},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sophgo_spifmc_match);
+
+static struct platform_driver sophgo_spifmc_driver = {
+	.probe	= sophgo_spifmc_probe,
+	.remove	= sophgo_spifmc_remove,
+	.driver	= {
+		.name = "sophgo-spifmc",
+		.of_match_table = sophgo_spifmc_match,
+	},
+};
+module_platform_driver(sophgo_spifmc_driver);
+
+MODULE_DESCRIPTION("Sophgo SPI Flash Master Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c
index d57ddaf1525b..c60656702063 100644
--- a/drivers/mtd/spi-nor/gigadevice.c
+++ b/drivers/mtd/spi-nor/gigadevice.c
@@ -33,6 +33,15 @@ static const struct spi_nor_fixups gd25q256_fixups = {
 	.post_bfpt = gd25q256_post_bfpt,
 };
 
+static void gd25lb512me_default_init(struct spi_nor *nor)
+{
+	nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
+}
+
+static const struct spi_nor_fixups gd25lb512me_fixups = {
+	.default_init = gd25lb512me_default_init,
+};
+
 static const struct flash_info gigadevice_nor_parts[] = {
 	{ "gd25q16", INFO(0xc84015, 0, 64 * 1024,  32)
 		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
@@ -67,6 +76,11 @@ static const struct flash_info gigadevice_nor_parts[] = {
 		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
 		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
 		.fixups = &gd25q256_fixups },
+	{ "gd25lb512me", INFO(0xc8671a, 0, 64 * 1024, 1024)
+		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
+		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
+		.fixups = &gd25lb512me_fixups },
 };
 
 const struct spi_nor_manufacturer spi_nor_gigadevice = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 61b9774b3d31..1b18fa4eb082 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -2069,7 +2069,7 @@ enum {
 #define IXGBE_DEVICE_CAPS       0x2C
 #define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11
 #define IXGBE_PCIE_MSIX_82599_CAPS  0x72
-#define IXGBE_MAX_MSIX_VECTORS_82599	0x40
+#define IXGBE_MAX_MSIX_VECTORS_82599	0x09
 #define IXGBE_PCIE_MSIX_82598_CAPS  0x62
 #define IXGBE_MAX_MSIX_VECTORS_82598	0x13
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index d4e12e9ace4f..d04e255204d2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_DWMAC_STI)		+= dwmac-sti.o
 obj-$(CONFIG_DWMAC_STM32)	+= dwmac-stm32.o
 obj-$(CONFIG_DWMAC_SUNXI)	+= dwmac-sunxi.o
 obj-$(CONFIG_DWMAC_SUN8I)	+= dwmac-sun8i.o
+obj-$(CONFIG_ARCH_SOPHGO)	+= dwmac-sophgo.o
 obj-$(CONFIG_DWMAC_DWC_QOS_ETH)	+= dwmac-dwc-qos-eth.o
 obj-$(CONFIG_DWMAC_INTEL_PLAT)	+= dwmac-intel-plat.o
 obj-$(CONFIG_DWMAC_GENERIC)	+= dwmac-generic.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c
new file mode 100644
index 000000000000..d0824f8a6f01
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c
@@ -0,0 +1,268 @@
+/*
+ * DWMAC specific glue layer
+ *
+ * Copyright (c) 2018 Bitmain Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/stmmac.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/of_net.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+
+#include "stmmac_platform.h"
+
+struct bm_mac {
+	struct device *dev;
+	struct reset_control *rst;
+	struct clk *clk_tx;
+	struct clk *gate_clk_tx;
+	struct clk *gate_clk_ref;
+	struct gpio_desc *reset;
+};
+
+static u64 bm_dma_mask = DMA_BIT_MASK(40);
+
+static int bm_eth_reset_phy(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int phy_reset_gpio;
+
+	if (!np)
+		return 0;
+
+	phy_reset_gpio = of_get_named_gpio(np, "phy-reset-gpios", 0);
+
+	if (phy_reset_gpio < 0)
+		return 0;
+
+	if (gpio_request(phy_reset_gpio, "eth-phy-reset"))
+		return 0;
+
+	/* RESET_PU */
+	gpio_direction_output(phy_reset_gpio, 0);
+	mdelay(100);
+
+	gpio_direction_output(phy_reset_gpio, 1);
+	/* RC charging time */
+	mdelay(100);
+
+	return 0;
+}
+
+static void bm_mac_fix_speed(void *priv, unsigned int speed)
+{
+	struct bm_mac *bsp_priv = priv;
+	unsigned long rate = 125000000;
+	bool needs_calibration = false;
+	int err;
+
+	switch (speed) {
+	case SPEED_1000:
+		needs_calibration = true;
+		rate = 125000000;
+		break;
+
+	case SPEED_100:
+		needs_calibration = true;
+		rate = 25000000;
+		break;
+
+	case SPEED_10:
+		needs_calibration = true;
+		rate = 2500000;
+		break;
+
+	default:
+		dev_err(bsp_priv->dev, "invalid speed %u\n", speed);
+		break;
+	}
+
+	if (needs_calibration) {
+		err = clk_set_rate(bsp_priv->clk_tx, rate);
+		if (err < 0)
+			dev_err(bsp_priv->dev, "failed to set TX rate: %d\n"
+					, err);
+	}
+}
+
+void bm_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+	struct bm_mac *bsp_priv = priv;
+
+	clk_disable_unprepare(bsp_priv->gate_clk_tx);
+	clk_disable_unprepare(bsp_priv->gate_clk_ref);
+}
+
+static int bm_validate_ucast_entries(struct device *dev, int ucast_entries)
+{
+	int x = ucast_entries;
+
+	switch (x) {
+	case 1 ... 32:
+	case 64:
+	case 128:
+		break;
+	default:
+		x = 1;
+		dev_info(dev, "Unicast table entries set to unexpected value %d\n",
+			 ucast_entries);
+		break;
+	}
+	return x;
+}
+
+static int bm_validate_mcast_bins(struct device *dev, int mcast_bins)
+{
+	int x = mcast_bins;
+
+	switch (x) {
+	case HASH_TABLE_SIZE:
+	case 128:
+	case 256:
+		break;
+	default:
+		x = 0;
+		dev_info(dev, "Hash table entries set to unexpected value %d\n",
+			 mcast_bins);
+		break;
+	}
+	return x;
+}
+
+static void bm_dwmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat)
+{
+	struct device_node *np = pdev->dev.of_node;
+
+	of_property_read_u32(np, "snps,multicast-filter-bins", &plat->multicast_filter_bins);
+	of_property_read_u32(np, "snps,perfect-filter-entries", &plat->unicast_filter_entries);
+	plat->unicast_filter_entries = bm_validate_ucast_entries(&pdev->dev,
+								 plat->unicast_filter_entries);
+	plat->multicast_filter_bins = bm_validate_mcast_bins(&pdev->dev,
+							     plat->multicast_filter_bins);
+	plat->has_gmac4 = 1;
+	plat->has_gmac = 0;
+	plat->tso_en = 1;
+	plat->pmt = 0;
+}
+
+static int bm_dwmac_probe(struct platform_device *pdev)
+{
+	struct plat_stmmacenet_data *plat_dat;
+	struct stmmac_resources stmmac_res;
+	struct bm_mac *bsp_priv = NULL;
+	struct phy_device *phydev = NULL;
+	struct stmmac_priv *priv = NULL;
+	struct net_device *ndev = NULL;
+	int ret;
+
+	pdev->dev.dma_mask = &bm_dma_mask;
+	pdev->dev.coherent_dma_mask = bm_dma_mask;
+
+	bm_eth_reset_phy(pdev);
+
+	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+	if (ret)
+		return ret;
+
+	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
+	if (IS_ERR(plat_dat))
+		return PTR_ERR(plat_dat);
+
+	bm_dwmac_probe_config_dt(pdev, plat_dat);
+	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+	if (ret)
+		goto err_remove_config_dt;
+
+	bsp_priv = devm_kzalloc(&pdev->dev, sizeof(*bsp_priv), GFP_KERNEL);
+	if (!bsp_priv)
+		return PTR_ERR(bsp_priv);
+
+	bsp_priv->dev = &pdev->dev;
+
+	/* clock setup */
+	bsp_priv->clk_tx = devm_clk_get(&pdev->dev,
+					"clk_tx");
+	if (IS_ERR(bsp_priv->clk_tx))
+		dev_warn(&pdev->dev, "Cannot get mac tx clock!\n");
+	else
+		plat_dat->fix_mac_speed = bm_mac_fix_speed;
+
+	bsp_priv->gate_clk_tx = devm_clk_get(&pdev->dev, "gate_clk_tx");
+	if (IS_ERR(bsp_priv->gate_clk_tx))
+		dev_warn(&pdev->dev, "Cannot get mac tx gating clock!\n");
+	else
+		clk_prepare_enable(bsp_priv->gate_clk_tx);
+
+	bsp_priv->gate_clk_ref = devm_clk_get(&pdev->dev, "gate_clk_ref");
+	if (IS_ERR(bsp_priv->gate_clk_ref))
+		dev_warn(&pdev->dev, "Cannot get mac ref gating clock!\n");
+	else
+		clk_prepare_enable(bsp_priv->gate_clk_ref);
+
+	plat_dat->bsp_priv = bsp_priv;
+	plat_dat->exit = bm_dwmac_exit;
+
+	ndev = dev_get_drvdata(&pdev->dev);
+	priv = netdev_priv(ndev);
+	phydev = mdiobus_get_phy(priv->mii, 0);
+	if (phydev == NULL) {
+		dev_err(&pdev->dev, "Can not get phy in addr 0\n");
+		goto err_remove_config_dt;
+	}
+
+	/* set green LED0 active for transmit, yellow LED1 for link*/
+	ret = phy_write_paged(phydev, 0, 0x1f, 0xd04);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Can not select page 0xd04\n");
+	ret = phy_write_paged(phydev, 0xd04, 0x10, 0x617f);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Can not alter LED Configuration\n");
+	/* disable eee LED function */
+	ret = phy_write_paged(phydev, 0xd04, 0x11, 0x0);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Can not disable EEE Configuration\n");
+	ret = phy_write_paged(phydev, 0, 0x1f, 0);
+	if (ret < 0)
+		dev_err(&pdev->dev, "Can not select page 0\n");
+
+	return 0;
+
+err_remove_config_dt:
+	stmmac_remove_config_dt(pdev, plat_dat);
+
+	return ret;
+}
+
+static const struct of_device_id bm_dwmac_match[] = {
+	{ .compatible = "bitmain,ethernet" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, bm_dwmac_match);
+
+static struct platform_driver bm_dwmac_driver = {
+	.probe  = bm_dwmac_probe,
+	.remove = stmmac_pltfr_remove,
+	.driver = {
+		.name           = "bm-dwmac",
+		.pm		= &stmmac_pltfr_pm_ops,
+		.of_match_table = bm_dwmac_match,
+	},
+};
+module_platform_driver(bm_dwmac_driver);
+
+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>");
+MODULE_DESCRIPTION("Bitmain DWMAC specific glue layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile
index 431303ca75b4..26095625d894 100644
--- a/drivers/net/ethernet/wangxun/txgbe/Makefile
+++ b/drivers/net/ethernet/wangxun/txgbe/Makefile
@@ -1,9 +1,37 @@
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd.
+################################################################################
 #
-# Makefile for the Wangxun(R) 10GbE PCI Express ethernet driver
+# WangXun 10GbE PCI Express Linux Network Driver
+# Copyright(c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
 #
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+################################################################################
 
 obj-$(CONFIG_TXGBE) += txgbe.o
 
-txgbe-objs := txgbe_main.o
+txgbe-y := txgbe_main.o txgbe_dcb.o txgbe_ethtool.o txgbe_lib.o \
+	   txgbe_mbx.o txgbe_sriov.o txgbe_param.o txgbe_phy.o \
+	   txgbe_procfs.o txgbe_hw.o txgbe_mtd.o txgbe_pcierr.o \
+	   txgbe_bp.o kcompat.o
+
+
+txgbe-${CONFIG_DCB} += txgbe_dcb_nl.o
+
+txgbe-${CONFIG_DEBUG_FS} += txgbe_debugfs.o
+
+txgbe-${CONFIG_FCOE:m=y} += txgbe_fcoe.o
+
+txgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += txgbe_ptp.o
+
+txgbe-${CONFIG_SYSFS} += txgbe_sysfs.o
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat.c b/drivers/net/ethernet/wangxun/txgbe/kcompat.c
new file mode 100644
index 000000000000..ef11c9a76a8e
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat.c
@@ -0,0 +1,3027 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on kcompat.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#include "txgbe.h"
+#include "kcompat.h"
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8)) || defined __VMKLNX__
+/* From lib/vsprintf.c */
+#include <asm/div64.h>
+
+static int skip_atoi(const char **s)
+{
+	int i = 0;
+
+	while (isdigit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+#define _kc_ZEROPAD	1		/* pad with zero */
+#define _kc_SIGN	2		/* unsigned/signed long */
+#define _kc_PLUS	4		/* show plus */
+#define _kc_SPACE	8		/* space if plus */
+#define _kc_LEFT	16		/* left justified */
+#define _kc_SPECIAL	32		/* 0x */
+#define _kc_LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+static char *number(char *buf, char *end, long long num, int base, int size, int precision, int type)
+{
+	char c, sign, tmp[66];
+	const char *digits;
+	const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	int i;
+
+	digits = (type & _kc_LARGE) ? large_digits : small_digits;
+	if (type & _kc_LEFT)
+		type &= ~_kc_ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & _kc_ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & _kc_SIGN) {
+		if (num < 0) {
+			sign = '-';
+			num = -num;
+			size--;
+		} else if (type & _kc_PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & _kc_SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & _kc_SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(_kc_ZEROPAD+_kc_LEFT))) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = ' ';
+			++buf;
+		}
+	}
+	if (sign) {
+		if (buf <= end)
+			*buf = sign;
+		++buf;
+	}
+	if (type & _kc_SPECIAL) {
+		if (base == 8) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+		} else if (base == 16) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+			if (buf <= end)
+				*buf = digits[33];
+			++buf;
+		}
+	}
+	if (!(type & _kc_LEFT)) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = c;
+			++buf;
+		}
+	}
+	while (i < precision--) {
+		if (buf <= end)
+			*buf = '0';
+		++buf;
+	}
+	while (i-- > 0) {
+		if (buf <= end)
+			*buf = tmp[i];
+		++buf;
+	}
+	while (size-- > 0) {
+		if (buf <= end)
+			*buf = ' ';
+		++buf;
+	}
+	return buf;
+}
+
+int _kc_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	int len;
+	unsigned long long num;
+	int i, base;
+	char *str, *end, c;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+				/* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+
+	str = buf;
+	end = buf + size - 1;
+
+	if (end < buf - 1) {
+		end = ((void *) -1);
+		size = end - buf + 1;
+	}
+
+	for (; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			if (str <= end)
+				*str = *fmt;
+			++str;
+			continue;
+		}
+
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= _kc_LEFT; goto repeat;
+				case '+': flags |= _kc_PLUS; goto repeat;
+				case ' ': flags |= _kc_SPACE; goto repeat;
+				case '#': flags |= _kc_SPECIAL; goto repeat;
+				case '0': flags |= _kc_ZEROPAD; goto repeat;
+			}
+
+		/* get field width */
+		field_width = -1;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= _kc_LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;
+			if (isdigit(*fmt))
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') {
+			qualifier = *fmt;
+			++fmt;
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+		case 'c':
+			if (!(flags & _kc_LEFT)) {
+				while (--field_width > 0) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+			}
+			c = (unsigned char) va_arg(args, int);
+			if (str <= end)
+				*str = c;
+			++str;
+			while (--field_width > 0) {
+				if (str <= end)
+					*str = ' ';
+				++str;
+			}
+			continue;
+
+		case 's':
+			s = va_arg(args, char *);
+			if (!s)
+				s = "<NULL>";
+
+			len = strnlen(s, precision);
+
+			if (!(flags & _kc_LEFT)) {
+				while (len < field_width--) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+			}
+			for (i = 0; i < len; ++i) {
+				if (str <= end)
+					*str = *s;
+				++str; ++s;
+			}
+			while (len < field_width--) {
+				if (str <= end)
+					*str = ' ';
+				++str;
+			}
+			continue;
+
+		case 'p':
+			if ('M' == *(fmt+1)) {
+				str = get_mac(str, end, va_arg(args, unsigned char *));
+				fmt++;
+			} else	{
+				if (field_width == -1) {
+					field_width = 2*sizeof(void *);
+					flags |= _kc_ZEROPAD;
+				}
+				str = number(str, end,
+						(unsigned long) va_arg(args, void *),
+						16, field_width, precision, flags);
+			}
+			continue;
+
+		case 'n':
+			/* FIXME:
+			* What does C99 say about the overflow case here? */
+			if (qualifier == 'l') {
+				long *ip = va_arg(args, long *);
+				*ip = (str - buf);
+			} else if (qualifier == 'Z') {
+				size_t *ip = va_arg(args, size_t *);
+				*ip = (str - buf);
+			} else {
+				int *ip = va_arg(args, int *);
+				*ip = (str - buf);
+			}
+			continue;
+
+		case '%':
+			if (str <= end)
+				*str = '%';
+			++str;
+			continue;
+
+			/* integer number formats - set up the flags and "break" */
+		case 'o':
+			base = 8;
+			break;
+
+		case 'X':
+			flags |= _kc_LARGE;
+		case 'x':
+			base = 16;
+			break;
+
+		case 'd':
+		case 'i':
+			flags |= _kc_SIGN;
+		case 'u':
+			break;
+
+		default:
+			if (str <= end)
+				*str = '%';
+			++str;
+			if (*fmt) {
+				if (str <= end)
+					*str = *fmt;
+				++str;
+			} else {
+				--fmt;
+			}
+			continue;
+		}
+		if (qualifier == 'L')
+			num = va_arg(args, long long);
+		else if (qualifier == 'l') {
+			num = va_arg(args, unsigned long);
+			if (flags & _kc_SIGN)
+				num = (signed long) num;
+		} else if (qualifier == 'Z') {
+			num = va_arg(args, size_t);
+		} else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & _kc_SIGN)
+				num = (signed short) num;
+		} else {
+			num = va_arg(args, unsigned int);
+			if (flags & _kc_SIGN)
+				num = (signed int) num;
+		}
+		str = number(str, end, num, base,
+				field_width, precision, flags);
+	}
+	if (str <= end)
+		*str = '\0';
+	else if (size > 0)
+		/* don't write out a null byte if the buf size is zero */
+		*end = '\0';
+	/* the trailing null byte doesn't count towards the total
+	* ++str;
+	*/
+	return str-buf;
+}
+
+int _kc_snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = _kc_vsnprintf(buf, size, fmt, args);
+	va_end(args);
+	return i;
+}
+#endif /* < 2.4.8 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 13))
+
+/**************************************/
+/* PCI DMA MAPPING */
+
+#if defined(CONFIG_HIGHMEM)
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+u64
+_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
+					size_t size, int direction)
+{
+	return (((u64) (page - mem_map) << PAGE_SHIFT) + offset +
+		PCI_DRAM_OFFSET);
+}
+
+#else /* CONFIG_HIGHMEM */
+
+u64
+_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
+					size_t size, int direction)
+{
+	return pci_map_single(dev, (void *)page_address(page) + offset, size,
+			      direction);
+}
+
+#endif /* CONFIG_HIGHMEM */
+
+void
+_kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size,
+					int direction)
+{
+	return pci_unmap_single(dev, dma_addr, size, direction);
+}
+
+#endif /* 2.4.13 => 2.4.3 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3))
+
+/**************************************/
+/* PCI DRIVER API */
+
+int
+_kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+	dev->dma_mask = mask;
+	return 0;
+}
+
+int
+_kc_pci_request_regions(struct pci_dev *dev, char *res_name)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(dev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+			if (!request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
+				pci_release_regions(dev);
+				return -EBUSY;
+			}
+		} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
+			if (!request_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
+				pci_release_regions(dev);
+				return -EBUSY;
+			}
+		}
+	}
+	return 0;
+}
+
+void
+_kc_pci_release_regions(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(dev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			release_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
+
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			release_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
+	}
+}
+
+/**************************************/
+/* NETWORK DRIVER API */
+
+struct net_device *
+_kc_alloc_etherdev(int sizeof_priv)
+{
+	struct net_device *dev;
+	int alloc_size;
+
+	alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 31;
+	dev = kzalloc(alloc_size, GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	if (sizeof_priv)
+		dev->priv = (void *) (((unsigned long)(dev + 1) + 31) & ~31);
+	dev->name[0] = '\0';
+	ether_setup(dev);
+
+	return dev;
+}
+
+int
+_kc_is_valid_ether_addr(u8 *addr)
+{
+	const char zaddr[6] = { 0, };
+
+	return !(addr[0] & 1) && memcmp(addr, zaddr, 6);
+}
+
+#endif /* 2.4.3 => 2.4.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6))
+
+int
+_kc_pci_set_power_state(struct pci_dev *dev, int state)
+{
+	return 0;
+}
+
+int
+_kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+{
+	return 0;
+}
+
+#endif /* 2.4.6 => 2.4.3 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page,
+							int off, int size)
+{
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+	frag->page = page;
+	frag->page_offset = off;
+	frag->size = size;
+	skb_shinfo(skb)->nr_frags = i + 1;
+}
+
+/*
+ * Original Copyright:
+ * find_next_bit.c: fallback find next bit implementation
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+							unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
+	if (offset) {
+		tmp = *(p++);
+		tmp &= (~0UL << offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1)) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp &= (~0UL >> (BITS_PER_LONG - size));
+	if (tmp == 0UL)		/* Are any bits set? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + ffs(tmp);
+}
+
+size_t _kc_strlcpy(char *dest, const char *src, size_t size)
+{
+	size_t ret = strlen(src);
+
+	if (size) {
+		size_t len = (ret >= size) ? size - 1 : ret;
+		memcpy(dest, src, len);
+		dest[len] = '\0';
+	}
+	return ret;
+}
+
+#ifndef do_div
+#if BITS_PER_LONG == 32
+uint32_t __attribute__((weak)) _kc__div64_32(uint64_t *n, uint32_t base)
+{
+	uint64_t rem = *n;
+	uint64_t b = base;
+	uint64_t res, d = 1;
+	uint32_t high = rem >> 32;
+
+	/* Reduce the thing a bit first */
+	res = 0;
+	if (high >= base) {
+		high /= base;
+		res = (uint64_t) high << 32;
+		rem -= (uint64_t) (high*base) << 32;
+	}
+
+	while ((int64_t)b > 0 && b < rem) {
+		b = b+b;
+		d = d+d;
+	}
+
+	do {
+		if (rem >= b) {
+			rem -= b;
+			res += d;
+		}
+		b >>= 1;
+		d >>= 1;
+	} while (d);
+
+	*n = res;
+	return rem;
+}
+#endif /* BITS_PER_LONG == 32 */
+#endif /* do_div */
+#endif /* 2.6.0 => 2.4.6 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 4))
+int _kc_scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vsnprintf(buf, size, fmt, args);
+	va_end(args);
+	return (i >= size) ? (size - 1) : i;
+}
+#endif /* < 2.6.4 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10))
+DECLARE_BITMAP(_kcompat_node_online_map, MAX_NUMNODES) = {1};
+#endif /* < 2.6.10 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13))
+char *_kc_kstrdup(const char *s, unsigned int gfp)
+{
+	size_t len;
+	char *buf;
+
+	if (!s)
+		return NULL;
+
+	len = strlen(s) + 1;
+	buf = kmalloc(len, gfp);
+	if (buf)
+		memcpy(buf, s, len);
+	return buf;
+}
+#endif /* < 2.6.13 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14))
+void *_kc_kzalloc(size_t size, int flags)
+{
+	void *ret = kmalloc(size, flags);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+#endif /* <= 2.6.13 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+int _kc_skb_pad(struct sk_buff *skb, int pad)
+{
+	int ntail;
+
+	/* If the skbuff is non linear tailroom is always zero.. */
+	if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
+		memset(skb->data+skb->len, 0, pad);
+		return 0;
+	}
+
+	ntail = skb->data_len + pad - (skb->end - skb->tail);
+	if (likely(skb_cloned(skb) || ntail > 0)) {
+		if (pskb_expand_head(skb, 0, ntail, GFP_ATOMIC))
+			goto free_skb;
+	}
+
+#ifdef MAX_SKB_FRAGS
+	if (skb_is_nonlinear(skb) &&
+	    !__pskb_pull_tail(skb, skb->data_len))
+		goto free_skb;
+
+#endif
+	memset(skb->data + skb->len, 0, pad);
+	return 0;
+
+free_skb:
+	kfree_skb(skb);
+	return -ENOMEM;
+}
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5, 4)))
+int _kc_pci_save_state(struct pci_dev *pdev)
+{
+	struct adapter_struct *adapter = pci_get_drvdata(pdev);
+	int size = PCI_CONFIG_SPACE_LEN, i;
+	u16 pcie_cap_offset, pcie_link_status;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+	/* no ->dev for 2.4 kernels */
+	WARN_ON(pdev->dev.driver_data == NULL);
+#endif
+	pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (pcie_cap_offset) {
+		if (!pci_read_config_word(pdev,
+									pcie_cap_offset + PCIE_LINK_STATUS,
+									&pcie_link_status))
+		size = PCIE_CONFIG_SPACE_LEN;
+	}
+	pci_config_space_ich8lan();
+#ifdef HAVE_PCI_ERS
+	if (adapter->config_space == NULL)
+#else
+	WARN_ON(adapter->config_space != NULL);
+#endif
+		adapter->config_space = kmalloc(size, GFP_KERNEL);
+	if (!adapter->config_space) {
+		printk(KERN_ERR "Out of memory in pci_save_state\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < (size / 4); i++)
+		pci_read_config_dword(pdev, i * 4, &adapter->config_space[i]);
+	return 0;
+}
+
+void _kc_pci_restore_state(struct pci_dev *pdev)
+{
+	struct adapter_struct *adapter = pci_get_drvdata(pdev);
+	int size = PCI_CONFIG_SPACE_LEN, i;
+	u16 pcie_cap_offset;
+	u16 pcie_link_status;
+
+	if (adapter->config_space != NULL) {
+		pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+		if (pcie_cap_offset &&
+		    !pci_read_config_word(pdev,
+									pcie_cap_offset + PCIE_LINK_STATUS,
+									&pcie_link_status))
+			size = PCIE_CONFIG_SPACE_LEN;
+
+		pci_config_space_ich8lan();
+		for (i = 0; i < (size / 4); i++)
+		pci_write_config_dword(pdev, i * 4, adapter->config_space[i]);
+#ifndef HAVE_PCI_ERS
+		kfree(adapter->config_space);
+		adapter->config_space = NULL;
+#endif
+	}
+}
+#endif /* !(RHEL_RELEASE_CODE >= RHEL 5.4) */
+
+#ifdef HAVE_PCI_ERS
+void _kc_free_netdev(struct net_device *netdev)
+{
+	struct adapter_struct *adapter = netdev_priv(netdev);
+
+	kfree(adapter->config_space);
+#ifdef CONFIG_SYSFS
+	if (netdev->reg_state == NETREG_UNINITIALIZED) {
+		kfree((char *)netdev - netdev->padded);
+	} else {
+		BUG_ON(netdev->reg_state != NETREG_UNREGISTERED);
+		netdev->reg_state = NETREG_RELEASED;
+		class_device_put(&netdev->class_dev);
+	}
+#else
+	kfree((char *)netdev - netdev->padded);
+#endif
+}
+#endif
+
+void *_kc_kmemdup(const void *src, size_t len, unsigned gfp)
+{
+	void *p;
+
+	p = kzalloc(len, gfp);
+	if (p)
+		memcpy(p, src, len);
+	return p;
+}
+#endif /* <= 2.6.19 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21))
+struct pci_dev *_kc_netdev_to_pdev(struct net_device *netdev)
+{
+	return ((struct adapter_struct *)netdev_priv(netdev))->pdev;
+}
+#endif /* < 2.6.21 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22))
+/* hexdump code taken from lib/hexdump.c */
+static void _kc_hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
+			int groupsize, unsigned char *linebuf,
+			size_t linebuflen, bool ascii)
+{
+	const u8 *ptr = buf;
+	u8 ch;
+	int j, lx = 0;
+	int ascii_column;
+
+	if (rowsize != 16 && rowsize != 32)
+		rowsize = 16;
+
+	if (!len)
+		goto nil;
+	if (len > rowsize)		/* limit to one line at a time */
+		len = rowsize;
+	if ((len % groupsize) != 0)	/* no mixed size output */
+		groupsize = 1;
+
+	switch (groupsize) {
+	case 8: {
+		const u64 *ptr8 = buf;
+		int ngroups = len / groupsize;
+
+		for (j = 0; j < ngroups; j++)
+			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
+				"%s%16.16llx", j ? " " : "",
+				(unsigned long long)*(ptr8 + j));
+		ascii_column = 17 * ngroups + 2;
+		break;
+	}
+
+	case 4: {
+		const u32 *ptr4 = buf;
+		int ngroups = len / groupsize;
+
+		for (j = 0; j < ngroups; j++)
+			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
+				"%s%8.8x", j ? " " : "", *(ptr4 + j));
+		ascii_column = 9 * ngroups + 2;
+		break;
+	}
+
+	case 2: {
+		const u16 *ptr2 = buf;
+		int ngroups = len / groupsize;
+
+		for (j = 0; j < ngroups; j++)
+			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
+				"%s%4.4x", j ? " " : "", *(ptr2 + j));
+		ascii_column = 5 * ngroups + 2;
+		break;
+	}
+
+	default:
+		for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
+			ch = ptr[j];
+			linebuf[lx++] = hex_asc(ch >> 4);
+			linebuf[lx++] = hex_asc(ch & 0x0f);
+			linebuf[lx++] = ' ';
+		}
+		if (j)
+			lx--;
+
+		ascii_column = 3 * rowsize + 2;
+		break;
+	}
+	if (!ascii)
+		goto nil;
+
+	while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
+		linebuf[lx++] = ' ';
+	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
+		linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
+				: '.';
+nil:
+	linebuf[lx++] = '\0';
+}
+
+void _kc_print_hex_dump(const char *level,
+			const char *prefix_str, int prefix_type,
+			int rowsize, int groupsize,
+			const void *buf, size_t len, bool ascii)
+{
+	const u8 *ptr = buf;
+	int i, linelen, remaining = len;
+	unsigned char linebuf[200];
+
+	if (rowsize != 16 && rowsize != 32)
+		rowsize = 16;
+
+	for (i = 0; i < len; i += rowsize) {
+		linelen = min(remaining, rowsize);
+		remaining -= rowsize;
+		_kc_hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
+				linebuf, sizeof(linebuf), ascii);
+
+		switch (prefix_type) {
+		case DUMP_PREFIX_ADDRESS:
+			printk("%s%s%*p: %s\n", level, prefix_str,
+				(int)(2 * sizeof(void *)), ptr + i, linebuf);
+			break;
+		case DUMP_PREFIX_OFFSET:
+			printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
+			break;
+		default:
+			printk("%s%s%s\n", level, prefix_str, linebuf);
+			break;
+		}
+	}
+}
+
+#endif /* < 2.6.22 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
+int txgbe_dcb_netlink_register(void)
+{
+	return 0;
+}
+
+int txgbe_dcb_netlink_unregister(void)
+{
+	return 0;
+}
+
+int txgbe_copy_dcb_cfg(struct txgbe_adapter __always_unused *adapter, int __always_unused tc_max)
+{
+	return 0;
+}
+#endif /* < 2.6.23 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
+#ifdef NAPI
+struct net_device *napi_to_poll_dev(const struct napi_struct *napi)
+{
+	struct adapter_q_vector *q_vector = container_of(napi,
+														struct adapter_q_vector,
+														napi);
+	return &q_vector->poll_dev;
+}
+
+int __kc_adapter_clean(struct net_device *netdev, int *budget)
+{
+	int work_done;
+	int work_to_do = min(*budget, netdev->quota);
+	/* kcompat.h netif_napi_add puts napi struct in "fake netdev->priv" */
+	struct napi_struct *napi = netdev->priv;
+	work_done = napi->poll(napi, work_to_do);
+	*budget -= work_done;
+	netdev->quota -= work_done;
+	return (work_done >= work_to_do) ? 1 : 0;
+}
+#endif /* NAPI */
+#endif /* <= 2.6.24 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+void _kc_pci_disable_link_state(struct pci_dev *pdev, int state)
+{
+	struct pci_dev *parent = pdev->bus->self;
+	u16 link_state;
+	int pos;
+
+	if (!parent)
+		return;
+
+	pos = pci_find_capability(parent, PCI_CAP_ID_EXP);
+	if (pos) {
+		pci_read_config_word(parent, pos + PCI_EXP_LNKCTL, &link_state);
+		link_state &= ~state;
+		pci_write_config_word(parent, pos + PCI_EXP_LNKCTL, link_state);
+	}
+}
+#endif /* < 2.6.26 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27))
+#ifdef HAVE_TX_MQ
+void _kc_netif_tx_stop_all_queues(struct net_device *netdev)
+{
+	struct adapter_struct *adapter = netdev_priv(netdev);
+	int i;
+
+	netif_stop_queue(netdev);
+	if (netif_is_multiqueue(netdev))
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			netif_stop_subqueue(netdev, i);
+}
+void _kc_netif_tx_wake_all_queues(struct net_device *netdev)
+{
+	struct adapter_struct *adapter = netdev_priv(netdev);
+	int i;
+
+	netif_wake_queue(netdev);
+	if (netif_is_multiqueue(netdev))
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			netif_wake_subqueue(netdev, i);
+}
+void _kc_netif_tx_start_all_queues(struct net_device *netdev)
+{
+	struct adapter_struct *adapter = netdev_priv(netdev);
+	int i;
+
+	netif_start_queue(netdev);
+	if (netif_is_multiqueue(netdev))
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			netif_start_subqueue(netdev, i);
+}
+#endif /* HAVE_TX_MQ */
+
+void __kc_warn_slowpath(const char *file, int line, const char *fmt, ...)
+{
+	va_list args;
+
+	printk(KERN_WARNING "------------[ cut here ]------------\n");
+	printk(KERN_WARNING "WARNING: at %s:%d \n", file, line);
+	va_start(args, fmt);
+	vprintk(fmt, args);
+	va_end(args);
+
+	dump_stack();
+}
+#endif /* __VMKLNX__ */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
+
+int
+_kc_pci_prepare_to_sleep(struct pci_dev *dev)
+{
+	pci_power_t target_state;
+	int error;
+
+	target_state = pci_choose_state(dev, PMSG_SUSPEND);
+
+	pci_enable_wake(dev, target_state, true);
+
+	error = pci_set_power_state(dev, target_state);
+
+	if (error)
+		pci_enable_wake(dev, target_state, false);
+
+	return error;
+}
+
+int
+_kc_pci_wake_from_d3(struct pci_dev *dev, bool enable)
+{
+	int err;
+
+	err = pci_enable_wake(dev, PCI_D3cold, enable);
+	if (err)
+		goto out;
+
+	err = pci_enable_wake(dev, PCI_D3hot, enable);
+
+out:
+	return err;
+}
+#endif /* < 2.6.28 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29))
+static void __kc_pci_set_master(struct pci_dev *pdev, bool enable)
+{
+	u16 old_cmd, cmd;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &old_cmd);
+	if (enable)
+		cmd = old_cmd | PCI_COMMAND_MASTER;
+	else
+		cmd = old_cmd & ~PCI_COMMAND_MASTER;
+	if (cmd != old_cmd) {
+		dev_dbg(pci_dev_to_dev(pdev), "%s bus mastering\n",
+			enable ? "enabling" : "disabling");
+		pci_write_config_word(pdev, PCI_COMMAND, cmd);
+	}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7))
+	pdev->is_busmaster = enable;
+#endif
+}
+
+void _kc_pci_clear_master(struct pci_dev *dev)
+{
+	__kc_pci_set_master(dev, false);
+}
+#endif /* < 2.6.29 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34))
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6, 0))
+int _kc_pci_num_vf(struct pci_dev __maybe_unused *dev)
+{
+	int num_vf = 0;
+#ifdef CONFIG_PCI_IOV
+	struct pci_dev *vfdev;
+
+	/* loop through all ethernet devices starting at PF dev */
+	vfdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, NULL);
+	while (vfdev) {
+		if (vfdev->is_virtfn && vfdev->physfn == dev)
+			num_vf++;
+
+		vfdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, vfdev);
+	}
+
+#endif
+	return num_vf;
+}
+#endif /* RHEL_RELEASE_CODE */
+#endif /* < 2.6.34 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35))
+#ifdef HAVE_TX_MQ
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 0)))
+#ifndef CONFIG_NETDEVICES_MULTIQUEUE
+int _kc_netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+	unsigned int real_num = dev->real_num_tx_queues;
+	struct Qdisc *qdisc;
+	int i;
+
+	if (txq < 1 || txq > dev->num_tx_queues)
+		return -EINVAL;
+
+	else if (txq > real_num)
+		dev->real_num_tx_queues = txq;
+	else if (txq < real_num) {
+		dev->real_num_tx_queues = txq;
+		for (i = txq; i < dev->num_tx_queues; i++) {
+			qdisc = netdev_get_tx_queue(dev, i)->qdisc;
+			if (qdisc) {
+				spin_lock_bh(qdisc_lock(qdisc));
+				qdisc_reset(qdisc);
+				spin_unlock_bh(qdisc_lock(qdisc));
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_NETDEVICES_MULTIQUEUE */
+#endif /* !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)) */
+#endif /* HAVE_TX_MQ */
+
+ssize_t _kc_simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
+				   const void __user *from, size_t count)
+{
+		loff_t pos = *ppos;
+		size_t res;
+
+		if (pos < 0)
+			return -EINVAL;
+		if (pos >= available || !count)
+			return 0;
+		if (count > available - pos)
+			count = available - pos;
+		res = copy_from_user(to + pos, from, count);
+		if (res == count)
+			return -EFAULT;
+		count -= res;
+		*ppos = pos + count;
+		return count;
+}
+
+#endif /* < 2.6.35 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36))
+static const u32 _kc_flags_dup_features =
+	(ETH_FLAG_LRO | ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH);
+
+u32 _kc_ethtool_op_get_flags(struct net_device *dev)
+{
+	return dev->features & _kc_flags_dup_features;
+}
+
+int _kc_ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
+{
+	if (data & ~supported)
+		return -EINVAL;
+
+	dev->features = ((dev->features & ~_kc_flags_dup_features) |
+			 (data & _kc_flags_dup_features));
+	return 0;
+}
+#endif /* < 2.6.36 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6, 0)))
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#include <net/ip.h>
+#include <linux/pkt_sched.h>
+
+u16 ___kc_skb_tx_hash(struct net_device *dev, const struct sk_buff *skb,
+		      u16 num_tx_queues)
+{
+	u32 hash;
+	u16 qoffset = 0;
+	u16 qcount = num_tx_queues;
+
+	if (skb_rx_queue_recorded(skb)) {
+		hash = skb_get_rx_queue(skb);
+		while (unlikely(hash >= num_tx_queues))
+			hash -= num_tx_queues;
+		return hash;
+	}
+
+	if (netdev_get_num_tc(dev)) {
+		struct adapter_struct *kc_adapter = netdev_priv(dev);
+
+		if (skb->priority == TC_PRIO_CONTROL) {
+			qoffset = kc_adapter->dcb_tc - 1;
+		} else {
+			qoffset = skb->vlan_tci;
+			qoffset &= TXGBE_TX_FLAGS_VLAN_PRIO_MASK;
+			qoffset >>= 13;
+		}
+
+		qcount = kc_adapter->ring_feature[RING_F_RSS].indices;
+		qoffset *= qcount;
+	}
+
+	if (skb->sk && skb->sk->sk_hash)
+		hash = skb->sk->sk_hash;
+	else
+#ifdef NETIF_F_RXHASH
+		hash = (__force u16) skb->protocol ^ skb->rxhash;
+#else
+		hash = skb->protocol;
+#endif
+
+	hash = jhash_1word(hash, _kc_hashrnd);
+
+	return (u16) (((u64) hash * qcount) >> 32) + qoffset;
+}
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+
+u8 _kc_netdev_get_num_tc(struct net_device *dev)
+{
+	struct adapter_struct *kc_adapter = netdev_priv(dev);
+	if (kc_adapter->flags & TXGBE_FLAG_DCB_ENABLED)
+		return kc_adapter->dcb_tc;
+	else
+		return 0;
+}
+
+int _kc_netdev_set_num_tc(struct net_device *dev, u8 num_tc)
+{
+	struct adapter_struct *kc_adapter = netdev_priv(dev);
+
+	if (num_tc > TXGBE_DCB_MAX_TRAFFIC_CLASS)
+		return -EINVAL;
+
+	kc_adapter->dcb_tc = num_tc;
+
+	return 0;
+}
+
+u8 _kc_netdev_get_prio_tc_map(struct net_device __maybe_unused *dev, u8 __maybe_unused up)
+{
+	struct adapter_struct *kc_adapter = netdev_priv(dev);
+
+	return txgbe_dcb_get_tc_from_up(&kc_adapter->dcb_cfg, 0, up);
+}
+
+#endif /* !(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,0)) */
+#endif /* < 2.6.39 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
+void _kc_skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
+			 int off, int size, unsigned int truesize)
+{
+	skb_fill_page_desc(skb, i, page, off, size);
+	skb->len += size;
+	skb->data_len += size;
+	skb->truesize += truesize;
+}
+
+#if !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11, 3, 0))
+int _kc_simple_open(struct inode *inode, struct file *file)
+{
+		if (inode->i_private)
+			file->private_data = inode->i_private;
+
+		return 0;
+}
+#endif /* SLE_VERSION < 11,3,0 */
+
+#endif /* < 3.4.0 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
+static inline int __kc_pcie_cap_version(struct pci_dev *dev)
+{
+	int pos;
+	u16 reg16;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (!pos)
+		return 0;
+	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+	return reg16 & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool __kc_pcie_cap_has_devctl(const struct pci_dev __always_unused *dev)
+{
+	return true;
+}
+
+static inline bool __kc_pcie_cap_has_lnkctl(struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+
+	return __kc_pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       type == PCI_EXP_TYPE_ENDPOINT ||
+	       type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool __kc_pcie_cap_has_sltctl(struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+	int pos;
+	u16 pcie_flags_reg;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (!pos)
+		return false;
+	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &pcie_flags_reg);
+
+	return __kc_pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       (type == PCI_EXP_TYPE_DOWNSTREAM &&
+		pcie_flags_reg & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool __kc_pcie_cap_has_rtctl(struct pci_dev *dev)
+{
+	int type = pci_pcie_type(dev);
+
+	return __kc_pcie_cap_version(dev) > 1 ||
+	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	       type == PCI_EXP_TYPE_RC_EC;
+}
+
+static bool __kc_pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+	if (!pci_is_pcie(dev))
+		return false;
+
+	switch (pos) {
+	case PCI_EXP_FLAGS_TYPE:
+		return true;
+	case PCI_EXP_DEVCAP:
+	case PCI_EXP_DEVCTL:
+	case PCI_EXP_DEVSTA:
+		return __kc_pcie_cap_has_devctl(dev);
+	case PCI_EXP_LNKCAP:
+	case PCI_EXP_LNKCTL:
+	case PCI_EXP_LNKSTA:
+		return __kc_pcie_cap_has_lnkctl(dev);
+	case PCI_EXP_SLTCAP:
+	case PCI_EXP_SLTCTL:
+	case PCI_EXP_SLTSTA:
+		return __kc_pcie_cap_has_sltctl(dev);
+	case PCI_EXP_RTCTL:
+	case PCI_EXP_RTCAP:
+	case PCI_EXP_RTSTA:
+		return __kc_pcie_cap_has_rtctl(dev);
+	case PCI_EXP_DEVCAP2:
+	case PCI_EXP_DEVCTL2:
+	case PCI_EXP_LNKCAP2:
+	case PCI_EXP_LNKCTL2:
+	case PCI_EXP_LNKSTA2:
+		return __kc_pcie_cap_version(dev) > 1;
+	default:
+		return false;
+	}
+}
+
+/*
+ * Note that these accessor functions are only for the "PCI Express
+ * Capability" (see PCIe spec r3.0, sec 7.8).  They do not apply to the
+ * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
+ */
+int __kc_pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
+{
+	int ret;
+
+	*val = 0;
+	if (pos & 1)
+		return -EINVAL;
+
+	if (__kc_pcie_capability_reg_implemented(dev, pos)) {
+		ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
+		/*
+		 * Reset *val to 0 if pci_read_config_word() fails, it may
+		 * have been written as 0xFFFF if hardware error happens
+		 * during pci_read_config_word().
+		 */
+		if (ret)
+			*val = 0;
+		return ret;
+	}
+
+	/*
+	 * For Functions that do not implement the Slot Capabilities,
+	 * Slot Status, and Slot Control registers, these spaces must
+	 * be hardwired to 0b, with the exception of the Presence Detect
+	 * State bit in the Slot Status register of Downstream Ports,
+	 * which must be hardwired to 1b.  (PCIe Base Spec 3.0, sec 7.8)
+	 */
+	if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
+	    pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+		*val = PCI_EXP_SLTSTA_PDS;
+	}
+
+	return 0;
+}
+
+int __kc_pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
+{
+	int ret;
+
+	*val = 0;
+	if (pos & 3)
+		return -EINVAL;
+
+	if (__kc_pcie_capability_reg_implemented(dev, pos)) {
+		ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+		/*
+		 * Reset *val to 0 if pci_read_config_dword() fails, it may
+		 * have been written as 0xFFFFFFFF if hardware error happens
+		 * during pci_read_config_dword().
+		 */
+		if (ret)
+			*val = 0;
+		return ret;
+	}
+
+	if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
+	    pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+		*val = PCI_EXP_SLTSTA_PDS;
+	}
+
+	return 0;
+}
+
+
+int __kc_pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
+{
+	if (pos & 1)
+		return -EINVAL;
+
+	if (!__kc_pcie_capability_reg_implemented(dev, pos))
+		return 0;
+
+	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
+}
+
+int __kc_pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+					    u16 clear, u16 set)
+{
+	int ret;
+	u16 val;
+
+	ret = __kc_pcie_capability_read_word(dev, pos, &val);
+	if (!ret) {
+		val &= ~clear;
+		val |= set;
+		ret = __kc_pcie_capability_write_word(dev, pos, val);
+	}
+
+	return ret;
+}
+
+int __kc_pcie_capability_clear_word(struct pci_dev *dev, int pos,
+					     u16 clear)
+{
+	return __kc_pcie_capability_clear_and_set_word(dev, pos, clear, 0);
+}
+#endif /* < 3.7.0 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+#ifdef CONFIG_XPS
+#if NR_CPUS < 64
+#define _KC_MAX_XPS_CPUS	NR_CPUS
+#else
+#define _KC_MAX_XPS_CPUS	64
+#endif
+
+/*
+ * netdev_queue sysfs structures and functions.
+ */
+struct _kc_netdev_queue_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct netdev_queue *queue,
+	    struct _kc_netdev_queue_attribute *attr, char *buf);
+	ssize_t (*store)(struct netdev_queue *queue,
+	    struct _kc_netdev_queue_attribute *attr, const char *buf, size_t len);
+};
+
+#define to_kc_netdev_queue_attr(_attr) container_of(_attr,		\
+    struct _kc_netdev_queue_attribute, attr)
+
+int __kc_netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
+			     u16 index)
+{
+	struct netdev_queue *txq = netdev_get_tx_queue(dev, index);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38))
+	/* Redhat requires some odd extended netdev structures */
+	struct netdev_tx_queue_extended *txq_ext =
+					netdev_extended(dev)->_tx_ext + index;
+	struct kobj_type *ktype = txq_ext->kobj.ktype;
+#else
+	struct kobj_type *ktype = txq->kobj.ktype;
+#endif
+	struct _kc_netdev_queue_attribute *xps_attr;
+	struct attribute *attr = NULL;
+	int i, len, err;
+#define _KC_XPS_BUFLEN	(DIV_ROUND_UP(_KC_MAX_XPS_CPUS, 32) * 9)
+	char buf[_KC_XPS_BUFLEN];
+
+	if (!ktype)
+		return -ENOMEM;
+
+	/* attempt to locate the XPS attribute in the Tx queue */
+	for (i = 0; (attr = ktype->default_attrs[i]); i++) {
+		if (!strcmp("xps_cpus", attr->name))
+			break;
+	}
+
+	/* if we did not find it return an error */
+	if (!attr)
+		return -EINVAL;
+
+	/* copy the mask into a string */
+	len = bitmap_scnprintf(buf, _KC_XPS_BUFLEN,
+			       cpumask_bits(mask), _KC_MAX_XPS_CPUS);
+	if (!len)
+		return -ENOMEM;
+
+	xps_attr = to_kc_netdev_queue_attr(attr);
+
+	/* Store the XPS value using the SYSFS store call */
+	err = xps_attr->store(txq, xps_attr, buf, len);
+
+	/* we only had an error on err < 0 */
+	return (err < 0) ? err : 0;
+}
+#endif /* CONFIG_XPS */
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+static inline int kc_get_xps_queue(struct net_device *dev, struct sk_buff *skb)
+{
+#ifdef CONFIG_XPS
+	struct xps_dev_maps *dev_maps;
+	struct xps_map *map;
+	int queue_index = -1;
+
+	rcu_read_lock();
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38))
+	/* Redhat requires some odd extended netdev structures */
+	dev_maps = rcu_dereference(netdev_extended(dev)->xps_maps);
+#else
+	dev_maps = rcu_dereference(dev->xps_maps);
+#endif
+	if (dev_maps) {
+		map = rcu_dereference(
+		    dev_maps->cpu_map[raw_smp_processor_id()]);
+		if (map) {
+			if (map->len == 1)
+				queue_index = map->queues[0];
+			else {
+				u32 hash;
+				if (skb->sk && skb->sk->sk_hash)
+					hash = skb->sk->sk_hash;
+				else
+					hash = (__force u16) skb->protocol ^
+					    skb->rxhash;
+				hash = jhash_1word(hash, _kc_hashrnd);
+				queue_index = map->queues[
+				    ((u64)hash * map->len) >> 32];
+			}
+			if (unlikely(queue_index >= dev->real_num_tx_queues))
+				queue_index = -1;
+		}
+	}
+	rcu_read_unlock();
+
+	return queue_index;
+#else
+	struct adapter_struct *kc_adapter = netdev_priv(dev);
+	int queue_index = -1;
+
+	if (kc_adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE) {
+		queue_index = skb_rx_queue_recorded(skb) ?
+					   skb_get_rx_queue(skb) :
+					   smp_processor_id();
+		while (unlikely(queue_index >= dev->real_num_tx_queues))
+			queue_index -= dev->real_num_tx_queues;
+		return queue_index;
+	}
+
+	return -1;
+#endif
+}
+
+u16 __kc_netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct sock *sk = skb->sk;
+	int queue_index = sk_tx_queue_get(sk);
+	int new_index;
+
+	if (queue_index >= 0 && queue_index < dev->real_num_tx_queues) {
+#ifdef CONFIG_XPS
+		if (!skb->ooo_okay)
+#endif
+			return queue_index;
+	}
+
+	new_index = kc_get_xps_queue(dev, skb);
+	if (new_index < 0)
+		new_index = skb_tx_hash(dev, skb);
+
+	if (queue_index != new_index && sk) {
+		struct dst_entry *dst =
+			    rcu_dereference(sk->sk_dst_cache);
+
+		if (dst && skb_dst(skb) == dst)
+			sk_tx_queue_set(sk, new_index);
+
+	}
+
+	return new_index;
+}
+
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+#endif /* 3.9.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+#ifdef HAVE_FDB_OPS
+#ifdef USE_CONST_DEV_UC_CHAR
+int __kc_ndo_dflt_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			  struct net_device *dev, const unsigned char *addr,
+			  u16 flags)
+#else
+int __kc_ndo_dflt_fdb_add(struct ndmsg *ndm, struct net_device *dev,
+			  unsigned char *addr, u16 flags)
+#endif
+{
+	int err = -EINVAL;
+
+	/* If aging addresses are supported device will need to
+	 * implement its own handler for this.
+	 */
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		pr_info("%s: FDB only supports static addresses\n", dev->name);
+		return err;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_add_excl(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_add_excl(dev, addr);
+
+	/* Only return duplicate errors if NLM_F_EXCL is set */
+	if (err == -EEXIST && !(flags & NLM_F_EXCL))
+		err = 0;
+
+	return err;
+}
+
+#ifdef USE_CONST_DEV_UC_CHAR
+#ifdef HAVE_FDB_DEL_NLATTR
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+			  struct net_device *dev, const unsigned char *addr)
+#else
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct net_device *dev,
+			  const unsigned char *addr)
+#endif
+#else
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct net_device *dev,
+			  unsigned char *addr)
+#endif
+{
+	int err = -EINVAL;
+
+	/* If aging addresses are supported device will need to
+	 * implement its own handler for this.
+	 */
+	if (!(ndm->ndm_state & NUD_PERMANENT)) {
+		pr_info("%s: FDB only supports static addresses\n", dev->name);
+		return err;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_del(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_del(dev, addr);
+
+	return err;
+}
+
+#endif /* HAVE_FDB_OPS */
+#ifdef CONFIG_PCI_IOV
+int __kc_pci_vfs_assigned(struct pci_dev __maybe_unused *dev)
+{
+	unsigned int vfs_assigned = 0;
+#ifdef HAVE_PCI_DEV_FLAGS_ASSIGNED
+	int pos;
+	struct pci_dev *vfdev;
+	unsigned short dev_id;
+
+	/* only search if we are a PF */
+	if (!dev->is_physfn)
+		return 0;
+
+	/* find SR-IOV capability */
+	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos)
+		return 0;
+
+	/*
+	 * determine the device ID for the VFs, the vendor ID will be the
+	 * same as the PF so there is no need to check for that one
+	 */
+	pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &dev_id);
+
+	/* loop through all the VFs to see if we own any that are assigned */
+	vfdev = pci_get_device(dev->vendor, dev_id, NULL);
+	while (vfdev) {
+		/*
+		 * It is considered assigned if it is a virtual function with
+		 * our dev as the physical function and the assigned bit is set
+		 */
+		if (vfdev->is_virtfn && (vfdev->physfn == dev) &&
+		    (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED))
+			vfs_assigned++;
+
+		vfdev = pci_get_device(dev->vendor, dev_id, vfdev);
+	}
+
+#endif /* HAVE_PCI_DEV_FLAGS_ASSIGNED */
+	return vfs_assigned;
+}
+
+#endif /* CONFIG_PCI_IOV */
+#endif /* 3.10.0 */
+
+static const unsigned char __maybe_unused pcie_link_speed[] = {
+	PCI_SPEED_UNKNOWN,      /* 0 */
+	PCIE_SPEED_2_5GT,       /* 1 */
+	PCIE_SPEED_5_0GT,       /* 2 */
+	PCIE_SPEED_8_0GT,       /* 3 */
+	PCIE_SPEED_16_0GT,      /* 4 */
+	PCI_SPEED_UNKNOWN,      /* 5 */
+	PCI_SPEED_UNKNOWN,      /* 6 */
+	PCI_SPEED_UNKNOWN,      /* 7 */
+	PCI_SPEED_UNKNOWN,      /* 8 */
+	PCI_SPEED_UNKNOWN,      /* 9 */
+	PCI_SPEED_UNKNOWN,      /* A */
+	PCI_SPEED_UNKNOWN,      /* B */
+	PCI_SPEED_UNKNOWN,      /* C */
+	PCI_SPEED_UNKNOWN,      /* D */
+	PCI_SPEED_UNKNOWN,      /* E */
+	PCI_SPEED_UNKNOWN       /* F */
+};
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0))
+int __kc_pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
+			       enum pcie_link_width *width)
+{
+	int ret;
+
+	*speed = PCI_SPEED_UNKNOWN;
+	*width = PCIE_LNK_WIDTH_UNKNOWN;
+
+	while (dev) {
+		u16 lnksta;
+		enum pci_bus_speed next_speed;
+		enum pcie_link_width next_width;
+
+		ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+		if (ret)
+			return ret;
+
+		next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
+		next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
+			PCI_EXP_LNKSTA_NLW_SHIFT;
+
+		if (next_speed < *speed)
+			*speed = next_speed;
+
+		if (next_width < *width)
+			*width = next_width;
+
+		dev = dev->bus->self;
+	}
+
+	return 0;
+}
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,7))
+int _kc_pci_wait_for_pending_transaction(struct pci_dev *dev)
+{
+	int i;
+	u16 status;
+
+	/* Wait for Transaction Pending bit clean */
+	for (i = 0; i < 4; i++) {
+		if (i)
+			msleep((1 << (i - 1)) * 100);
+
+		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
+		if (!(status & PCI_EXP_DEVSTA_TRPND))
+			return 1;
+	}
+
+	return 0;
+}
+#endif /* <RHEL6.7 */
+
+#endif /* <3.12 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+int __kc_dma_set_mask_and_coherent(struct device *dev, u64 mask)
+{
+	int err = dma_set_mask(dev, mask);
+
+	if (!err)
+		/* coherent mask for the same size will always succeed if
+		 * dma_set_mask does. However we store the error anyways, due
+		 * to some kernels which use gcc's warn_unused_result on their
+		 * definition of dma_set_coherent_mask.
+		 */
+		err = dma_set_coherent_mask(dev, mask);
+	return err;
+}
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0))
+static bool _kc_pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn,
+					   u32 *l, int crs_timeout)
+{
+	int delay = 1;
+
+	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+		return false;
+
+	/* some broken boards return 0 or ~0 if a slot is empty: */
+	if (*l == 0xffffffff || *l == 0x00000000 ||
+	    *l == 0x0000ffff || *l == 0xffff0000)
+		return false;
+
+	/* Configuration request Retry Status */
+	while (*l == 0xffff0001) {
+		if (!crs_timeout)
+			return false;
+
+		msleep(delay);
+		delay *= 2;
+		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+			return false;
+		/* Card hasn't responded in 60 seconds?  Must be stuck. */
+		if (delay > crs_timeout) {
+			printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not "
+			       "responding\n", pci_domain_nr(bus),
+			       bus->number, PCI_SLOT(devfn),
+			       PCI_FUNC(devfn));
+			return false;
+		}
+	}
+
+	return true;
+}
+
+bool _kc_pci_device_is_present(struct pci_dev *pdev)
+{
+	u32 v;
+
+	return _kc_pci_bus_read_dev_vendor_id(pdev->bus, pdev->devfn, &v, 0);
+}
+#endif /* <RHEL7.0 */
+#endif /* 3.13.0 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+/******************************************************************************
+ * ripped from linux/net/ipv6/exthdrs_core.c, GPL2, no direct copyright,
+ * inferred copyright from kernel
+ */
+int __kc_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
+		       int target, unsigned short *fragoff, int *flags)
+{
+	unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
+	u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+	unsigned int len;
+	bool found;
+
+#define __KC_IP6_FH_F_FRAG	BIT(0)
+#define __KC_IP6_FH_F_AUTH	BIT(1)
+#define __KC_IP6_FH_F_SKIP_RH	BIT(2)
+
+	if (fragoff)
+		*fragoff = 0;
+
+	if (*offset) {
+		struct ipv6hdr _ip6, *ip6;
+
+		ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);
+		if (!ip6 || (ip6->version != 6)) {
+			printk(KERN_ERR "IPv6 header not found\n");
+			return -EBADMSG;
+		}
+		start = *offset + sizeof(struct ipv6hdr);
+		nexthdr = ip6->nexthdr;
+	}
+	len = skb->len - start;
+
+	do {
+		struct ipv6_opt_hdr _hdr, *hp;
+		unsigned int hdrlen;
+		found = (nexthdr == target);
+
+		if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
+			if (target < 0 || found)
+				break;
+			return -ENOENT;
+		}
+
+		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
+		if (!hp)
+			return -EBADMSG;
+
+		if (nexthdr == NEXTHDR_ROUTING) {
+			struct ipv6_rt_hdr _rh, *rh;
+
+			rh = skb_header_pointer(skb, start, sizeof(_rh),
+						&_rh);
+			if (!rh)
+				return -EBADMSG;
+
+			if (flags && (*flags & __KC_IP6_FH_F_SKIP_RH) &&
+			    rh->segments_left == 0)
+				found = false;
+		}
+
+		if (nexthdr == NEXTHDR_FRAGMENT) {
+			unsigned short _frag_off;
+			__be16 *fp;
+
+			if (flags)	/* Indicate that this is a fragment */
+				*flags |= __KC_IP6_FH_F_FRAG;
+			fp = skb_header_pointer(skb,
+						start+offsetof(struct frag_hdr,
+							       frag_off),
+						sizeof(_frag_off),
+						&_frag_off);
+			if (!fp)
+				return -EBADMSG;
+
+			_frag_off = ntohs(*fp) & ~0x7;
+			if (_frag_off) {
+				if (target < 0 &&
+				    ((!ipv6_ext_hdr(hp->nexthdr)) ||
+				     hp->nexthdr == NEXTHDR_NONE)) {
+					if (fragoff)
+						*fragoff = _frag_off;
+					return hp->nexthdr;
+				}
+				return -ENOENT;
+			}
+			hdrlen = 8;
+		} else if (nexthdr == NEXTHDR_AUTH) {
+			if (flags && (*flags & __KC_IP6_FH_F_AUTH) && (target < 0))
+				break;
+			hdrlen = (hp->hdrlen + 2) << 2;
+		} else
+			hdrlen = ipv6_optlen(hp);
+
+		if (!found) {
+			nexthdr = hp->nexthdr;
+			len -= hdrlen;
+			start += hdrlen;
+		}
+	} while (!found);
+
+	*offset = start;
+	return nexthdr;
+}
+
+int __kc_pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
+			       int minvec, int maxvec)
+{
+		int nvec = maxvec;
+		int rc;
+
+		if (maxvec < minvec)
+			return -ERANGE;
+
+		do {
+			rc = pci_enable_msix(dev, entries, nvec);
+			if (rc < 0) {
+				return rc;
+			} else if (rc > 0) {
+				if (rc < minvec)
+					return -ENOSPC;
+				nvec = rc;
+			}
+		} while (rc);
+
+		return nvec;
+}
+#endif /* 3.14.0 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0))
+char *_kc_devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
+{
+	size_t size;
+	char *buf;
+
+	if (!s)
+		return NULL;
+
+	size = strlen(s) + 1;
+	buf = devm_kzalloc(dev, size, gfp);
+	if (buf)
+		memcpy(buf, s, size);
+	return buf;
+}
+
+void __kc_netdev_rss_key_fill(void *buffer, size_t len)
+{
+	/* Set of random keys generated using kernel random number generator */
+	static const u8 seed[NETDEV_RSS_KEY_LEN] = {0xE6, 0xFA, 0x35, 0x62,
+				0x95, 0x12, 0x3E, 0xA3, 0xFB, 0x46, 0xC1, 0x5F,
+				0xB1, 0x43, 0x82, 0x5B, 0x6A, 0x49, 0x50, 0x95,
+				0xCD, 0xAB, 0xD8, 0x11, 0x8F, 0xC5, 0xBD, 0xBC,
+				0x6A, 0x4A, 0xB2, 0xD4, 0x1F, 0xFE, 0xBC, 0x41,
+				0xBF, 0xAC, 0xB2, 0x9A, 0x8F, 0x70, 0xE9, 0x2A,
+				0xD7, 0xB2, 0x80, 0xB6, 0x5B, 0xAA, 0x9D, 0x20};
+
+	BUG_ON(len > NETDEV_RSS_KEY_LEN);
+	memcpy(buffer, seed, len);
+}
+#endif /* 3.15.0 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0))
+#ifdef HAVE_SET_RX_MODE
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+int __kc_hw_addr_sync_dev(struct netdev_hw_addr_list *list,
+		struct net_device *dev,
+		int (*sync)(struct net_device *, const unsigned char *),
+		int (*unsync)(struct net_device *, const unsigned char *))
+{
+	struct netdev_hw_addr *ha, *tmp;
+	int err;
+
+	/* first go through and flush out any stale entries */
+	list_for_each_entry_safe(ha, tmp, &list->list, list) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+		if (!ha->synced || ha->refcount != 1)
+#else
+		if (!ha->sync_cnt || ha->refcount != 1)
+#endif
+			continue;
+
+		if (unsync && unsync(dev, ha->addr))
+			continue;
+
+		list_del_rcu(&ha->list);
+		kfree_rcu(ha, rcu_head);
+		list->count--;
+	}
+
+	/* go through and sync new entries to the list */
+	list_for_each_entry_safe(ha, tmp, &list->list, list) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+		if (ha->synced)
+#else
+		if (ha->sync_cnt)
+#endif
+			continue;
+
+		err = sync(dev, ha->addr);
+		if (err)
+			return err;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+		ha->synced = true;
+#else
+		ha->sync_cnt++;
+#endif
+		ha->refcount++;
+	}
+
+	return 0;
+}
+
+void __kc_hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
+		struct net_device *dev,
+		int (*unsync)(struct net_device *, const unsigned char *))
+{
+	struct netdev_hw_addr *ha, *tmp;
+
+	list_for_each_entry_safe(ha, tmp, &list->list, list) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+		if (!ha->synced)
+#else
+		if (!ha->sync_cnt)
+#endif
+			continue;
+
+		if (unsync && unsync(dev, ha->addr))
+			continue;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+		ha->synced = false;
+#else
+		ha->sync_cnt--;
+#endif
+		if (--ha->refcount)
+			continue;
+
+		list_del_rcu(&ha->list);
+		kfree_rcu(ha, rcu_head);
+		list->count--;
+	}
+}
+
+#endif /* NETDEV_HW_ADDR_T_UNICAST  */
+#ifndef NETDEV_HW_ADDR_T_MULTICAST
+int __kc_dev_addr_sync_dev(struct dev_addr_list **list, int *count,
+		struct net_device *dev,
+		int (*sync)(struct net_device *, const unsigned char *),
+		int (*unsync)(struct net_device *, const unsigned char *))
+{
+	struct dev_addr_list *da, **next = list;
+	int err;
+
+	/* first go through and flush out any stale entries */
+	while ((da = *next) != NULL) {
+		if (da->da_synced && da->da_users == 1) {
+			if (!unsync || !unsync(dev, da->da_addr)) {
+				*next = da->next;
+				kfree(da);
+				(*count)--;
+				continue;
+			}
+		}
+		next = &da->next;
+	}
+
+	/* go through and sync new entries to the list */
+	for (da = *list; da != NULL; da = da->next) {
+		if (da->da_synced)
+			continue;
+
+		err = sync(dev, da->da_addr);
+		if (err)
+			return err;
+
+		da->da_synced++;
+		da->da_users++;
+	}
+
+	return 0;
+}
+
+void __kc_dev_addr_unsync_dev(struct dev_addr_list **list, int *count,
+		struct net_device *dev,
+		int (*unsync)(struct net_device *, const unsigned char *))
+{
+	struct dev_addr_list *da;
+
+	while ((da = *list) != NULL) {
+		if (da->da_synced) {
+			if (!unsync || !unsync(dev, da->da_addr)) {
+				da->da_synced--;
+				if (--da->da_users == 0) {
+					*list = da->next;
+					kfree(da);
+					(*count)--;
+					continue;
+				}
+			}
+		}
+		list = &da->next;
+	}
+}
+#endif /* NETDEV_HW_ADDR_T_MULTICAST  */
+#endif /* HAVE_SET_RX_MODE */
+void *__kc_devm_kmemdup(struct device *dev, const void *src, size_t len,
+			gfp_t gfp)
+{
+	void *p;
+
+	p = devm_kzalloc(dev, len, gfp);
+	if (p)
+		memcpy(p, src, len);
+
+	return p;
+}
+#endif /* 3.16.0 */
+
+/******************************************************************************/
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5)))
+#endif /* <3.17.0 && RHEL_RELEASE_CODE < RHEL7.5 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0))
+#ifndef NO_PTP_SUPPORT
+static void __kc_sock_efree(struct sk_buff *skb)
+{
+	sock_put(skb->sk);
+}
+
+struct sk_buff *__kc_skb_clone_sk(struct sk_buff *skb)
+{
+	struct sock *sk = skb->sk;
+	struct sk_buff *clone;
+
+	if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
+		return NULL;
+
+	clone = skb_clone(skb, GFP_ATOMIC);
+	if (!clone) {
+		sock_put(sk);
+		return NULL;
+	}
+
+	clone->sk = sk;
+	clone->destructor = __kc_sock_efree;
+
+	return clone;
+}
+
+void __kc_skb_complete_tx_timestamp(struct sk_buff *skb,
+				    struct skb_shared_hwtstamps *hwtstamps)
+{
+	struct sock_exterr_skb *serr;
+	struct sock *sk = skb->sk;
+	int err;
+
+	sock_hold(sk);
+
+	*skb_hwtstamps(skb) = *hwtstamps;
+
+	serr = SKB_EXT_ERR(skb);
+	memset(serr, 0, sizeof(*serr));
+	serr->ee.ee_errno = ENOMSG;
+	serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
+	err = sock_queue_err_skb(sk, skb);
+	if (err)
+		kfree_skb(skb);
+
+	sock_put(sk);
+}
+#endif
+
+/* include headers needed for get_headlen function */
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#include <scsi/fc/fc_fcoe.h>
+#endif
+#ifdef HAVE_SCTP
+#include <linux/sctp.h>
+#endif
+
+u32 __kc_eth_get_headlen(const struct net_device __always_unused *dev,
+			 unsigned char *data, unsigned int max_len)
+{
+	union {
+		unsigned char *network;
+		/* l2 headers */
+		struct ethhdr *eth;
+		struct vlan_hdr *vlan;
+		/* l3 headers */
+		struct iphdr *ipv4;
+		struct ipv6hdr *ipv6;
+	} hdr;
+	__be16 proto;
+	u8 nexthdr = 0;	/* default to not TCP */
+	u8 hlen;
+
+	/* this should never happen, but better safe than sorry */
+	if (max_len < ETH_HLEN)
+		return max_len;
+
+	/* initialize network frame pointer */
+	hdr.network = data;
+
+	/* set first protocol and move network header forward */
+	proto = hdr.eth->h_proto;
+	hdr.network += ETH_HLEN;
+
+again:
+	switch (proto) {
+	/* handle any vlan tag if present */
+	case __constant_htons(ETH_P_8021AD):
+	case __constant_htons(ETH_P_8021Q):
+		if ((hdr.network - data) > (max_len - VLAN_HLEN))
+			return max_len;
+
+		proto = hdr.vlan->h_vlan_encapsulated_proto;
+		hdr.network += VLAN_HLEN;
+		goto again;
+	/* handle L3 protocols */
+	case __constant_htons(ETH_P_IP):
+		if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
+			return max_len;
+
+		/* access ihl as a u8 to avoid unaligned access on ia64 */
+		hlen = (hdr.network[0] & 0x0F) << 2;
+
+		/* verify hlen meets minimum size requirements */
+		if (hlen < sizeof(struct iphdr))
+			return hdr.network - data;
+
+		/* record next protocol if header is present */
+		if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
+			nexthdr = hdr.ipv4->protocol;
+
+		hdr.network += hlen;
+		break;
+#ifdef NETIF_F_TSO6
+	case __constant_htons(ETH_P_IPV6):
+		if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
+			return max_len;
+
+		/* record next protocol */
+		nexthdr = hdr.ipv6->nexthdr;
+		hdr.network += sizeof(struct ipv6hdr);
+		break;
+#endif /* NETIF_F_TSO6 */
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+	case __constant_htons(ETH_P_FCOE):
+		hdr.network += FCOE_HEADER_LEN;
+		break;
+#endif
+	default:
+		return hdr.network - data;
+	}
+
+	/* finally sort out L4 */
+	switch (nexthdr) {
+	case IPPROTO_TCP:
+		if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
+			return max_len;
+
+		/* access doff as a u8 to avoid unaligned access on ia64 */
+		hdr.network += max_t(u8, sizeof(struct tcphdr),
+				     (hdr.network[12] & 0xF0) >> 2);
+
+		break;
+	case IPPROTO_UDP:
+	case IPPROTO_UDPLITE:
+		hdr.network += sizeof(struct udphdr);
+		break;
+#ifdef HAVE_SCTP
+	case IPPROTO_SCTP:
+		hdr.network += sizeof(struct sctphdr);
+		break;
+#endif
+	}
+
+	/*
+	 * If everything has gone correctly hdr.network should be the
+	 * data section of the packet and will be the end of the header.
+	 * If not then it probably represents the end of the last recognized
+	 * header.
+	 */
+	return min_t(unsigned int, hdr.network - data, max_len);
+}
+
+#endif /* < 3.18.0 */
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
+#ifdef HAVE_NET_GET_RANDOM_ONCE
+static u8 __kc_netdev_rss_key[NETDEV_RSS_KEY_LEN];
+
+void __kc_netdev_rss_key_fill(void *buffer, size_t len)
+{
+	BUG_ON(len > sizeof(__kc_netdev_rss_key));
+	net_get_random_once(__kc_netdev_rss_key, sizeof(__kc_netdev_rss_key));
+	memcpy(buffer, __kc_netdev_rss_key, len);
+}
+#endif
+
+int _kc_bitmap_print_to_pagebuf(bool list, char *buf,
+				const unsigned long *maskp,
+				int nmaskbits)
+{
+	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf - 2;
+	int n = 0;
+
+	if (len > 1) {
+		n = list ? bitmap_scnlistprintf(buf, len, maskp, nmaskbits) :
+			   bitmap_scnprintf(buf, len, maskp, nmaskbits);
+		buf[n++] = '\n';
+		buf[n] = '\0';
+	}
+	return n;
+}
+#endif
+
+/******************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) )
+#if !((RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,8) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) && \
+      (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)) && \
+      (SLE_VERSION_CODE > SLE_VERSION(12,1,0)))
+unsigned int _kc_cpumask_local_spread(unsigned int i, int node)
+{
+	int cpu;
+
+	/* Wrap: we always want a cpu. */
+	i %= num_online_cpus();
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
+	/* Kernels prior to 2.6.28 do not have for_each_cpu or
+	 * cpumask_of_node, so just use for_each_online_cpu()
+	 */
+	for_each_online_cpu(cpu)
+		if (i-- == 0)
+			return cpu;
+
+	return 0;
+#else
+	if (node == -1) {
+		for_each_cpu(cpu, cpu_online_mask)
+			if (i-- == 0)
+				return cpu;
+	} else {
+		/* NUMA first. */
+		for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask)
+			if (i-- == 0)
+				return cpu;
+
+		for_each_cpu(cpu, cpu_online_mask) {
+			/* Skip NUMA nodes, done above. */
+			if (cpumask_test_cpu(cpu, cpumask_of_node(node)))
+				continue;
+
+			if (i-- == 0)
+				return cpu;
+		}
+	}
+#endif /* KERNEL_VERSION >= 2.6.28 */
+	BUG();
+}
+#endif
+#endif
+
+/******************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,2,0)))
+/**
+ * _kc_skb_flow_dissect_flow_keys - parse SKB to fill _kc_flow_keys
+ * @skb: SKB used to fille _kc_flow_keys
+ * @flow: _kc_flow_keys to set with SKB fields
+ * @flags: currently unused flags
+ *
+ * The purpose of using kcompat for this function is so the caller doesn't have
+ * to care about which kernel version they are on, which prevents a larger than
+ * normal #ifdef mess created by using a HAVE_* flag for this case. This is also
+ * done for 4.2 kernels to simplify calling skb_flow_dissect_flow_keys()
+ * because in 4.2 kernels skb_flow_dissect_flow_keys() exists, but only has 2
+ * arguments. Recent kernels have skb_flow_dissect_flow_keys() that has 3
+ * arguments.
+ *
+ * The caller needs to understand that this function was only implemented as a
+ * bare-minimum replacement for recent versions of skb_flow_dissect_flow_keys()
+ * and this function is in no way similar to skb_flow_dissect_flow_keys(). An
+ * example use can be found in the ice driver, specifically ice_arfs.c.
+ *
+ * This function is treated as a whitelist of supported fields the SKB can
+ * parse. If new functionality is added make sure to keep this format (i.e. only
+ * check for fields that are explicity wanted).
+ *
+ * Current whitelist:
+ *
+ * TCPv4, TCPv6, UDPv4, UDPv6
+ *
+ * If any unexpected protocol or other field is found this function memsets the
+ * flow passed in back to 0 and returns false. Otherwise the flow is populated
+ * and returns true.
+ */
+bool
+_kc_skb_flow_dissect_flow_keys(const struct sk_buff *skb,
+			       struct _kc_flow_keys *flow,
+			       unsigned int __always_unused flags)
+{
+	memset(flow, 0, sizeof(*flow));
+
+	flow->basic.n_proto = skb->protocol;
+	switch (flow->basic.n_proto) {
+	case htons(ETH_P_IP):
+		flow->basic.ip_proto = ip_hdr(skb)->protocol;
+		flow->addrs.v4addrs.src = ip_hdr(skb)->saddr;
+		flow->addrs.v4addrs.dst = ip_hdr(skb)->daddr;
+		break;
+	case htons(ETH_P_IPV6):
+		flow->basic.ip_proto = ipv6_hdr(skb)->nexthdr;
+		memcpy(&flow->addrs.v6addrs.src, &ipv6_hdr(skb)->saddr,
+		       sizeof(struct in6_addr));
+		memcpy(&flow->addrs.v6addrs.dst, &ipv6_hdr(skb)->daddr,
+		       sizeof(struct in6_addr));
+		break;
+	default:
+		netdev_dbg(skb->dev, "%s: Unsupported/unimplemented layer 3 protocol %04x\n", __func__, htons(flow->basic.n_proto));
+		goto unsupported;
+	}
+
+	switch (flow->basic.ip_proto) {
+	case IPPROTO_TCP:
+	{
+		struct tcphdr *tcph;
+
+		tcph = tcp_hdr(skb);
+		flow->ports.src = tcph->source;
+		flow->ports.dst = tcph->dest;
+		break;
+	}
+	case IPPROTO_UDP:
+	{
+		struct udphdr *udph;
+
+		udph = udp_hdr(skb);
+		flow->ports.src = udph->source;
+		flow->ports.dst = udph->dest;
+		break;
+	}
+	default:
+		netdev_dbg(skb->dev, "%s: Unsupported/unimplemented layer 4 protocol %02x\n", __func__, flow->basic.ip_proto);
+		return false;
+	}
+
+	return true;
+
+unsupported:
+	memset(flow, 0, sizeof(*flow));
+	return false;
+}
+#endif /* ! >= RHEL7.4 && ! >= SLES12.2 */
+#endif /* 4.3.0 */
+
+/******************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) )
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)))
+#ifdef CONFIG_SPARC
+#include <asm/idprom.h>
+#include <asm/prom.h>
+#endif
+int _kc_eth_platform_get_mac_address(struct device *dev __maybe_unused,
+				     u8 *mac_addr __maybe_unused)
+{
+#if (((LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) && defined(CONFIG_OF) && \
+      !defined(HAVE_STRUCT_DEVICE_OF_NODE) || !defined(CONFIG_OF)) && \
+     !defined(CONFIG_SPARC))
+	return -ENODEV;
+#else
+	const unsigned char *addr;
+	struct device_node *dp;
+
+	if (dev_is_pci(dev))
+		dp = pci_device_to_OF_node(to_pci_dev(dev));
+	else
+#if defined(HAVE_STRUCT_DEVICE_OF_NODE) && defined(CONFIG_OF)
+		dp = dev->of_node;
+#else
+		dp = NULL;
+#endif
+
+	addr = NULL;
+	if (dp)
+		addr = of_get_mac_address(dp);
+#ifdef CONFIG_SPARC
+	/* Kernel hasn't implemented arch_get_platform_mac_address, but we
+	 * should handle the SPARC case here since it was supported
+	 * originally. This is replaced by arch_get_platform_mac_address()
+	 * upstream.
+	 */
+	if (!addr)
+		addr = idprom->id_ethaddr;
+#endif
+	if (!addr)
+		return -ENODEV;
+
+	ether_addr_copy(mac_addr, addr);
+	return 0;
+#endif
+}
+#endif /* !(RHEL_RELEASE >= 7.3) */
+#endif /* < 4.5.0 */
+
+/*****************************************************************************/
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE <= SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,5))))
+const char *_kc_phy_speed_to_str(int speed)
+{
+	switch (speed) {
+	case SPEED_10:
+		return "10Mbps";
+	case SPEED_100:
+		return "100Mbps";
+	case SPEED_1000:
+		return "1Gbps";
+	case SPEED_2500:
+		return "2.5Gbps";
+	case SPEED_5000:
+		return "5Gbps";
+	case SPEED_10000:
+		return "10Gbps";
+	case SPEED_14000:
+		return "14Gbps";
+	case SPEED_20000:
+		return "20Gbps";
+	case SPEED_25000:
+		return "25Gbps";
+	case SPEED_40000:
+		return "40Gbps";
+	case SPEED_50000:
+		return "50Gbps";
+	case SPEED_56000:
+		return "56Gbps";
+#ifdef SPEED_100000
+	case SPEED_100000:
+		return "100Gbps";
+#endif
+	case SPEED_UNKNOWN:
+		return "Unknown";
+	default:
+		return "Unsupported (update phy-core.c)";
+	}
+}
+#endif /* (LINUX < 4.14.0) || (SLES <= 12.3.0) || (RHEL <= 7.5) */
+
+/******************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) )
+void _kc_ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
+				      struct ethtool_link_ksettings *src)
+{
+	unsigned int size = BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS);
+	unsigned int idx = 0;
+
+	for (; idx < size; idx++) {
+		dst->link_modes.supported[idx] &=
+			src->link_modes.supported[idx];
+		dst->link_modes.advertising[idx] &=
+			src->link_modes.advertising[idx];
+	}
+}
+#endif /* 4.15.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0))
+#if !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,5,0) && \
+       SLE_VERSION_CODE < SLE_VERSION(15,0,0) || \
+       SLE_VERSION_CODE >= SLE_VERSION(15,1,0))
+#if BITS_PER_LONG == 64
+/**
+ * bitmap_from_arr32 - copy the contents of u32 array of bits to bitmap
+ * @bitmap: array of unsigned longs, the destination bitmap
+ * @buf: array of u32 (in host byte order), the source bitmap
+ * @nbits: number of bits in @bitmap
+ */
+void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf, unsigned int nbits)
+{
+	unsigned int i, halfwords;
+
+	halfwords = DIV_ROUND_UP(nbits, 32);
+	for (i = 0; i < halfwords; i++) {
+		bitmap[i/2] = (unsigned long) buf[i];
+		if (++i < halfwords)
+			bitmap[i/2] |= ((unsigned long) buf[i]) << 32;
+	}
+
+	/* Clear tail bits in last word beyond nbits. */
+	if (nbits % BITS_PER_LONG)
+		bitmap[(halfwords - 1) / 2] &= BITMAP_LAST_WORD_MASK(nbits);
+}
+#endif /* BITS_PER_LONG == 64 */
+#endif /* !(RHEL >= 8.0) && !(SLES >= 12.5 && SLES < 15.0 || SLES >= 15.1) */
+#endif /* 4.16.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+/* PCIe link information */
+#define PCIE_SPEED2STR(speed) \
+	((speed) == PCIE_SPEED_16_0GT ? "16 GT/s" : \
+	 (speed) == PCIE_SPEED_8_0GT ? "8 GT/s" : \
+	 (speed) == PCIE_SPEED_5_0GT ? "5 GT/s" : \
+	 (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
+	 "Unknown speed")
+
+/* PCIe speed to Mb/s reduced by encoding overhead */
+#define PCIE_SPEED2MBS_ENC(speed) \
+	((speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
+	 (speed) == PCIE_SPEED_8_0GT  ?  8000*128/130 : \
+	 (speed) == PCIE_SPEED_5_0GT  ?  5000*8/10 : \
+	 (speed) == PCIE_SPEED_2_5GT  ?  2500*8/10 : \
+	 0)
+
+static u32
+_kc_pcie_bandwidth_available(struct pci_dev *dev,
+			     struct pci_dev **limiting_dev,
+			     enum pci_bus_speed *speed,
+			     enum pcie_link_width *width)
+{
+	u16 lnksta;
+	enum pci_bus_speed next_speed;
+	enum pcie_link_width next_width;
+	u32 bw, next_bw;
+
+	if (speed)
+		*speed = PCI_SPEED_UNKNOWN;
+	if (width)
+		*width = PCIE_LNK_WIDTH_UNKNOWN;
+
+	bw = 0;
+
+	while (dev) {
+		pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+
+		next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
+		next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
+			PCI_EXP_LNKSTA_NLW_SHIFT;
+
+		next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
+
+		/* Check if current device limits the total bandwidth */
+		if (!bw || next_bw <= bw) {
+			bw = next_bw;
+
+			if (limiting_dev)
+				*limiting_dev = dev;
+			if (speed)
+				*speed = next_speed;
+			if (width)
+				*width = next_width;
+		}
+
+		dev = pci_upstream_bridge(dev);
+	}
+
+	return bw;
+}
+
+static enum pci_bus_speed _kc_pcie_get_speed_cap(struct pci_dev *dev)
+{
+	u32 lnkcap2, lnkcap;
+
+	/*
+	 * PCIe r4.0 sec 7.5.3.18 recommends using the Supported Link
+	 * Speeds Vector in Link Capabilities 2 when supported, falling
+	 * back to Max Link Speed in Link Capabilities otherwise.
+	 */
+	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
+	if (lnkcap2) { /* PCIe r3.0-compliant */
+		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
+			return PCIE_SPEED_16_0GT;
+		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
+			return PCIE_SPEED_8_0GT;
+		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
+			return PCIE_SPEED_5_0GT;
+		else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
+			return PCIE_SPEED_2_5GT;
+		return PCI_SPEED_UNKNOWN;
+	}
+
+	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+	if (lnkcap) {
+		if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
+			return PCIE_SPEED_16_0GT;
+		else if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
+			return PCIE_SPEED_8_0GT;
+		else if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
+			return PCIE_SPEED_5_0GT;
+		else if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
+			return PCIE_SPEED_2_5GT;
+	}
+
+	return PCI_SPEED_UNKNOWN;
+}
+
+static enum pcie_link_width _kc_pcie_get_width_cap(struct pci_dev *dev)
+{
+	u32 lnkcap;
+
+	pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+	if (lnkcap)
+		return (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
+
+	return PCIE_LNK_WIDTH_UNKNOWN;
+}
+
+static u32
+_kc_pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
+			   enum pcie_link_width *width)
+{
+	*speed = _kc_pcie_get_speed_cap(dev);
+	*width = _kc_pcie_get_width_cap(dev);
+
+	if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
+		return 0;
+
+	return *width * PCIE_SPEED2MBS_ENC(*speed);
+}
+
+void _kc_pcie_print_link_status(struct pci_dev *dev) {
+	enum pcie_link_width width, width_cap;
+	enum pci_bus_speed speed, speed_cap;
+	struct pci_dev *limiting_dev = NULL;
+	u32 bw_avail, bw_cap;
+
+	bw_cap = _kc_pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
+	bw_avail = _kc_pcie_bandwidth_available(dev, &limiting_dev, &speed,
+						&width);
+
+	if (bw_avail >= bw_cap)
+		pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
+			 bw_cap / 1000, bw_cap % 1000,
+			 PCIE_SPEED2STR(speed_cap), width_cap);
+	else
+		pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
+			 bw_avail / 1000, bw_avail % 1000,
+			 PCIE_SPEED2STR(speed), width,
+			 limiting_dev ? pci_name(limiting_dev) : "<unknown>",
+			 bw_cap / 1000, bw_cap % 1000,
+			 PCIE_SPEED2STR(speed_cap), width_cap);
+}
+#endif /* 4.17.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,1)))
+#define HAVE_NDO_FDB_ADD_EXTACK
+#else /* !RHEL || RHEL < 8.1 */
+#ifdef HAVE_TC_SETUP_CLSFLOWER
+#define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\
+	const struct flow_match *__m = &(__rule)->match;			\
+	struct flow_dissector *__d = (__m)->dissector;				\
+										\
+	(__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key);	\
+	(__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask);	\
+
+void txgbe_flow_rule_match_basic(const struct flow_rule *rule,
+			   struct flow_match_basic *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_BASIC, out);
+}
+
+void txgbe_flow_rule_match_control(const struct flow_rule *rule,
+			     struct flow_match_control *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CONTROL, out);
+}
+
+void txgbe_flow_rule_match_eth_addrs(const struct flow_rule *rule,
+			       struct flow_match_eth_addrs *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS, out);
+}
+
+#ifdef HAVE_TC_FLOWER_ENC
+void txgbe_flow_rule_match_enc_keyid(const struct flow_rule *rule,
+			       struct flow_match_enc_keyid *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_KEYID, out);
+}
+
+void txgbe_flow_rule_match_enc_ports(const struct flow_rule *rule,
+			       struct flow_match_ports *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_PORTS, out);
+}
+
+void txgbe_flow_rule_match_enc_control(const struct flow_rule *rule,
+				 struct flow_match_control *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL, out);
+}
+
+void txgbe_flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
+				    struct flow_match_ipv4_addrs *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, out);
+}
+
+void txgbe_flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
+				    struct flow_match_ipv6_addrs *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, out);
+}
+#endif
+
+#ifndef HAVE_TC_FLOWER_VLAN_IN_TAGS
+void txgbe_flow_rule_match_vlan(const struct flow_rule *rule,
+			  struct flow_match_vlan *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_VLAN, out);
+}
+#endif
+
+void txgbe_flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
+				struct flow_match_ipv4_addrs *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS, out);
+}
+
+void txgbe_flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
+				struct flow_match_ipv6_addrs *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS, out);
+}
+
+void txgbe_flow_rule_match_ports(const struct flow_rule *rule,
+			   struct flow_match_ports *out)
+{
+	FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS, out);
+}
+#endif /* HAVE_TC_SETUP_CLSFLOWER */
+#endif /* !RHEL || RHEL < 8.1 */
+#endif /* 5.1.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0))
+#if (!(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2))))
+#ifdef HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#if 0
+int _kc_flow_block_cb_setup_simple(struct flow_block_offload *f,
+				   struct list_head __always_unused *driver_list,
+				   tc_setup_cb_t *cb,
+				   void *cb_ident, void *cb_priv,
+				   bool ingress_only)
+{
+	if (ingress_only &&
+	    f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+		return -EOPNOTSUPP;
+
+	/* Note: Upstream has driver_block_list, but older kernels do not */
+	switch (f->command) {
+	case TC_BLOCK_BIND:
+#ifdef HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+		return tcf_block_cb_register(f->block, cb, cb_ident, cb_priv,
+					     f->extack);
+#else
+		return tcf_block_cb_register(f->block, cb, cb_ident, cb_priv);
+#endif
+	case TC_BLOCK_UNBIND:
+		tcf_block_cb_unregister(f->block, cb, cb_ident);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+#endif
+#endif
+#endif /* HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO */
+#endif /* 5.3.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0))
+u64 _kc_pci_get_dsn(struct pci_dev *dev)
+{
+	u32 dword;
+	u64 dsn;
+	int pos;
+
+	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
+	if (!pos)
+		return 0;
+
+	/*
+	 * The Device Serial Number is two dwords offset 4 bytes from the
+	 * capability position. The specification says that the first dword is
+	 * the lower half, and the second dword is the upper half.
+	 */
+	pos += 4;
+	pci_read_config_dword(dev, pos, &dword);
+	dsn = (u64)dword;
+	pci_read_config_dword(dev, pos + 4, &dword);
+	dsn |= ((u64)dword) << 32;
+
+	return dsn;
+}
+#endif /* 5.7.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,17,0))
+void _kc_eth_hw_addr_set(struct net_device *dev, const void *addr)
+{
+	ether_addr_copy(dev->dev_addr, addr);
+}
+#endif
\ No newline at end of file
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat.h b/drivers/net/ethernet/wangxun/txgbe/kcompat.h
new file mode 100644
index 000000000000..047ddea7aabb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat.h
@@ -0,0 +1,7693 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on kcompat.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#ifndef _KCOMPAT_H_
+#define _KCOMPAT_H_
+
+#include "kcompat_gcc.h"
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#else
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include <linux/if_link.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+#include <linux/vmalloc.h>
+
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 10000		\
+		     + __GNUC_MINOR__ * 100	\
+		     + __GNUC_PATCHLEVEL__)
+#endif /* GCC_VERSION */
+
+/* Backport macros for controlling GCC diagnostics */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) )
+
+/* Compilers before gcc-4.6 do not understand "#pragma GCC diagnostic push" */
+#if GCC_VERSION >= 40600
+#define __diag_str1(s)		#s
+#define __diag_str(s)		__diag_str1(s)
+#define __diag(s)		_Pragma(__diag_str(GCC diagnostic s))
+#else
+#define __diag(s)
+#endif /* GCC_VERSION >= 4.6 */
+#define __diag_push()	__diag(push)
+#define __diag_pop()	__diag(pop)
+#endif /* LINUX_VERSION < 4.18.0 */
+
+#ifndef NSEC_PER_MSEC
+#define NSEC_PER_MSEC 1000000L
+#endif
+#include <net/ipv6.h>
+/* UTS_RELEASE is in a different header starting in kernel 2.6.18 */
+#ifndef UTS_RELEASE
+/* utsrelease.h changed locations in 2.6.33 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) )
+#include <linux/utsrelease.h>
+#else
+#include <generated/utsrelease.h>
+#endif
+#endif
+
+/**************************selection************************************/
+
+/*#define TXGBE_SUPPORT_KYLIN_FT*/	/*kylinft to open*/
+/*#define TXGBE_SUPPORT_KYLIN_LX*/	/*kylinlx to open*/
+
+#ifndef AUTO
+#define AUTO 1
+#endif 
+
+#ifndef KR_FEC
+#define KR_FEC 0
+#endif 
+
+/**************************performance************************************/
+#ifndef DEFAULT_FCPAUSE
+#define DEFAULT_FCPAUSE 0xFFFF 	/* kylinft/kylinlx : 0x3FFF	default to 0xFFFF*/
+#endif 
+
+#ifndef MAX_REQUEST_SIZE
+#define MAX_REQUEST_SIZE 256		/* kylinft : 512	default to 256*/
+#endif 
+
+#ifndef DEFAULT_TXD
+#define DEFAULT_TXD 512				/*deepinsw : 1024	default to 512*/
+#endif 
+
+#ifndef DEFAULT_TX_WORK
+#define DEFAULT_TX_WORK 256			/*deepinsw : 512	default to 256*/
+#endif 
+
+#ifndef CL72_KRTR_PRBS_MODE_EN
+#define CL72_KRTR_PRBS_MODE_EN 0xffff			/*open kr prbs check */
+#endif 
+
+#ifndef TXGBE_STATIC_ITR
+#define TXGBE_STATIC_ITR 1		/* static itr configure */
+#endif 
+
+/**************************performance************************************/
+
+/**************************sfi************************************/
+#ifndef SFI_SET
+#define SFI_SET 0
+#define SFI_MAIN 24
+#define SFI_PRE 4
+#define SFI_POST 16
+#endif 
+#ifndef SFI_TXRX_PIN
+#define SFI_TXRX_PIN 0			/*rx : 0xf  tx : 0xf0 */
+#endif 
+/**************************sfi************************************/
+
+/**************************kr************************************/
+#ifndef KR_MODE
+#define KR_MODE 0
+#endif 
+
+#ifndef KR_AN73_PRESET
+#define KR_AN73_PRESET 0
+#endif
+
+#ifndef KR_POLLING
+#define KR_POLLING 1
+#endif 
+
+#ifndef KR_NORESET
+#define KR_NORESET 1
+#endif
+
+#ifndef KR_CL72_TRAINING
+#define KR_CL72_TRAINING 1
+#endif
+
+#ifndef KR_NOREINITED
+#define KR_NOREINITED 0
+#endif
+
+#ifndef KR_SET
+#define KR_SET 0
+#define KR_MAIN 27
+#define KR_PRE 8
+#define KR_POST 44
+#endif
+#ifndef KR_TXRX_PIN
+#define KR_TXRX_PIN 0			/*rx : 0xf  tx : 0xf0 */
+#endif 
+/**************************kr************************************/
+
+/**************************kx4************************************/
+#ifndef KX4_SET
+#define KX4_SET 0
+#define KX4_MAIN 40
+#define KX4_PRE 0
+#define KX4_POST 0
+#endif
+#ifndef KX4_TXRX_PIN
+#define KX4_TXRX_PIN 0			/*rx : 0xf  tx : 0xf0 */
+#endif 
+/**************************kx4************************************/
+
+/**************************kx************************************/
+#ifndef KX_SET
+#define KX_SET 0
+#define KX_MAIN 24
+#define KX_PRE 4
+#define KX_POST 16
+#endif
+
+#ifndef KX_SGMII
+#define KX_SGMII 0				/* 1   0x18090 :0xcf00 */
+#endif 
+/**************************kx************************************/
+
+#ifndef BOND_CHECK_LINK_MODE
+#define BOND_CHECK_LINK_MODE 0
+#endif
+
+/**************************selection************************************/
+
+/* For Kylin:
+ * support Kylin-4.0.2-SP2-17122218.j1-arm64 */
+#if defined(TXGBE_SUPPORT_KYLIN_FT) || defined(TXGBE_SUPPORT_KYLIN_LX)
+#ifdef UTS_UBUNTU_RELEASE_ABI
+#undef UTS_UBUNTU_RELEASE_ABI
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
+#define UTS_UBUNTU_RELEASE_ABI 21
+#else
+#define UTS_UBUNTU_RELEASE_ABI 21
+#endif
+#endif
+
+#ifdef UTS_KYLINOS_RELEASE_ABI
+#ifndef UTS_UBUNTU_RELEASE_ABI
+#if UTS_KYLINOS_RELEASE_ABI <= 20171215
+#define UTS_UBUNTU_RELEASE_ABI 21
+#else
+#define UTS_UBUNTU_RELEASE_ABI 21
+#endif
+#endif /* !UTS_UBUNTU_RELEASE_ABI */
+#endif /* UTS_KYLINOS_RELEASE_ABI */
+
+/* NAPI enable/disable flags here */
+#define NAPI
+
+#define adapter_struct txgbe_adapter
+#define adapter_q_vector txgbe_q_vector
+
+/* and finally set defines so that the code sees the changes */
+#ifdef NAPI
+#else
+#endif /* NAPI */
+
+/* Dynamic LTR and deeper C-State support disable/enable */
+
+/* packet split disable/enable */
+#ifdef DISABLE_PACKET_SPLIT
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+#define CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+#endif
+#endif /* DISABLE_PACKET_SPLIT */
+
+/* MSI compatibility code for all kernels and drivers */
+#ifdef DISABLE_PCI_MSI
+#undef CONFIG_PCI_MSI
+#endif
+#ifndef CONFIG_PCI_MSI
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) )
+struct msix_entry {
+	u16 vector; /* kernel uses to write allocated vector */
+	u16 entry;  /* driver uses to specify entry, OS writes */
+};
+#endif
+#undef pci_enable_msi
+#define pci_enable_msi(a) -ENOTSUPP
+#undef pci_disable_msi
+#define pci_disable_msi(a) do {} while (0)
+#undef pci_enable_msix
+#define pci_enable_msix(a, b, c) -ENOTSUPP
+#undef pci_disable_msix
+#define pci_disable_msix(a) do {} while (0)
+#define msi_remove_pci_irq_vectors(a) do {} while (0)
+#endif /* CONFIG_PCI_MSI */
+#ifdef DISABLE_PM
+#undef CONFIG_PM
+#endif
+
+#ifdef DISABLE_NET_POLL_CONTROLLER
+#undef CONFIG_NET_POLL_CONTROLLER
+#endif
+
+#ifndef PMSG_SUSPEND
+#define PMSG_SUSPEND 3
+#endif
+
+/* generic boolean compatibility */
+#undef TRUE
+#undef FALSE
+#define TRUE true
+#define FALSE false
+#ifdef GCC_VERSION
+#if ( GCC_VERSION < 3000 )
+#define _Bool char
+#endif
+#else
+#define _Bool char
+#endif
+
+#ifndef ipv6_authlen
+#define ipv6_authlen(p) (((p)->hdrlen+2) << 2)
+#endif
+
+#ifndef BIT
+#define BIT(nr)         (1UL << (nr))
+#endif
+
+#undef __always_unused
+#define __always_unused __attribute__((__unused__))
+
+#undef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+
+/* kernels less than 2.4.14 don't have this */
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif
+
+#ifndef module_param
+#define module_param(v,t,p) MODULE_PARM(v, "i");
+#endif
+
+#ifndef DMA_64BIT_MASK
+#define DMA_64BIT_MASK  0xffffffffffffffffULL
+#endif
+
+#ifndef DMA_32BIT_MASK
+#define DMA_32BIT_MASK  0x00000000ffffffffULL
+#endif
+
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+
+#ifndef uninitialized_var
+#define uninitialized_var(x) x = x
+#endif
+
+#ifndef PCIE_LINK_STATE_L0S
+#define PCIE_LINK_STATE_L0S 1
+#endif
+#ifndef PCIE_LINK_STATE_L1
+#define PCIE_LINK_STATE_L1 2
+#endif
+
+#ifndef SET_NETDEV_DEV
+#define SET_NETDEV_DEV(net, pdev)
+#endif
+
+#if !defined(HAVE_FREE_NETDEV) && ( LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) )
+#define free_netdev(x)	kfree(x)
+#endif
+
+#ifdef HAVE_POLL_CONTROLLER
+#define CONFIG_NET_POLL_CONTROLLER
+#endif
+
+#ifndef SKB_DATAREF_SHIFT
+/* if we do not have the infrastructure to detect if skb_header is cloned
+   just return false in all cases */
+#define skb_header_cloned(x) 0
+#endif
+
+#ifndef NETIF_F_GSO
+#define gso_size tso_size
+#define gso_segs tso_segs
+#endif
+
+#ifndef NETIF_F_GRO
+#define vlan_gro_receive(_napi, _vlgrp, _vlan, _skb) \
+		vlan_hwaccel_receive_skb(_skb, _vlgrp, _vlan)
+#define napi_gro_receive(_napi, _skb) netif_receive_skb(_skb)
+#endif
+
+#ifndef NETIF_F_SCTP_CSUM
+#define NETIF_F_SCTP_CSUM 0
+#endif
+
+#ifndef NETIF_F_LRO
+#define NETIF_F_LRO BIT(15)
+#endif
+
+#ifndef NETIF_F_NTUPLE
+#define NETIF_F_NTUPLE BIT(27)
+#endif
+
+#ifndef NETIF_F_ALL_FCOE
+#define NETIF_F_ALL_FCOE	(NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \
+				 NETIF_F_FSO)
+#endif
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+#ifndef IPPROTO_UDPLITE
+#define IPPROTO_UDPLITE 136
+#endif
+
+#ifndef CHECKSUM_PARTIAL
+#define CHECKSUM_PARTIAL CHECKSUM_HW
+#define CHECKSUM_COMPLETE CHECKSUM_HW
+#endif
+
+#ifndef __read_mostly
+#define __read_mostly
+#endif
+
+#ifndef MII_RESV1
+#define MII_RESV1		0x17		/* Reserved...		*/
+#endif
+
+#ifndef unlikely
+#define unlikely(_x) _x
+#define likely(_x) _x
+#endif
+
+#ifndef WARN_ON
+#define WARN_ON(x)
+#endif
+
+#ifndef PCI_DEVICE
+#define PCI_DEVICE(vend,dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#endif
+
+#ifndef node_online
+#define node_online(node) ((node) == 0)
+#endif
+
+#ifndef _LINUX_RANDOM_H
+#include <linux/random.h>
+#endif
+
+#ifndef BITS_PER_TYPE
+#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
+#endif
+
+#ifndef BITS_TO_LONGS
+#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#endif
+
+#ifndef DECLARE_BITMAP
+#define DECLARE_BITMAP(name,bits) long name[BITS_TO_LONGS(bits)]
+#endif
+
+#ifndef VLAN_HLEN
+#define VLAN_HLEN 4
+#endif
+
+#ifndef VLAN_ETH_HLEN
+#define VLAN_ETH_HLEN 18
+#endif
+
+#ifndef VLAN_ETH_FRAME_LEN
+#define VLAN_ETH_FRAME_LEN 1518
+#endif
+
+#ifndef DCA_GET_TAG_TWO_ARGS
+#define dca3_get_tag(a,b) dca_get_tag(b)
+#endif
+
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#if defined(__i386__) || defined(__x86_64__)
+#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#endif
+#endif
+
+/* taken from 2.6.24 definition in linux/kernel.h */
+#ifndef IS_ALIGNED
+#define IS_ALIGNED(x,a)         (((x) % ((typeof(x))(a))) == 0)
+#endif
+
+#ifdef IS_ENABLED
+#undef IS_ENABLED
+#undef __ARG_PLACEHOLDER_1
+#undef config_enabled
+#undef _config_enabled
+#undef __config_enabled
+#undef ___config_enabled
+#endif
+
+#define __ARG_PLACEHOLDER_1 0,
+#define config_enabled(cfg) _config_enabled(cfg)
+#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
+#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
+#define ___config_enabled(__ignored, val, ...) val
+
+#define IS_ENABLED(option) \
+	(config_enabled(option) || config_enabled(option##_MODULE))
+
+#if !defined(NETIF_F_HW_VLAN_TX) && !defined(NETIF_F_HW_VLAN_CTAG_TX)
+struct _kc_vlan_ethhdr {
+	unsigned char	h_dest[ETH_ALEN];
+	unsigned char	h_source[ETH_ALEN];
+	__be16		h_vlan_proto;
+	__be16		h_vlan_TCI;
+	__be16		h_vlan_encapsulated_proto;
+};
+#define vlan_ethhdr _kc_vlan_ethhdr
+struct _kc_vlan_hdr {
+	__be16		h_vlan_TCI;
+	__be16		h_vlan_encapsulated_proto;
+};
+#define vlan_hdr _kc_vlan_hdr
+#define vlan_tx_tag_present(_skb) 0
+#define vlan_tx_tag_get(_skb) 0
+#endif /* NETIF_F_HW_VLAN_TX && NETIF_F_HW_VLAN_CTAG_TX */
+
+#ifndef VLAN_PRIO_SHIFT
+#define VLAN_PRIO_SHIFT 13
+#endif
+
+#ifndef PCI_EXP_LNKSTA_CLS_2_5GB
+#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001
+#endif
+
+#ifndef PCI_EXP_LNKSTA_CLS_5_0GB
+#define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002
+#endif
+
+#ifndef PCI_EXP_LNKSTA_CLS_8_0GB
+#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003
+#endif
+
+#ifndef PCI_EXP_LNKSTA_NLW_X1
+#define PCI_EXP_LNKSTA_NLW_X1 0x0010
+#endif
+
+#ifndef PCI_EXP_LNKSTA_NLW_X2
+#define PCI_EXP_LNKSTA_NLW_X2 0x0020
+#endif
+
+#ifndef PCI_EXP_LNKSTA_NLW_X4
+#define PCI_EXP_LNKSTA_NLW_X4 0x0040
+#endif
+
+#ifndef PCI_EXP_LNKSTA_NLW_X8
+#define PCI_EXP_LNKSTA_NLW_X8 0x0080
+#endif
+
+#ifndef __GFP_COLD
+#define __GFP_COLD 0
+#endif
+
+#ifndef __GFP_COMP
+#define __GFP_COMP 0
+#endif
+
+#ifndef IP_OFFSET
+#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
+#endif
+
+/*****************************************************************************/
+/* Installations with ethtool version without eeprom, adapter id, or statistics
+ * support */
+
+#ifndef ETH_GSTRING_LEN
+#define ETH_GSTRING_LEN 32
+#endif
+
+#ifndef ETHTOOL_GSTATS
+#define ETHTOOL_GSTATS 0x1d
+#undef ethtool_drvinfo
+#define ethtool_drvinfo k_ethtool_drvinfo
+struct k_ethtool_drvinfo {
+	u32 cmd;
+	char driver[32];
+	char version[32];
+	char fw_version[32];
+	char bus_info[32];
+	char reserved1[32];
+	char reserved2[16];
+	u32 n_stats;
+	u32 testinfo_len;
+	u32 eedump_len;
+	u32 regdump_len;
+};
+
+struct ethtool_stats {
+	u32 cmd;
+	u32 n_stats;
+	u64 data[0];
+};
+#endif /* ETHTOOL_GSTATS */
+
+#ifndef ETHTOOL_PHYS_ID
+#define ETHTOOL_PHYS_ID 0x1c
+#endif /* ETHTOOL_PHYS_ID */
+
+#ifndef ETHTOOL_GSTRINGS
+#define ETHTOOL_GSTRINGS 0x1b
+enum ethtool_stringset {
+	ETH_SS_TEST             = 0,
+	ETH_SS_STATS,
+};
+struct ethtool_gstrings {
+	u32 cmd;            /* ETHTOOL_GSTRINGS */
+	u32 string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
+	u32 len;            /* number of strings in the string set */
+	u8 data[0];
+};
+#endif /* ETHTOOL_GSTRINGS */
+
+#ifndef ETHTOOL_TEST
+#define ETHTOOL_TEST 0x1a
+enum ethtool_test_flags {
+	ETH_TEST_FL_OFFLINE	= BIT(0),
+	ETH_TEST_FL_FAILED	= BIT(1),
+};
+struct ethtool_test {
+	u32 cmd;
+	u32 flags;
+	u32 reserved;
+	u32 len;
+	u64 data[0];
+};
+#endif /* ETHTOOL_TEST */
+
+#ifndef ETHTOOL_GEEPROM
+#define ETHTOOL_GEEPROM 0xb
+#undef ETHTOOL_GREGS
+struct ethtool_eeprom {
+	u32 cmd;
+	u32 magic;
+	u32 offset;
+	u32 len;
+	u8 data[0];
+};
+
+struct ethtool_value {
+	u32 cmd;
+	u32 data;
+};
+#endif /* ETHTOOL_GEEPROM */
+
+#ifndef ETHTOOL_GLINK
+#define ETHTOOL_GLINK 0xa
+#endif /* ETHTOOL_GLINK */
+
+#ifndef ETHTOOL_GWOL
+#define ETHTOOL_GWOL 0x5
+#define ETHTOOL_SWOL 0x6
+#define SOPASS_MAX      6
+struct ethtool_wolinfo {
+	u32 cmd;
+	u32 supported;
+	u32 wolopts;
+	u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+#endif /* ETHTOOL_GWOL */
+
+#ifndef ETHTOOL_GREGS
+#define ETHTOOL_GREGS		0x00000004 /* Get NIC registers */
+#define ethtool_regs _kc_ethtool_regs
+/* for passing big chunks of data */
+struct _kc_ethtool_regs {
+	u32 cmd;
+	u32 version; /* driver-specific, indicates different chips/revs */
+	u32 len; /* bytes */
+	u8 data[0];
+};
+#endif /* ETHTOOL_GREGS */
+
+#ifndef ETHTOOL_GMSGLVL
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#endif
+#ifndef ETHTOOL_SMSGLVL
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level, priv. */
+#endif
+#ifndef ETHTOOL_NWAY_RST
+#define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation, priv */
+#endif
+#ifndef ETHTOOL_GLINK
+#define ETHTOOL_GLINK		0x0000000a /* Get link status */
+#endif
+#ifndef ETHTOOL_GEEPROM
+#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
+#endif
+#ifndef ETHTOOL_SEEPROM
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data */
+#endif
+#ifndef ETHTOOL_GCOALESCE
+#define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
+/* for configuring coalescing parameters of chip */
+#define ethtool_coalesce _kc_ethtool_coalesce
+struct _kc_ethtool_coalesce {
+	u32	cmd;	/* ETHTOOL_{G,S}COALESCE */
+
+	/* How many usecs to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	rx_coalesce_usecs;
+
+	/* How many packets to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause RX interrupts to never be
+	 * generated.
+	 */
+	u32	rx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being serviced by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	rx_coalesce_usecs_irq;
+	u32	rx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	tx_coalesce_usecs;
+
+	/* How many packets to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause TX interrupts to never be
+	 * generated.
+	 */
+	u32	tx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being serviced by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	tx_coalesce_usecs_irq;
+	u32	tx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay in-memory statistics
+	 * block updates.  Some drivers do not have an in-memory
+	 * statistic block, and in such cases this value is ignored.
+	 * This value must not be zero.
+	 */
+	u32	stats_block_coalesce_usecs;
+
+	/* Adaptive RX/TX coalescing is an algorithm implemented by
+	 * some drivers to improve latency under low packet rates and
+	 * improve throughput under high packet rates.  Some drivers
+	 * only implement one of RX or TX adaptive coalescing.  Anything
+	 * not implemented by the driver causes these values to be
+	 * silently ignored.
+	 */
+	u32	use_adaptive_rx_coalesce;
+	u32	use_adaptive_tx_coalesce;
+
+	/* When the packet rate (measured in packets per second)
+	 * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+	 * used.
+	 */
+	u32	pkt_rate_low;
+	u32	rx_coalesce_usecs_low;
+	u32	rx_max_coalesced_frames_low;
+	u32	tx_coalesce_usecs_low;
+	u32	tx_max_coalesced_frames_low;
+
+	/* When the packet rate is below pkt_rate_high but above
+	 * pkt_rate_low (both measured in packets per second) the
+	 * normal {rx,tx}_* coalescing parameters are used.
+	 */
+
+	/* When the packet rate is (measured in packets per second)
+	 * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+	 * used.
+	 */
+	u32	pkt_rate_high;
+	u32	rx_coalesce_usecs_high;
+	u32	rx_max_coalesced_frames_high;
+	u32	tx_coalesce_usecs_high;
+	u32	tx_max_coalesced_frames_high;
+
+	/* How often to do adaptive coalescing packet rate sampling,
+	 * measured in seconds.  Must not be zero.
+	 */
+	u32	rate_sample_interval;
+};
+#endif /* ETHTOOL_GCOALESCE */
+
+#ifndef ETHTOOL_SCOALESCE
+#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config. */
+#endif
+#ifndef ETHTOOL_GRINGPARAM
+#define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
+/* for configuring RX/TX ring parameters */
+#define ethtool_ringparam _kc_ethtool_ringparam
+struct _kc_ethtool_ringparam {
+	u32	cmd;	/* ETHTOOL_{G,S}RINGPARAM */
+
+	/* Read only attributes.  These indicate the maximum number
+	 * of pending RX/TX ring entries the driver will allow the
+	 * user to set.
+	 */
+	u32	rx_max_pending;
+	u32	rx_mini_max_pending;
+	u32	rx_jumbo_max_pending;
+	u32	tx_max_pending;
+
+	/* Values changeable by the user.  The valid values are
+	 * in the range 1 to the "*_max_pending" counterpart above.
+	 */
+	u32	rx_pending;
+	u32	rx_mini_pending;
+	u32	rx_jumbo_pending;
+	u32	tx_pending;
+};
+#endif /* ETHTOOL_GRINGPARAM */
+
+#ifndef ETHTOOL_SRINGPARAM
+#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters, priv. */
+#endif
+#ifndef ETHTOOL_GPAUSEPARAM
+#define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
+/* for configuring link flow control parameters */
+#define ethtool_pauseparam _kc_ethtool_pauseparam
+struct _kc_ethtool_pauseparam {
+	u32	cmd;	/* ETHTOOL_{G,S}PAUSEPARAM */
+
+	/* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+	 * being true) the user may set 'autoneg' here non-zero to have the
+	 * pause parameters be auto-negotiated too.  In such a case, the
+	 * {rx,tx}_pause values below determine what capabilities are
+	 * advertised.
+	 *
+	 * If 'autoneg' is zero or the link is not being auto-negotiated,
+	 * then {rx,tx}_pause force the driver to use/not-use pause
+	 * flow control.
+	 */
+	u32	autoneg;
+	u32	rx_pause;
+	u32	tx_pause;
+};
+#endif /* ETHTOOL_GPAUSEPARAM */
+
+#ifndef ETHTOOL_SPAUSEPARAM
+#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters. */
+#endif
+#ifndef ETHTOOL_GRXCSUM
+#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_SRXCSUM
+#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_GTXCSUM
+#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_STXCSUM
+#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_GSG
+#define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
+					    * (ethtool_value) */
+#endif
+#ifndef ETHTOOL_SSG
+#define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
+					    * (ethtool_value). */
+#endif
+#ifndef ETHTOOL_TEST
+#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test, priv. */
+#endif
+#ifndef ETHTOOL_GSTRINGS
+#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
+#endif
+#ifndef ETHTOOL_PHYS_ID
+#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
+#endif
+#ifndef ETHTOOL_GSTATS
+#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
+#endif
+#ifndef ETHTOOL_GTSO
+#define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_STSO
+#define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
+#endif
+
+#ifndef ETHTOOL_BUSINFO_LEN
+#define ETHTOOL_BUSINFO_LEN	32
+#endif
+
+#ifndef WAKE_FILTER
+#define WAKE_FILTER	BIT(7)
+#endif
+
+#ifndef SPEED_2500
+#define SPEED_2500 2500
+#endif
+#ifndef SPEED_5000
+#define SPEED_5000 5000
+#endif
+#ifndef SPEED_14000
+#define SPEED_14000 14000
+#endif
+#ifndef SPEED_25000
+#define SPEED_25000 25000
+#endif
+#ifndef SPEED_50000
+#define SPEED_50000 50000
+#endif
+#ifndef SPEED_56000
+#define SPEED_56000 56000
+#endif
+#ifndef SPEED_100000
+#define SPEED_100000 100000
+#endif
+
+#ifndef RHEL_RELEASE_VERSION
+#define RHEL_RELEASE_VERSION(a,b) (((a) << 8) + (b))
+#endif
+#ifndef AX_RELEASE_VERSION
+#define AX_RELEASE_VERSION(a,b) (((a) << 8) + (b))
+#endif
+
+#ifndef AX_RELEASE_CODE
+#define AX_RELEASE_CODE 0
+#endif
+
+#if (AX_RELEASE_CODE && AX_RELEASE_CODE == AX_RELEASE_VERSION(3,0))
+#define RHEL_RELEASE_CODE RHEL_RELEASE_VERSION(5,0)
+#elif (AX_RELEASE_CODE && AX_RELEASE_CODE == AX_RELEASE_VERSION(3,1))
+#define RHEL_RELEASE_CODE RHEL_RELEASE_VERSION(5,1)
+#elif (AX_RELEASE_CODE && AX_RELEASE_CODE == AX_RELEASE_VERSION(3,2))
+#define RHEL_RELEASE_CODE RHEL_RELEASE_VERSION(5,3)
+#endif
+
+#ifndef RHEL_RELEASE_CODE
+/* NOTE: RHEL_RELEASE_* introduced in RHEL4.5 */
+#define RHEL_RELEASE_CODE 0
+#endif
+
+/* RHEL 7 didn't backport the parameter change in
+ * create_singlethread_workqueue.
+ * If/when RH corrects this we will want to tighten up the version check.
+ */
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0))
+#undef create_singlethread_workqueue
+#define create_singlethread_workqueue(name)	\
+	alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name)
+#endif
+
+/* Ubuntu Release ABI is the 4th digit of their kernel version. You can find
+ * it in /usr/src/linux/$(uname -r)/include/generated/utsrelease.h for new
+ * enough versions of Ubuntu. Otherwise you can simply see it in the output of
+ * uname as the 4th digit of the kernel. The UTS_UBUNTU_RELEASE_ABI is not in
+ * the linux-source package, but in the linux-headers package. It begins to
+ * appear in later releases of 14.04 and 14.10.
+ *
+ * Ex:
+ * <Ubuntu 14.04.1>
+ *  $uname -r
+ *  3.13.0-45-generic
+ * ABI is 45
+ *
+ * <Ubuntu 14.10>
+ *  $uname -r
+ *  3.16.0-23-generic
+ * ABI is 23
+ */
+#ifndef UTS_UBUNTU_RELEASE_ABI
+#define UTS_UBUNTU_RELEASE_ABI 0
+#define UBUNTU_VERSION_CODE 0
+#else
+/* Ubuntu does not provide actual release version macro, so we use the kernel
+ * version plus the ABI to generate a unique version code specific to Ubuntu.
+ * In addition, we mask the lower 8 bits of LINUX_VERSION_CODE in order to
+ * ignore differences in sublevel which are not important since we have the
+ * ABI value. Otherwise, it becomes impossible to correlate ABI to version for
+ * ordering checks.
+ */
+#define UBUNTU_VERSION_CODE (((~0xFF & LINUX_VERSION_CODE) << 8) + \
+			     UTS_UBUNTU_RELEASE_ABI)
+
+#if UTS_UBUNTU_RELEASE_ABI > 255
+#error UTS_UBUNTU_RELEASE_ABI is too large...
+#endif /* UTS_UBUNTU_RELEASE_ABI > 255 */
+
+#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,0) )
+/* Our version code scheme does not make sense for non 3.x or newer kernels,
+ * and we have no support in kcompat for this scenario. Thus, treat this as a
+ * non-Ubuntu kernel. Possibly might be better to error here.
+ */
+#define UTS_UBUNTU_RELEASE_ABI 0
+#define UBUNTU_VERSION_CODE 0
+#endif
+
+#endif
+
+/* Note that the 3rd digit is always zero, and will be ignored. This is
+ * because Ubuntu kernels are based on x.y.0-ABI values, and while their linux
+ * version codes are 3 digit, this 3rd digit is superseded by the ABI value.
+ */
+#define UBUNTU_VERSION(a,b,c,d) ((KERNEL_VERSION(a,b,0) << 8) + (d))
+
+/* SuSE version macros are the same as Linux kernel version macro */
+#ifndef SLE_VERSION
+#define SLE_VERSION(a,b,c)	KERNEL_VERSION(a,b,c)
+#endif
+#define SLE_LOCALVERSION(a,b,c)	KERNEL_VERSION(a,b,c)
+
+#ifdef CONFIG_SUSE_KERNEL
+/* Starting since at least SLE 12sp4 and SLE 15, the SUSE kernels have
+ * provided CONFIG_SUSE_VERSION, CONFIG_SUSE_PATCHLEVEL and
+ * CONFIG_SUSE_AUXRELEASE. Use these to generate SLE_VERSION if available.
+ * Only fall back to the manual table otherwise. We expect all future versions
+ * of SLE kernels to include these values, so the table will remain only for
+ * the older releases.
+ */
+#ifdef CONFIG_SUSE_VERSION
+#ifndef CONFIG_SUSE_PATCHLEVEL
+#error "CONFIG_SUSE_VERSION exists but CONFIG_SUSE_PATCHLEVEL is missing"
+#endif
+#ifndef CONFIG_SUSE_AUXRELEASE
+#error "CONFIG_SUSE_VERSION exists but CONFIG_SUSE_AUXRELEASE is missing"
+#endif
+#define SLE_VERSION_CODE SLE_VERSION(CONFIG_SUSE_VERSION, CONFIG_SUSE_PATCHLEVEL, CONFIG_SUSE_AUXRELEASE)
+#else
+/* If we do not have the CONFIG_SUSE_VERSION configuration values, fall back
+ * to the following table for older releases.
+ */
+#if ( LINUX_VERSION_CODE == KERNEL_VERSION(2,6,27) )
+/* SLES11 GA is 2.6.27 based */
+#define SLE_VERSION_CODE SLE_VERSION(11,0,0)
+#elif ( LINUX_VERSION_CODE == KERNEL_VERSION(2,6,32) )
+/* SLES11 SP1 is 2.6.32 based */
+#define SLE_VERSION_CODE SLE_VERSION(11,1,0)
+#elif ( LINUX_VERSION_CODE == KERNEL_VERSION(3,0,13) )
+/* SLES11 SP2 GA is 3.0.13-0.27 */
+#define SLE_VERSION_CODE SLE_VERSION(11,2,0)
+#elif ((LINUX_VERSION_CODE == KERNEL_VERSION(3,0,76)))
+/* SLES11 SP3 GA is 3.0.76-0.11 */
+#define SLE_VERSION_CODE SLE_VERSION(11,3,0)
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(3,0,101))
+  #if (SLE_LOCALVERSION_CODE < SLE_LOCALVERSION(0,8,0))
+  /* some SLES11sp2 update kernels up to 3.0.101-0.7.x */
+  #define SLE_VERSION_CODE SLE_VERSION(11,2,0)
+  #elif (SLE_LOCALVERSION_CODE < SLE_LOCALVERSION(63,0,0))
+  /* most SLES11sp3 update kernels */
+  #define SLE_VERSION_CODE SLE_VERSION(11,3,0)
+  #else
+  /* SLES11 SP4 GA (3.0.101-63) and update kernels 3.0.101-63+ */
+  #define SLE_VERSION_CODE SLE_VERSION(11,4,0)
+  #endif
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(3,12,28))
+/* SLES12 GA is 3.12.28-4
+ * kernel updates 3.12.xx-<33 through 52>[.yy] */
+#define SLE_VERSION_CODE SLE_VERSION(12,0,0)
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(3,12,49))
+/* SLES12 SP1 GA is 3.12.49-11
+ * updates 3.12.xx-60.yy where xx={51..} */
+#define SLE_VERSION_CODE SLE_VERSION(12,1,0)
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,21) && \
+       (LINUX_VERSION_CODE <= KERNEL_VERSION(4,4,59))) || \
+       (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,74) && \
+        LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) && \
+        SLE_LOCALVERSION_CODE >= KERNEL_VERSION(92,0,0) && \
+        SLE_LOCALVERSION_CODE <  KERNEL_VERSION(93,0,0)))
+/* SLES12 SP2 GA is 4.4.21-69.
+ * SLES12 SP2 updates before SLES12 SP3 are: 4.4.{21,38,49,59}
+ * SLES12 SP2 updates after SLES12 SP3 are: 4.4.{74,90,103,114,120}
+ * but they all use a SLE_LOCALVERSION_CODE matching 92.nn.y */
+#define SLE_VERSION_CODE SLE_VERSION(12,2,0)
+#elif ((LINUX_VERSION_CODE == KERNEL_VERSION(4,4,73) || \
+        LINUX_VERSION_CODE == KERNEL_VERSION(4,4,82) || \
+        LINUX_VERSION_CODE == KERNEL_VERSION(4,4,92)) || \
+       (LINUX_VERSION_CODE == KERNEL_VERSION(4,4,103) && \
+       (SLE_LOCALVERSION_CODE == KERNEL_VERSION(6,33,0) || \
+        SLE_LOCALVERSION_CODE == KERNEL_VERSION(6,38,0))) || \
+       (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,114) && \
+        LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) && \
+        SLE_LOCALVERSION_CODE >= KERNEL_VERSION(94,0,0) && \
+        SLE_LOCALVERSION_CODE <  KERNEL_VERSION(95,0,0)) )
+/* SLES12 SP3 GM is 4.4.73-5 and update kernels are 4.4.82-6.3.
+ * SLES12 SP3 updates not conflicting with SP2 are: 4.4.{82,92}
+ * SLES12 SP3 updates conflicting with SP2 are:
+ *   - 4.4.103-6.33.1, 4.4.103-6.38.1
+ *   - 4.4.{114,120}-94.nn.y */
+#define SLE_VERSION_CODE SLE_VERSION(12,3,0)
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(4,12,14) && \
+       (SLE_LOCALVERSION_CODE == KERNEL_VERSION(94,41,0) || \
+       (SLE_LOCALVERSION_CODE >= KERNEL_VERSION(95,0,0) && \
+        SLE_LOCALVERSION_CODE < KERNEL_VERSION(96,0,0))))
+/* SLES12 SP4 GM is 4.12.14-94.41 and update kernel is 4.12.14-95.x. */
+#define SLE_VERSION_CODE SLE_VERSION(12,4,0)
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(4,12,14) && \
+       (SLE_LOCALVERSION_CODE == KERNEL_VERSION(23,0,0) || \
+        SLE_LOCALVERSION_CODE == KERNEL_VERSION(2,0,0) || \
+        SLE_LOCALVERSION_CODE == KERNEL_VERSION(136,0,0) || \
+        (SLE_LOCALVERSION_CODE >= KERNEL_VERSION(25,0,0) && \
+	 SLE_LOCALVERSION_CODE < KERNEL_VERSION(26,0,0)) || \
+	(SLE_LOCALVERSION_CODE >= KERNEL_VERSION(150,0,0) && \
+	 SLE_LOCALVERSION_CODE < KERNEL_VERSION(151,0,0))))
+/* SLES15 Beta1 is 4.12.14-2
+ * SLES15 GM is 4.12.14-23 and update kernel is 4.12.14-{25,136},
+ * and 4.12.14-150.14.
+ */
+#define SLE_VERSION_CODE SLE_VERSION(15,0,0)
+#elif (LINUX_VERSION_CODE == KERNEL_VERSION(4,12,14) && \
+       SLE_LOCALVERSION_CODE >= KERNEL_VERSION(25,23,0))
+/* SLES15 SP1 Beta1 is 4.12.14-25.23 */
+#define SLE_VERSION_CODE SLE_VERSION(15,1,0)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5,3,13))
+/* SLES15 SP2 Beta1 is 5.3.13 */
+#define SLE_VERSION_CODE SLE_VERSION(15,2,0)
+
+/* new SLES kernels must be added here with >= based on kernel
+ * the idea is to order from newest to oldest and just catch all
+ * of them using the >=
+ */
+#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(x,y,z) */
+#endif /* !CONFIG_SUSE_VERSION */
+#endif /* CONFIG_SUSE_KERNEL */
+#ifndef SLE_VERSION_CODE
+#define SLE_VERSION_CODE 0
+#endif /* SLE_VERSION_CODE */
+#ifndef SLE_LOCALVERSION_CODE
+#define SLE_LOCALVERSION_CODE 0
+#endif /* SLE_LOCALVERSION_CODE */
+
+#ifdef CONFIG_SUSE_KERNEL
+#include "kcompat_sles_defs.h"
+#elif (defined(CONFIG_UOS_KERNEL) || defined(CONFIG_EULER_KERNEL))
+#include "kcompat_chn_os.h"
+#endif
+
+/*
+ * ADQ depends on __TC_MQPRIO_MODE_MAX and related kernel code
+ * added around 4.15. Some distributions (e.g. Oracle Linux 7.7)
+ * have done a partial back-port of that to their kernels based
+ * on older mainline kernels that did not include all the necessary
+ * kernel enablement to support ADQ.
+ * Undefine __TC_MQPRIO_MODE_MAX for all OSV distributions with
+ * kernels based on mainline kernels older than 4.15 except for
+ * RHEL, SLES and Ubuntu which are known to have good back-ports.
+ */
+#if (!RHEL_RELEASE_CODE && !SLE_VERSION_CODE && !UBUNTU_VERSION_CODE)
+  #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+  #undef __TC_MQPRIO_MODE_MAX
+  #endif /*  LINUX_VERSION_CODE == KERNEL_VERSION(4,15,0) */
+#endif /* if (NOT RHEL && NOT SLES && NOT UBUNTU) */
+
+#ifdef __KLOCWORK__
+/* The following are not compiled into the binary driver; they are here
+ * only to tune Klocwork scans to workaround false-positive issues.
+ */
+#ifdef ARRAY_SIZE
+#undef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#define memcpy(dest, src, len)	memcpy_s(dest, len, src, len)
+#define memset(dest, ch, len)	memset_s(dest, len, ch, len)
+
+static inline int _kc_test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old;
+	unsigned long flags = 0;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	old = *p;
+	*p = old & ~mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+
+	return (old & mask) != 0;
+}
+#define test_and_clear_bit(nr, addr) _kc_test_and_clear_bit(nr, addr)
+
+static inline int _kc_test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+	unsigned long old;
+	unsigned long flags = 0;
+
+	_atomic_spin_lock_irqsave(p, flags);
+	old = *p;
+	*p = old | mask;
+	_atomic_spin_unlock_irqrestore(p, flags);
+
+	return (old & mask) != 0;
+}
+#define test_and_set_bit(nr, addr) _kc_test_and_set_bit(nr, addr)
+
+#ifdef CONFIG_DYNAMIC_DEBUG
+#undef dev_dbg
+#define dev_dbg(dev, format, arg...) dev_printk(KERN_DEBUG, dev, format, ##arg)
+#undef pr_debug
+#define pr_debug(format, arg...) printk(KERN_DEBUG format, ##arg)
+#endif /* CONFIG_DYNAMIC_DEBUG */
+
+#undef hlist_for_each_entry_safe
+#define hlist_for_each_entry_safe(pos, n, head, member)			     \
+	for (n = NULL, pos = hlist_entry_safe((head)->first, typeof(*(pos)), \
+					      member);			     \
+	     pos;							     \
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#ifdef uninitialized_var
+#undef uninitialized_var
+#define uninitialized_var(x) x = *(&(x))
+#endif
+
+#ifdef WRITE_ONCE
+#undef WRITE_ONCE
+#define WRITE_ONCE(x, val)	((x) = (val))
+#endif /* WRITE_ONCE */
+#endif /* __KLOCWORK__ */
+
+/* Older versions of GCC will trigger -Wformat-nonliteral warnings for const
+ * char * strings. Unfortunately, the implementation of do_trace_printk does
+ * this, in order to add a storage attribute to the memory. This was fixed in
+ * GCC 5.1, but we still use older distributions built with GCC 4.x.
+ *
+ * The string pointer is only passed as a const char * to the __trace_bprintk
+ * function. Since that function has the __printf attribute, it will trigger
+ * the warnings. We can't remove the attribute, so instead we'll use the
+ * __diag macro to disable -Wformat-nonliteral around the call to
+ * __trace_bprintk.
+ */
+#if GCC_VERSION < 50100
+#define __trace_bprintk(ip, fmt, args...) ({		\
+	int err;					\
+	__diag_push();					\
+	__diag(ignored "-Wformat-nonliteral");		\
+	err = __trace_bprintk(ip, fmt, ##args);		\
+	__diag_pop();					\
+	err;						\
+})
+#endif /* GCC_VERSION < 5.1.0 */
+
+/* Newer kernels removed <linux/pci-aspm.h> */
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)) && \
+     (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,3)) && \
+     !(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,3,0)))))
+#define HAVE_PCI_ASPM_H
+#endif
+
+/*****************************************************************************/
+/* 2.4.3 => 2.4.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) )
+
+/**************************************/
+/* PCI DRIVER API */
+
+#ifndef pci_set_dma_mask
+#define pci_set_dma_mask _kc_pci_set_dma_mask
+int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
+#endif
+
+#ifndef pci_request_regions
+#define pci_request_regions _kc_pci_request_regions
+int _kc_pci_request_regions(struct pci_dev *pdev, char *res_name);
+#endif
+
+#ifndef pci_release_regions
+#define pci_release_regions _kc_pci_release_regions
+void _kc_pci_release_regions(struct pci_dev *pdev);
+#endif
+
+/**************************************/
+/* NETWORK DRIVER API */
+
+#ifndef alloc_etherdev
+#define alloc_etherdev _kc_alloc_etherdev
+struct net_device * _kc_alloc_etherdev(int sizeof_priv);
+#endif
+
+#ifndef is_valid_ether_addr
+#define is_valid_ether_addr _kc_is_valid_ether_addr
+int _kc_is_valid_ether_addr(u8 *addr);
+#endif
+
+/**************************************/
+/* MISCELLANEOUS */
+
+#ifndef INIT_TQUEUE
+#define INIT_TQUEUE(_tq, _routine, _data)		\
+	do {						\
+		INIT_LIST_HEAD(&(_tq)->list);		\
+		(_tq)->sync = 0;			\
+		(_tq)->routine = _routine;		\
+		(_tq)->data = _data;			\
+	} while (0)
+#endif
+
+#endif /* 2.4.3 => 2.4.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) )
+/* Generic MII registers. */
+#define MII_BMCR            0x00        /* Basic mode control register */
+#define MII_BMSR            0x01        /* Basic mode status register  */
+#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
+#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
+#define MII_ADVERTISE       0x04        /* Advertisement control reg   */
+#define MII_LPA             0x05        /* Link partner ability reg    */
+#define MII_EXPANSION       0x06        /* Expansion register          */
+/* Basic mode control register. */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+/* Advertisement control register. */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+/* Expansion register for auto-negotiation. */
+#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
+#endif
+
+/*****************************************************************************/
+/* 2.4.6 => 2.4.3 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) )
+
+#ifndef pci_set_power_state
+#define pci_set_power_state _kc_pci_set_power_state
+int _kc_pci_set_power_state(struct pci_dev *dev, int state);
+#endif
+
+#ifndef pci_enable_wake
+#define pci_enable_wake _kc_pci_enable_wake
+int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable);
+#endif
+
+#ifndef pci_disable_device
+#define pci_disable_device _kc_pci_disable_device
+void _kc_pci_disable_device(struct pci_dev *pdev);
+#endif
+
+/* PCI PM entry point syntax changed, so don't support suspend/resume */
+#undef CONFIG_PM
+
+#endif /* 2.4.6 => 2.4.3 */
+
+#ifndef HAVE_PCI_SET_MWI
+#define pci_set_mwi(X) pci_write_config_word(X, \
+			       PCI_COMMAND, adapter->hw.bus.pci_cmd_word | \
+			       PCI_COMMAND_INVALIDATE);
+#define pci_clear_mwi(X) pci_write_config_word(X, \
+			       PCI_COMMAND, adapter->hw.bus.pci_cmd_word & \
+			       ~PCI_COMMAND_INVALIDATE);
+#endif
+
+/*****************************************************************************/
+/* 2.4.10 => 2.4.9 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) )
+
+/**************************************/
+/* MODULE API */
+
+#ifndef MODULE_LICENSE
+	#define MODULE_LICENSE(X)
+#endif
+
+/**************************************/
+/* OTHER */
+
+#undef min
+#define min(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x < _y ? _x : _y; })
+
+#undef max
+#define max(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x > _y ? _x : _y; })
+
+#define min_t(type,x,y) ({ \
+	type _x = (x); \
+	type _y = (y); \
+	_x < _y ? _x : _y; })
+
+#define max_t(type,x,y) ({ \
+	type _x = (x); \
+	type _y = (y); \
+	_x > _y ? _x : _y; })
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+#endif
+
+#ifndef ____cacheline_aligned_in_smp
+#ifdef CONFIG_SMP
+#define ____cacheline_aligned_in_smp ____cacheline_aligned
+#else
+#define ____cacheline_aligned_in_smp
+#endif /* CONFIG_SMP */
+#endif
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,8) )
+int _kc_snprintf(char * buf, size_t size, const char *fmt, ...);
+#define snprintf(buf, size, fmt, args...) _kc_snprintf(buf, size, fmt, ##args)
+int _kc_vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+#define vsnprintf(buf, size, fmt, args) _kc_vsnprintf(buf, size, fmt, args)
+#else /* 2.4.8 => 2.4.9 */
+int snprintf(char * buf, size_t size, const char *fmt, ...);
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+#endif
+#endif /* 2.4.10 -> 2.4.6 */
+
+
+/*****************************************************************************/
+/* 2.4.12 => 2.4.10 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12) )
+#ifndef HAVE_NETIF_MSG
+#define HAVE_NETIF_MSG 1
+enum {
+	NETIF_MSG_DRV		= 0x0001,
+	NETIF_MSG_PROBE		= 0x0002,
+	NETIF_MSG_LINK		= 0x0004,
+	NETIF_MSG_TIMER		= 0x0008,
+	NETIF_MSG_IFDOWN	= 0x0010,
+	NETIF_MSG_IFUP		= 0x0020,
+	NETIF_MSG_RX_ERR	= 0x0040,
+	NETIF_MSG_TX_ERR	= 0x0080,
+	NETIF_MSG_TX_QUEUED	= 0x0100,
+	NETIF_MSG_INTR		= 0x0200,
+	NETIF_MSG_TX_DONE	= 0x0400,
+	NETIF_MSG_RX_STATUS	= 0x0800,
+	NETIF_MSG_PKTDATA	= 0x1000,
+	NETIF_MSG_HW		= 0x2000,
+	NETIF_MSG_WOL		= 0x4000,
+};
+
+#define netif_msg_drv(p)	((p)->msg_enable & NETIF_MSG_DRV)
+#define netif_msg_probe(p)	((p)->msg_enable & NETIF_MSG_PROBE)
+#define netif_msg_link(p)	((p)->msg_enable & NETIF_MSG_LINK)
+#define netif_msg_timer(p)	((p)->msg_enable & NETIF_MSG_TIMER)
+#define netif_msg_ifdown(p)	((p)->msg_enable & NETIF_MSG_IFDOWN)
+#define netif_msg_ifup(p)	((p)->msg_enable & NETIF_MSG_IFUP)
+#define netif_msg_rx_err(p)	((p)->msg_enable & NETIF_MSG_RX_ERR)
+#define netif_msg_tx_err(p)	((p)->msg_enable & NETIF_MSG_TX_ERR)
+#define netif_msg_tx_queued(p)	((p)->msg_enable & NETIF_MSG_TX_QUEUED)
+#define netif_msg_intr(p)	((p)->msg_enable & NETIF_MSG_INTR)
+#define netif_msg_tx_done(p)	((p)->msg_enable & NETIF_MSG_TX_DONE)
+#define netif_msg_rx_status(p)	((p)->msg_enable & NETIF_MSG_RX_STATUS)
+#define netif_msg_pktdata(p)	((p)->msg_enable & NETIF_MSG_PKTDATA)
+#endif /* !HAVE_NETIF_MSG */
+#endif /* 2.4.12 => 2.4.10 */
+
+/*****************************************************************************/
+/* 2.4.13 => 2.4.12 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) )
+
+/**************************************/
+/* PCI DMA MAPPING */
+
+#ifndef virt_to_page
+	#define virt_to_page(v) (mem_map + (virt_to_phys(v) >> PAGE_SHIFT))
+#endif
+
+#ifndef pci_map_page
+#define pci_map_page _kc_pci_map_page
+u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction);
+#endif
+
+#ifndef pci_unmap_page
+#define pci_unmap_page _kc_pci_unmap_page
+void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction);
+#endif
+
+/* pci_set_dma_mask takes dma_addr_t, which is only 32-bits prior to 2.4.13 */
+
+#undef DMA_32BIT_MASK
+#define DMA_32BIT_MASK	0xffffffff
+#undef DMA_64BIT_MASK
+#define DMA_64BIT_MASK	0xffffffff
+
+/**************************************/
+/* OTHER */
+
+#ifndef cpu_relax
+#define cpu_relax()	rep_nop()
+#endif
+
+struct vlan_ethhdr {
+	unsigned char h_dest[ETH_ALEN];
+	unsigned char h_source[ETH_ALEN];
+	unsigned short h_vlan_proto;
+	unsigned short h_vlan_TCI;
+	unsigned short h_vlan_encapsulated_proto;
+};
+#endif /* 2.4.13 => 2.4.12 */
+
+/*****************************************************************************/
+/* 2.4.17 => 2.4.12 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17) )
+
+#ifndef __devexit_p
+	#define __devexit_p(x) &(x)
+#endif
+
+#endif /* 2.4.17 => 2.4.13 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) )
+#define NETIF_MSG_HW	0x2000
+#define NETIF_MSG_WOL	0x4000
+
+#ifndef netif_msg_hw
+#define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
+#endif
+#ifndef netif_msg_wol
+#define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
+#endif
+#endif /* 2.4.18 */
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* 2.4.20 => 2.4.19 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) )
+
+/* we won't support NAPI on less than 2.4.20 */
+#ifdef NAPI
+#undef NAPI
+#endif
+
+#endif /* 2.4.20 => 2.4.19 */
+
+/*****************************************************************************/
+/* 2.4.22 => 2.4.17 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) )
+#define pci_name(x)	((x)->slot_name)
+#define cpu_online(cpuid) test_bit((cpuid), &cpu_online_map)
+
+#ifndef SUPPORTED_10000baseT_Full
+#define SUPPORTED_10000baseT_Full	BIT(12)
+#endif
+#ifndef ADVERTISED_10000baseT_Full
+#define ADVERTISED_10000baseT_Full	BIT(12)
+#endif
+#endif
+
+/*****************************************************************************/
+/* 2.4.22 => 2.4.17 */
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) )
+#endif
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* 2.4.23 => 2.4.22 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) )
+/*****************************************************************************/
+#ifdef NAPI
+#ifndef netif_poll_disable
+#define netif_poll_disable(x) _kc_netif_poll_disable(x)
+static inline void _kc_netif_poll_disable(struct net_device *netdev)
+{
+	while (test_and_set_bit(__LINK_STATE_RX_SCHED, &netdev->state)) {
+		/* No hurry */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+}
+#endif
+#ifndef netif_poll_enable
+#define netif_poll_enable(x) _kc_netif_poll_enable(x)
+static inline void _kc_netif_poll_enable(struct net_device *netdev)
+{
+	clear_bit(__LINK_STATE_RX_SCHED, &netdev->state);
+}
+#endif
+#endif /* NAPI */
+#ifndef netif_tx_disable
+#define netif_tx_disable(x) _kc_netif_tx_disable(x)
+static inline void _kc_netif_tx_disable(struct net_device *dev)
+{
+	spin_lock_bh(&dev->xmit_lock);
+	netif_stop_queue(dev);
+	spin_unlock_bh(&dev->xmit_lock);
+}
+#endif
+#else /* 2.4.23 => 2.4.22 */
+#define HAVE_SCTP
+#endif /* 2.4.23 => 2.4.22 */
+
+/*****************************************************************************/
+/* 2.6.4 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) || \
+    ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) )
+#define ETHTOOL_OPS_COMPAT
+#endif /* 2.6.4 => 2.6.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) )
+#define __user
+#endif /* < 2.4.27 */
+
+/*****************************************************************************/
+/* 2.5.71 => 2.4.x */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71) )
+#define sk_protocol protocol
+#define pci_get_device pci_find_device
+#endif /* 2.5.70 => 2.4.x */
+
+/*****************************************************************************/
+/* < 2.4.27 or 2.6.0 <= 2.6.5 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) || \
+    ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) )
+
+#ifndef netif_msg_init
+#define netif_msg_init _kc_netif_msg_init
+static inline u32 _kc_netif_msg_init(int debug_value, int default_msg_enable_bits)
+{
+	/* use default */
+	if (debug_value < 0 || debug_value >= (sizeof(u32) * 8))
+		return default_msg_enable_bits;
+	if (debug_value == 0) /* no output */
+		return 0;
+	/* set low N bits */
+	return (1 << debug_value) -1;
+}
+#endif
+
+#endif /* < 2.4.27 or 2.6.0 <= 2.6.5 */
+/*****************************************************************************/
+#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) ) || \
+     (( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) && \
+      ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) )))
+#define netdev_priv(x) x->priv
+#endif
+
+/*****************************************************************************/
+/* <= 2.5.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) )
+#include <linux/rtnetlink.h>
+#undef pci_register_driver
+#define pci_register_driver pci_module_init
+
+/*
+ * Most of the dma compat code is copied/modifed from the 2.4.37
+ * /include/linux/libata-compat.h header file
+ */
+/* These definitions mirror those in pci.h, so they can be used
+ * interchangeably with their PCI_ counterparts */
+enum dma_data_direction {
+	DMA_BIDIRECTIONAL = 0,
+	DMA_TO_DEVICE = 1,
+	DMA_FROM_DEVICE = 2,
+	DMA_NONE = 3,
+};
+
+struct device {
+	struct pci_dev pdev;
+};
+
+static inline struct pci_dev *to_pci_dev (struct device *dev)
+{
+	return (struct pci_dev *) dev;
+}
+static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
+{
+	return (struct device *) pdev;
+}
+#define pdev_printk(lvl, pdev, fmt, args...) 	\
+	printk("%s %s: " fmt, lvl, pci_name(pdev), ## args)
+#define dev_err(dev, fmt, args...)            \
+	pdev_printk(KERN_ERR, to_pci_dev(dev), fmt, ## args)
+#define dev_info(dev, fmt, args...)            \
+	pdev_printk(KERN_INFO, to_pci_dev(dev), fmt, ## args)
+#define dev_warn(dev, fmt, args...)            \
+	pdev_printk(KERN_WARNING, to_pci_dev(dev), fmt, ## args)
+#define dev_notice(dev, fmt, args...)            \
+	pdev_printk(KERN_NOTICE, to_pci_dev(dev), fmt, ## args)
+#define dev_dbg(dev, fmt, args...) \
+	pdev_printk(KERN_DEBUG, to_pci_dev(dev), fmt, ## args)
+
+/* NOTE: dangerous! we ignore the 'gfp' argument */
+#define dma_alloc_coherent(dev,sz,dma,gfp) \
+	pci_alloc_consistent(to_pci_dev(dev),(sz),(dma))
+#define dma_free_coherent(dev,sz,addr,dma_addr) \
+	pci_free_consistent(to_pci_dev(dev),(sz),(addr),(dma_addr))
+
+#define dma_map_page(dev,a,b,c,d) \
+	pci_map_page(to_pci_dev(dev),(a),(b),(c),(d))
+#define dma_unmap_page(dev,a,b,c) \
+	pci_unmap_page(to_pci_dev(dev),(a),(b),(c))
+
+#define dma_map_single(dev,a,b,c) \
+	pci_map_single(to_pci_dev(dev),(a),(b),(c))
+#define dma_unmap_single(dev,a,b,c) \
+	pci_unmap_single(to_pci_dev(dev),(a),(b),(c))
+
+#define dma_map_sg(dev, sg, nents, dir) \
+	pci_map_sg(to_pci_dev(dev), (sg), (nents), (dir)
+#define dma_unmap_sg(dev, sg, nents, dir) \
+	pci_unmap_sg(to_pci_dev(dev), (sg), (nents), (dir)
+
+#define dma_sync_single(dev,a,b,c) \
+	pci_dma_sync_single(to_pci_dev(dev),(a),(b),(c))
+
+/* for range just sync everything, that's all the pci API can do */
+#define dma_sync_single_range(dev,addr,off,sz,dir) \
+	pci_dma_sync_single(to_pci_dev(dev),(addr),(off)+(sz),(dir))
+
+#define dma_set_mask(dev,mask) \
+	pci_set_dma_mask(to_pci_dev(dev),(mask))
+
+/* hlist_* code - double linked lists */
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+	next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	__hlist_del(n);
+	n->next = NULL;
+	n->pprev = NULL;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+	h->next = NULL;
+	h->pprev = NULL;
+}
+
+#ifndef might_sleep
+#define might_sleep()
+#endif
+#else
+static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
+{
+	return &pdev->dev;
+}
+#endif /* <= 2.5.0 */
+
+/*****************************************************************************/
+/* 2.5.28 => 2.4.23 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) )
+
+#include <linux/tqueue.h>
+#define work_struct tq_struct
+#undef INIT_WORK
+#define INIT_WORK(a,b) INIT_TQUEUE(a,(void (*)(void *))b,a)
+#undef container_of
+#define container_of list_entry
+#define schedule_work schedule_task
+#define flush_scheduled_work flush_scheduled_tasks
+#define cancel_work_sync(x) flush_scheduled_work()
+
+#endif /* 2.5.28 => 2.4.17 */
+
+/*****************************************************************************/
+/* 2.6.0 => 2.5.28 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+#ifndef read_barrier_depends
+#define read_barrier_depends() rmb()
+#endif
+
+#ifndef rcu_head
+struct __kc_callback_head {
+	struct __kc_callback_head *next;
+	void (*func)(struct callback_head *head);
+};
+#define rcu_head __kc_callback_head
+#endif
+
+#undef get_cpu
+#define get_cpu() smp_processor_id()
+#undef put_cpu
+#define put_cpu() do { } while(0)
+#define MODULE_INFO(version, _version)
+#ifndef CONFIG_T1000_DISABLE_PACKET_SPLIT
+#define CONFIG_T1000_DISABLE_PACKET_SPLIT 1
+#endif
+#ifndef CONFIG_TGB_DISABLE_PACKET_SPLIT
+#define CONFIG_TGB_DISABLE_PACKET_SPLIT 1
+#endif
+#ifndef CONFIG_TGC_DISABLE_PACKET_SPLIT
+#define CONFIG_TGC_DISABLE_PACKET_SPLIT 1
+#endif
+
+#define dma_set_coherent_mask(dev,mask) 1
+
+#undef dev_put
+#define dev_put(dev) __dev_put(dev)
+
+#ifndef skb_fill_page_desc
+#define skb_fill_page_desc _kc_skb_fill_page_desc
+void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size);
+#endif
+
+#undef ALIGN
+#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
+
+#ifndef page_count
+#define page_count(p) atomic_read(&(p)->count)
+#endif
+
+#ifdef MAX_NUMNODES
+#undef MAX_NUMNODES
+#endif
+#define MAX_NUMNODES 1
+
+/* find_first_bit and find_next bit are not defined for most
+ * 2.4 kernels (except for the redhat 2.4.21 kernels
+ */
+#include <linux/bitops.h>
+#define BITOP_WORD(nr)          ((nr) / BITS_PER_LONG)
+#undef find_next_bit
+#define find_next_bit _kc_find_next_bit
+unsigned long _kc_find_next_bit(const unsigned long *addr, unsigned long size,
+				unsigned long offset);
+#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
+
+#ifndef netdev_name
+static inline const char *_kc_netdev_name(const struct net_device *dev)
+{
+	if (strchr(dev->name, '%'))
+		return "(unregistered net_device)";
+	return dev->name;
+}
+#define netdev_name(netdev)	_kc_netdev_name(netdev)
+#endif /* netdev_name */
+
+#ifndef strlcpy
+#define strlcpy _kc_strlcpy
+size_t _kc_strlcpy(char *dest, const char *src, size_t size);
+#endif /* strlcpy */
+
+#ifndef do_div
+#if BITS_PER_LONG == 64
+# define do_div(n,base) ({					\
+	uint32_t __base = (base);				\
+	uint32_t __rem;						\
+	__rem = ((uint64_t)(n)) % __base;			\
+	(n) = ((uint64_t)(n)) / __base;				\
+	__rem;							\
+ })
+#elif BITS_PER_LONG == 32
+uint32_t _kc__div64_32(uint64_t *dividend, uint32_t divisor);
+# define do_div(n,base) ({				\
+	uint32_t __base = (base);			\
+	uint32_t __rem;					\
+	if (likely(((n) >> 32) == 0)) {			\
+		__rem = (uint32_t)(n) % __base;		\
+		(n) = (uint32_t)(n) / __base;		\
+	} else 						\
+		__rem = _kc__div64_32(&(n), __base);	\
+	__rem;						\
+ })
+#else /* BITS_PER_LONG == ?? */
+# error do_div() does not yet support the C64
+#endif /* BITS_PER_LONG */
+#endif /* do_div */
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC	1000000000L
+#endif
+
+#undef HAVE_I2C_SUPPORT
+#else /* 2.6.0 */
+
+#endif /* 2.6.0 => 2.5.28 */
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) )
+#define dma_pool pci_pool
+#define dma_pool_destroy pci_pool_destroy
+#define dma_pool_alloc pci_pool_alloc
+#define dma_pool_free pci_pool_free
+
+#define dma_pool_create(name,dev,size,align,allocation) \
+       pci_pool_create((name),to_pci_dev(dev),(size),(align),(allocation))
+#endif /* < 2.6.3 */
+
+/*****************************************************************************/
+/* 2.6.4 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) )
+#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#endif /* 2.6.4 => 2.6.0 */
+
+/*****************************************************************************/
+/* 2.6.5 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) )
+#define dma_sync_single_for_cpu		dma_sync_single
+#define dma_sync_single_for_device	dma_sync_single
+#define dma_sync_single_range_for_cpu		dma_sync_single_range
+#define dma_sync_single_range_for_device	dma_sync_single_range
+#ifndef pci_dma_mapping_error
+#define pci_dma_mapping_error _kc_pci_dma_mapping_error
+static inline int _kc_pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_addr == 0;
+}
+#endif
+#endif /* 2.6.5 => 2.6.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) )
+int _kc_scnprintf(char * buf, size_t size, const char *fmt, ...);
+#define scnprintf(buf, size, fmt, args...) _kc_scnprintf(buf, size, fmt, ##args)
+#endif /* < 2.6.4 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) )
+/* taken from 2.6 include/linux/bitmap.h */
+#undef bitmap_zero
+#define bitmap_zero _kc_bitmap_zero
+static inline void _kc_bitmap_zero(unsigned long *dst, int nbits)
+{
+        if (nbits <= BITS_PER_LONG)
+                *dst = 0UL;
+        else {
+                int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+                memset(dst, 0, len);
+        }
+}
+#define page_to_nid(x) 0
+
+#endif /* < 2.6.6 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) )
+#undef if_mii
+#define if_mii _kc_if_mii
+static inline struct mii_ioctl_data *_kc_if_mii(struct ifreq *rq)
+{
+	return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+
+#ifndef __force
+#define __force
+#endif
+#endif /* < 2.6.7 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) )
+#ifndef PCI_EXP_DEVCTL
+#define PCI_EXP_DEVCTL 8
+#endif
+#ifndef PCI_EXP_DEVCTL_CERE
+#define PCI_EXP_DEVCTL_CERE 0x0001
+#endif
+#define PCI_EXP_FLAGS		2	/* Capabilities register */
+#define PCI_EXP_FLAGS_VERS	0x000f	/* Capability version */
+#define PCI_EXP_FLAGS_TYPE	0x00f0	/* Device/Port type */
+#define  PCI_EXP_TYPE_ENDPOINT	0x0	/* Express Endpoint */
+#define  PCI_EXP_TYPE_LEG_END	0x1	/* Legacy Endpoint */
+#define  PCI_EXP_TYPE_ROOT_PORT 0x4	/* Root Port */
+#define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
+#define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
+#define PCI_EXP_DEVCAP		4	/* Device capabilities */
+#define PCI_EXP_DEVSTA		10	/* Device Status */
+#define msleep(x)	do { set_current_state(TASK_UNINTERRUPTIBLE); \
+				schedule_timeout((x * HZ)/1000 + 2); \
+			} while (0)
+
+#endif /* < 2.6.8 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+#include <net/dsfield.h>
+#define __iomem
+
+#ifndef kcalloc
+#define kcalloc(n, size, flags) _kc_kzalloc(((n) * (size)), flags)
+void *_kc_kzalloc(size_t size, int flags);
+#endif
+#define MSEC_PER_SEC    1000L
+static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+	return (MSEC_PER_SEC / HZ) * j;
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
+#else
+	return (j * MSEC_PER_SEC) / HZ;
+#endif
+}
+static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m)
+{
+	if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET))
+		return MAX_JIFFY_OFFSET;
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+	return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+	return m * (HZ / MSEC_PER_SEC);
+#else
+	return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
+#endif
+}
+
+#define msleep_interruptible _kc_msleep_interruptible
+static inline unsigned long _kc_msleep_interruptible(unsigned int msecs)
+{
+	unsigned long timeout = _kc_msecs_to_jiffies(msecs) + 1;
+
+	while (timeout && !signal_pending(current)) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+	return _kc_jiffies_to_msecs(timeout);
+}
+
+/* Basic mode control register. */
+#define BMCR_SPEED1000		0x0040  /* MSB of Speed (1000)         */
+
+#ifndef __le16
+#define __le16 u16
+#endif
+#ifndef __le32
+#define __le32 u32
+#endif
+#ifndef __le64
+#define __le64 u64
+#endif
+#ifndef __be16
+#define __be16 u16
+#endif
+#ifndef __be32
+#define __be32 u32
+#endif
+#ifndef __be64
+#define __be64 u64
+#endif
+
+static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
+{
+	return (struct vlan_ethhdr *)skb->mac.raw;
+}
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY		BIT(0)
+#define WAKE_UCAST		BIT(1)
+#define WAKE_MCAST		BIT(2)
+#define WAKE_BCAST		BIT(3)
+#define WAKE_ARP		BIT(4)
+#define WAKE_MAGIC		BIT(5)
+#define WAKE_MAGICSECURE	BIT(6) /* only meaningful if WAKE_MAGIC */
+
+#define skb_header_pointer _kc_skb_header_pointer
+static inline void *_kc_skb_header_pointer(const struct sk_buff *skb,
+					    int offset, int len, void *buffer)
+{
+	int hlen = skb_headlen(skb);
+
+	if (hlen - offset >= len)
+		return skb->data + offset;
+
+#ifdef MAX_SKB_FRAGS
+	if (skb_copy_bits(skb, offset, buffer, len) < 0)
+		return NULL;
+
+	return buffer;
+#else
+	return NULL;
+#endif
+
+#ifndef NETDEV_TX_OK
+#define NETDEV_TX_OK 0
+#endif
+#ifndef NETDEV_TX_BUSY
+#define NETDEV_TX_BUSY 1
+#endif
+#ifndef NETDEV_TX_LOCKED
+#define NETDEV_TX_LOCKED -1
+#endif
+}
+
+#ifndef __bitwise
+#define __bitwise
+#endif
+#endif /* < 2.6.9 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) )
+#ifdef module_param_array_named
+#undef module_param_array_named
+#define module_param_array_named(name, array, type, nump, perm)          \
+	static struct kparam_array __param_arr_##name                    \
+	= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type, \
+	    sizeof(array[0]), array };                                   \
+	module_param_call(name, param_array_set, param_array_get,        \
+			  &__param_arr_##name, perm)
+#endif /* module_param_array_named */
+/*
+ * num_online is broken for all < 2.6.10 kernels.  This is needed to support
+ * Node module parameter of ixgbe.
+ */
+#undef num_online_nodes
+#define num_online_nodes(n) 1
+extern DECLARE_BITMAP(_kcompat_node_online_map, MAX_NUMNODES);
+#undef node_online_map
+#define node_online_map _kcompat_node_online_map
+#define pci_get_class pci_find_class
+#endif /* < 2.6.10 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
+#define PCI_D0      0
+#define PCI_D1      1
+#define PCI_D2      2
+#define PCI_D3hot   3
+#define PCI_D3cold  4
+typedef int pci_power_t;
+#define pci_choose_state(pdev,state) state
+#define PMSG_SUSPEND 3
+#define PCI_EXP_LNKCTL	16
+
+#undef NETIF_F_LLTX
+
+#ifndef ARCH_HAS_PREFETCH
+#define prefetch(X)
+#endif
+
+#ifndef NET_IP_ALIGN
+#define NET_IP_ALIGN 2
+#endif
+
+#define KC_USEC_PER_SEC	1000000L
+#define usecs_to_jiffies _kc_usecs_to_jiffies
+static inline unsigned int _kc_jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ)
+	return (KC_USEC_PER_SEC / HZ) * j;
+#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC)
+	return (j + (HZ / KC_USEC_PER_SEC) - 1)/(HZ / KC_USEC_PER_SEC);
+#else
+	return (j * KC_USEC_PER_SEC) / HZ;
+#endif
+}
+static inline unsigned long _kc_usecs_to_jiffies(const unsigned int m)
+{
+	if (m > _kc_jiffies_to_usecs(MAX_JIFFY_OFFSET))
+		return MAX_JIFFY_OFFSET;
+#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ)
+	return (m + (KC_USEC_PER_SEC / HZ) - 1) / (KC_USEC_PER_SEC / HZ);
+#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC)
+	return m * (HZ / KC_USEC_PER_SEC);
+#else
+	return (m * HZ + KC_USEC_PER_SEC - 1) / KC_USEC_PER_SEC;
+#endif
+}
+
+#define PCI_EXP_LNKCAP		12	/* Link Capabilities */
+#define PCI_EXP_LNKSTA		18	/* Link Status */
+#define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
+#define PCI_EXP_SLTCTL		24	/* Slot Control */
+#define PCI_EXP_SLTSTA		26	/* Slot Status */
+#define PCI_EXP_RTCTL		28	/* Root Control */
+#define PCI_EXP_RTCAP		30	/* Root Capabilities */
+#define PCI_EXP_RTSTA		32	/* Root Status */
+#endif /* < 2.6.11 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) )
+#include <linux/reboot.h>
+#define USE_REBOOT_NOTIFIER
+
+/* Generic MII registers. */
+#define MII_CTRL1000        0x09        /* 1000BASE-T control          */
+#define MII_STAT1000        0x0a        /* 1000BASE-T status           */
+/* Advertisement control register. */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymmetric pause     */
+/* Link partner ability register. */
+#define LPA_PAUSE_CAP		0x0400	/* Can pause                   */
+#define LPA_PAUSE_ASYM		0x0800	/* Can pause asymetrically     */
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF	0x0100  /* Advertise 1000BASE-T half duplex */
+/* 1000BASE-T Status register */
+#define LPA_1000LOCALRXOK	0x2000	/* Link partner local receiver status */
+#define LPA_1000REMRXOK		0x1000	/* Link partner remote receiver status */
+
+#ifndef is_zero_ether_addr
+#define is_zero_ether_addr _kc_is_zero_ether_addr
+static inline int _kc_is_zero_ether_addr(const u8 *addr)
+{
+	return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
+}
+#endif /* is_zero_ether_addr */
+#ifndef is_multicast_ether_addr
+#define is_multicast_ether_addr _kc_is_multicast_ether_addr
+static inline int _kc_is_multicast_ether_addr(const u8 *addr)
+{
+	return addr[0] & 0x01;
+}
+#endif /* is_multicast_ether_addr */
+#endif /* < 2.6.12 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) )
+#ifndef kstrdup
+#define kstrdup _kc_kstrdup
+char *_kc_kstrdup(const char *s, unsigned int gfp);
+#endif
+#endif /* < 2.6.13 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) )
+#define pm_message_t u32
+#ifndef kzalloc
+#define kzalloc _kc_kzalloc
+void *_kc_kzalloc(size_t size, int flags);
+#endif
+
+/* Generic MII registers. */
+#define MII_ESTATUS	    0x0f	/* Extended Status */
+/* Basic mode status register. */
+#define BMSR_ESTATEN		0x0100	/* Extended Status in R15 */
+/* Extended status register. */
+#define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */
+#define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */
+
+#define SUPPORTED_Pause	        BIT(13)
+#define SUPPORTED_Asym_Pause	BIT(14)
+#define ADVERTISED_Pause	BIT(13)
+#define ADVERTISED_Asym_Pause	BIT(14)
+
+#if (!(RHEL_RELEASE_CODE && \
+       (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(4,3)) && \
+       (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0))))
+#if ((LINUX_VERSION_CODE == KERNEL_VERSION(2,6,9)) && !defined(gfp_t))
+#define gfp_t unsigned
+#else
+typedef unsigned gfp_t;
+#endif
+#endif /* !RHEL4.3->RHEL5.0 */
+
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) )
+#ifdef CONFIG_X86_64
+#define dma_sync_single_range_for_cpu(dev, addr, off, sz, dir)       \
+	dma_sync_single_for_cpu((dev), (addr), (off) + (sz), (dir))
+#define dma_sync_single_range_for_device(dev, addr, off, sz, dir)    \
+	dma_sync_single_for_device((dev), (addr), (off) + (sz), (dir))
+#endif
+#endif
+#endif /* < 2.6.14 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) )
+#ifndef kfree_rcu
+/* this is placed here due to a lack of rcu_barrier in previous kernels */
+#define kfree_rcu(_ptr, _offset) kfree(_ptr)
+#endif /* kfree_rcu */
+#ifndef vmalloc_node
+#define vmalloc_node(a,b) vmalloc(a)
+#endif /* vmalloc_node*/
+
+#define setup_timer(_timer, _function, _data) \
+do { \
+	(_timer)->function = _function; \
+	(_timer)->data = _data; \
+	init_timer(_timer); \
+} while (0)
+#ifndef device_can_wakeup
+#define device_can_wakeup(dev)	(1)
+#endif
+#ifndef device_set_wakeup_enable
+#define device_set_wakeup_enable(dev, val)	do{}while(0)
+#endif
+#ifndef device_init_wakeup
+#define device_init_wakeup(dev,val) do {} while (0)
+#endif
+static inline unsigned _kc_compare_ether_addr(const u8 *addr1, const u8 *addr2)
+{
+	const u16 *a = (const u16 *) addr1;
+	const u16 *b = (const u16 *) addr2;
+
+	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+#undef compare_ether_addr
+#define compare_ether_addr(addr1, addr2) _kc_compare_ether_addr(addr1, addr2)
+#endif /* < 2.6.15 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) )
+#undef DEFINE_MUTEX
+#define DEFINE_MUTEX(x)	DECLARE_MUTEX(x)
+#define mutex_lock(x)	down_interruptible(x)
+#define mutex_unlock(x)	up(x)
+
+#ifndef ____cacheline_internodealigned_in_smp
+#ifdef CONFIG_SMP
+#define ____cacheline_internodealigned_in_smp ____cacheline_aligned_in_smp
+#else
+#define ____cacheline_internodealigned_in_smp
+#endif /* CONFIG_SMP */
+#endif /* ____cacheline_internodealigned_in_smp */
+#undef HAVE_PCI_ERS
+#else /* 2.6.16 and above */
+#undef HAVE_PCI_ERS
+#define HAVE_PCI_ERS
+#if ( SLE_VERSION_CODE && SLE_VERSION_CODE == SLE_VERSION(10,4,0) )
+#ifdef device_can_wakeup
+#undef device_can_wakeup
+#endif /* device_can_wakeup */
+#define device_can_wakeup(dev) 1
+#endif /* SLE_VERSION(10,4,0) */
+#endif /* < 2.6.16 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) )
+#ifndef dev_notice
+#define dev_notice(dev, fmt, args...)            \
+	dev_printk(KERN_NOTICE, dev, fmt, ## args)
+#endif
+
+#ifndef first_online_node
+#define first_online_node 0
+#endif
+#ifndef NET_SKB_PAD
+#define NET_SKB_PAD 16
+#endif
+#endif /* < 2.6.17 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) )
+
+#ifndef IRQ_HANDLED
+#define irqreturn_t void
+#define IRQ_HANDLED
+#define IRQ_NONE
+#endif
+
+#ifndef IRQF_PROBE_SHARED
+#ifdef SA_PROBEIRQ
+#define IRQF_PROBE_SHARED SA_PROBEIRQ
+#else
+#define IRQF_PROBE_SHARED 0
+#endif
+#endif
+
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef skb_is_gso
+#ifdef NETIF_F_TSO
+#define skb_is_gso _kc_skb_is_gso
+static inline int _kc_skb_is_gso(const struct sk_buff *skb)
+{
+	return skb_shinfo(skb)->gso_size;
+}
+#else
+#define skb_is_gso(a) 0
+#endif
+#endif
+
+#ifndef resource_size_t
+#define resource_size_t unsigned long
+#endif
+
+#ifdef skb_pad
+#undef skb_pad
+#endif
+#define skb_pad(x,y) _kc_skb_pad(x, y)
+int _kc_skb_pad(struct sk_buff *skb, int pad);
+#ifdef skb_padto
+#undef skb_padto
+#endif
+#define skb_padto(x,y) _kc_skb_padto(x, y)
+static inline int _kc_skb_padto(struct sk_buff *skb, unsigned int len)
+{
+	unsigned int size = skb->len;
+	if(likely(size >= len))
+		return 0;
+	return _kc_skb_pad(skb, len - size);
+}
+
+#ifndef DECLARE_PCI_UNMAP_ADDR
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
+	dma_addr_t ADDR_NAME
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
+	u32 LEN_NAME
+#define pci_unmap_addr(PTR, ADDR_NAME) \
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) \
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
+	(((PTR)->LEN_NAME) = (VAL))
+#endif /* DECLARE_PCI_UNMAP_ADDR */
+#endif /* < 2.6.18 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) )
+enum pcie_link_width {
+	PCIE_LNK_WIDTH_RESRV    = 0x00,
+	PCIE_LNK_X1             = 0x01,
+	PCIE_LNK_X2             = 0x02,
+	PCIE_LNK_X4             = 0x04,
+	PCIE_LNK_X8             = 0x08,
+	PCIE_LNK_X12            = 0x0C,
+	PCIE_LNK_X16            = 0x10,
+	PCIE_LNK_X32            = 0x20,
+	PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,0)))
+#define i_private u.generic_ip
+#endif /* >= RHEL 5.0 */
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+#ifndef __ALIGN_MASK
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+#endif
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) )
+#if (!((RHEL_RELEASE_CODE && \
+        ((RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(4,4) && \
+          RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0)) || \
+         (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,0))))))
+typedef irqreturn_t (*irq_handler_t)(int, void*, struct pt_regs *);
+#endif
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,0))
+#undef CONFIG_INET_LRO
+#undef CONFIG_INET_LRO_MODULE
+#undef CONFIG_FCOE
+#undef CONFIG_FCOE_MODULE
+#endif
+typedef irqreturn_t (*new_handler_t)(int, void*);
+static inline irqreturn_t _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id)
+#else /* 2.4.x */
+typedef void (*irq_handler_t)(int, void*, struct pt_regs *);
+typedef void (*new_handler_t)(int, void*);
+static inline int _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id)
+#endif /* >= 2.5.x */
+{
+	irq_handler_t new_handler = (irq_handler_t) handler;
+	return request_irq(irq, new_handler, flags, devname, dev_id);
+}
+
+#undef request_irq
+#define request_irq(irq, handler, flags, devname, dev_id) _kc_request_irq((irq), (handler), (flags), (devname), (dev_id))
+
+#define irq_handler_t new_handler_t
+
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) )
+#ifndef skb_checksum_help
+static inline int __kc_skb_checksum_help(struct sk_buff *skb)
+{
+	return skb_checksum_help(skb, 0);
+}
+#define skb_checksum_help(skb) __kc_skb_checksum_help((skb))
+#endif
+#endif /* < 2.6.19 && >= 2.6.11 */
+
+/* pci_restore_state and pci_save_state handles MSI/PCIE from 2.6.19 */
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,4)))
+#define PCIE_CONFIG_SPACE_LEN 256
+#define PCI_CONFIG_SPACE_LEN 64
+#define PCIE_LINK_STATUS 0x12
+#define pci_config_space_ich8lan() do {} while(0)
+#undef pci_save_state
+int _kc_pci_save_state(struct pci_dev *);
+#define pci_save_state(pdev) _kc_pci_save_state(pdev)
+#undef pci_restore_state
+void _kc_pci_restore_state(struct pci_dev *);
+#define pci_restore_state(pdev) _kc_pci_restore_state(pdev)
+#endif /* !(RHEL_RELEASE_CODE >= RHEL 5.4) */
+
+#ifdef HAVE_PCI_ERS
+#undef free_netdev
+void _kc_free_netdev(struct net_device *);
+#define free_netdev(netdev) _kc_free_netdev(netdev)
+#endif
+static inline int pci_enable_pcie_error_reporting(struct pci_dev __always_unused *dev)
+{
+	return 0;
+}
+#define pci_disable_pcie_error_reporting(dev) do {} while (0)
+#define pci_cleanup_aer_uncorrect_error_status(dev) do {} while (0)
+
+void *_kc_kmemdup(const void *src, size_t len, unsigned gfp);
+#define kmemdup(src, len, gfp) _kc_kmemdup(src, len, gfp)
+#ifndef bool
+#define bool _Bool
+#define true 1
+#define false 0
+#endif
+#else /* 2.6.19 */
+#include <linux/aer.h>
+#include <linux/pci_hotplug.h>
+
+#define NEW_SKB_CSUM_HELP
+#endif /* < 2.6.19 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) )
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) )
+#undef INIT_WORK
+#define INIT_WORK(_work, _func) \
+do { \
+	INIT_LIST_HEAD(&(_work)->entry); \
+	(_work)->pending = 0; \
+	(_work)->func = (void (*)(void *))_func; \
+	(_work)->data = _work; \
+	init_timer(&(_work)->timer); \
+} while (0)
+#endif
+
+#ifndef PCI_VDEVICE
+#define PCI_VDEVICE(ven, dev)        \
+	PCI_VENDOR_ID_##ven, (dev),  \
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0
+#endif
+
+#ifndef PCI_VENDOR_ID_WANGXUN
+#define PCI_VENDOR_ID_WANGXUN 0x8088
+#endif
+
+#ifndef round_jiffies
+#define round_jiffies(x) x
+#endif
+
+#define csum_offset csum
+
+#define HAVE_EARLY_VMALLOC_NODE
+#define dev_to_node(dev) -1
+#undef set_dev_node
+/* remove compiler warning with b=b, for unused variable */
+#define set_dev_node(a, b) do { (b) = (b); } while(0)
+
+#if (!(RHEL_RELEASE_CODE && \
+       (((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(4,7)) && \
+         (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0))) || \
+        (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,6)))) && \
+     !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(10,2,0)))
+typedef __u16 __bitwise __sum16;
+typedef __u32 __bitwise __wsum;
+#endif
+
+#if (!(RHEL_RELEASE_CODE && \
+       (((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(4,7)) && \
+         (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0))) || \
+        (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,4)))) && \
+     !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(10,2,0)))
+static inline __wsum csum_unfold(__sum16 n)
+{
+	return (__force __wsum)n;
+}
+#endif
+
+#else /* < 2.6.20 */
+#define HAVE_DEVICE_NUMA_NODE
+#endif /* < 2.6.20 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) )
+#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define NETDEV_CLASS_DEV
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,5)))
+#define vlan_group_get_device(vg, id) (vg->vlan_devices[id])
+#define vlan_group_set_device(vg, id, dev)		\
+	do {						\
+		if (vg) vg->vlan_devices[id] = dev;	\
+	} while (0)
+#endif /* !(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,5)) */
+#define pci_channel_offline(pdev) (pdev->error_state && \
+	pdev->error_state != pci_channel_io_normal)
+#define pci_request_selected_regions(pdev, bars, name) \
+        pci_request_regions(pdev, name)
+#define pci_release_selected_regions(pdev, bars) pci_release_regions(pdev);
+
+#ifndef __aligned
+#define __aligned(x)			__attribute__((aligned(x)))
+#endif
+
+struct pci_dev *_kc_netdev_to_pdev(struct net_device *netdev);
+#define netdev_to_dev(netdev)	\
+	pci_dev_to_dev(_kc_netdev_to_pdev(netdev))
+#define devm_kzalloc(dev, size, flags) kzalloc(size, flags)
+#define devm_kfree(dev, p) kfree(p)
+#else /* 2.6.21 */
+static inline struct device *netdev_to_dev(struct net_device *netdev)
+{
+	return &netdev->dev;
+}
+
+#endif /* < 2.6.21 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) )
+#define tcp_hdr(skb) (skb->h.th)
+#define tcp_hdrlen(skb) (skb->h.th->doff << 2)
+#define skb_transport_offset(skb) (skb->h.raw - skb->data)
+#define skb_transport_header(skb) (skb->h.raw)
+#define ipv6_hdr(skb) (skb->nh.ipv6h)
+#define ip_hdr(skb) (skb->nh.iph)
+#define skb_network_offset(skb) (skb->nh.raw - skb->data)
+#define skb_network_header(skb) (skb->nh.raw)
+#define skb_tail_pointer(skb) skb->tail
+#define skb_reset_tail_pointer(skb) \
+	do { \
+		skb->tail = skb->data; \
+	} while (0)
+#define skb_set_tail_pointer(skb, offset) \
+	do { \
+		skb->tail = skb->data + offset; \
+	} while (0)
+#define skb_copy_to_linear_data(skb, from, len) \
+				memcpy(skb->data, from, len)
+#define skb_copy_to_linear_data_offset(skb, offset, from, len) \
+				memcpy(skb->data + offset, from, len)
+#define skb_network_header_len(skb) (skb->h.raw - skb->nh.raw)
+#define pci_register_driver pci_module_init
+#define skb_mac_header(skb) skb->mac.raw
+
+#ifdef NETIF_F_MULTI_QUEUE
+#ifndef alloc_etherdev_mq
+#define alloc_etherdev_mq(_a, _b) alloc_etherdev(_a)
+#endif
+#endif /* NETIF_F_MULTI_QUEUE */
+
+#ifndef ETH_FCS_LEN
+#define ETH_FCS_LEN 4
+#endif
+#define cancel_work_sync(x) flush_scheduled_work()
+#ifndef udp_hdr
+#define udp_hdr _udp_hdr
+static inline struct udphdr *_udp_hdr(const struct sk_buff *skb)
+{
+	return (struct udphdr *)skb_transport_header(skb);
+}
+#endif
+
+#ifdef cpu_to_be16
+#undef cpu_to_be16
+#endif
+#define cpu_to_be16(x) __constant_htons(x)
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,1)))
+enum {
+	DUMP_PREFIX_NONE,
+	DUMP_PREFIX_ADDRESS,
+	DUMP_PREFIX_OFFSET
+};
+#endif /* !(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,1)) */
+#ifndef hex_asc
+#define hex_asc(x)	"0123456789abcdef"[x]
+#endif
+#include <linux/ctype.h>
+void _kc_print_hex_dump(const char *level, const char *prefix_str,
+			int prefix_type, int rowsize, int groupsize,
+			const void *buf, size_t len, bool ascii);
+#define print_hex_dump(lvl, s, t, r, g, b, l, a) \
+		_kc_print_hex_dump(lvl, s, t, r, g, b, l, a)
+#ifndef ADVERTISED_2500baseX_Full
+#define ADVERTISED_2500baseX_Full BIT(15)
+#endif
+#ifndef SUPPORTED_2500baseX_Full
+#define SUPPORTED_2500baseX_Full BIT(15)
+#endif
+
+#ifndef ETH_P_PAUSE
+#define ETH_P_PAUSE 0x8808
+#endif
+
+static inline int compound_order(struct page *page)
+{
+	return 0;
+}
+
+#define __must_be_array(a) 0
+
+#ifndef SKB_WITH_OVERHEAD
+#define SKB_WITH_OVERHEAD(X) \
+	((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+#endif
+#else /* 2.6.22 */
+#define ETH_TYPE_TRANS_SETS_DEV
+#define HAVE_NETDEV_STATS_IN_NETDEV
+#endif /* < 2.6.22 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) )
+#undef SET_MODULE_OWNER
+#define SET_MODULE_OWNER(dev) do { } while (0)
+#endif /* > 2.6.22 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) )
+#define netif_subqueue_stopped(_a, _b) 0
+#ifndef PTR_ALIGN
+#define PTR_ALIGN(p, a)         ((typeof(p))ALIGN((unsigned long)(p), (a)))
+#endif
+
+#ifndef CONFIG_PM_SLEEP
+#define CONFIG_PM_SLEEP	CONFIG_PM
+#endif
+
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) )
+#define HAVE_ETHTOOL_GET_PERM_ADDR
+#endif /* 2.6.14 through 2.6.22 */
+
+static inline int __kc_skb_cow_head(struct sk_buff *skb, unsigned int headroom)
+{
+	int delta = 0;
+
+	if (headroom > (skb->data - skb->head))
+		delta = headroom - (skb->data - skb->head);
+
+	if (delta || skb_header_cloned(skb))
+		return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
+					GFP_ATOMIC);
+	return 0;
+}
+#define skb_cow_head(s, h) __kc_skb_cow_head((s), (h))
+#endif /* < 2.6.23 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) )
+#ifndef ETH_FLAG_LRO
+#define ETH_FLAG_LRO NETIF_F_LRO
+#endif
+
+#ifndef ACCESS_ONCE
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#endif
+
+/* if GRO is supported then the napi struct must already exist */
+#ifndef NETIF_F_GRO
+/* NAPI API changes in 2.6.24 break everything */
+struct napi_struct {
+	/* used to look up the real NAPI polling routine */
+	int (*poll)(struct napi_struct *, int);
+	struct net_device *dev;
+	int weight;
+};
+#endif
+
+#ifdef NAPI
+int __kc_adapter_clean(struct net_device *, int *);
+/* The following definitions are multi-queue aware, and thus we have a driver
+ * define list which determines which drivers support multiple queues, and
+ * thus need these stronger defines. If a driver does not support multi-queue
+ * functionality, you don't need to add it to this list.
+ */
+struct net_device *napi_to_poll_dev(const struct napi_struct *napi);
+
+static inline void __kc_mq_netif_napi_add(struct net_device *dev, struct napi_struct *napi,
+					  int (*poll)(struct napi_struct *, int), int weight)
+{
+	struct net_device *poll_dev = napi_to_poll_dev(napi);
+	poll_dev->poll = __kc_adapter_clean;
+	poll_dev->priv = napi;
+	poll_dev->weight = weight;
+	set_bit(__LINK_STATE_RX_SCHED, &poll_dev->state);
+	set_bit(__LINK_STATE_START, &poll_dev->state);
+	dev_hold(poll_dev);
+	napi->poll = poll;
+	napi->weight = weight;
+	napi->dev = dev;
+}
+#define netif_napi_add __kc_mq_netif_napi_add
+
+static inline void __kc_mq_netif_napi_del(struct napi_struct *napi)
+{
+	struct net_device *poll_dev = napi_to_poll_dev(napi);
+	WARN_ON(!test_bit(__LINK_STATE_RX_SCHED, &poll_dev->state));
+	dev_put(poll_dev);
+	memset(poll_dev, 0, sizeof(struct net_device));
+}
+
+#define netif_napi_del __kc_mq_netif_napi_del
+
+static inline bool __kc_mq_napi_schedule_prep(struct napi_struct *napi)
+{
+	return netif_running(napi->dev) &&
+		netif_rx_schedule_prep(napi_to_poll_dev(napi));
+}
+#define napi_schedule_prep __kc_mq_napi_schedule_prep
+
+static inline void __kc_mq_napi_schedule(struct napi_struct *napi)
+{
+	if (napi_schedule_prep(napi))
+		__netif_rx_schedule(napi_to_poll_dev(napi));
+}
+#define napi_schedule __kc_mq_napi_schedule
+
+#define napi_enable(_napi) netif_poll_enable(napi_to_poll_dev(_napi))
+#define napi_disable(_napi) netif_poll_disable(napi_to_poll_dev(_napi))
+#ifdef CONFIG_SMP
+static inline void napi_synchronize(const struct napi_struct *n)
+{
+	struct net_device *dev = napi_to_poll_dev(n);
+
+	while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+		/* No hurry. */
+		msleep(1);
+	}
+}
+#else
+#define napi_synchronize(n)	barrier()
+#endif /* CONFIG_SMP */
+#define __napi_schedule(_napi) __netif_rx_schedule(napi_to_poll_dev(_napi))
+static inline void _kc_napi_complete(struct napi_struct *napi)
+{
+#ifdef NETIF_F_GRO
+	napi_gro_flush(napi);
+#endif
+	netif_rx_complete(napi_to_poll_dev(napi));
+}
+#define napi_complete _kc_napi_complete
+#else /* NAPI */
+
+/* The following definitions are only used if we don't support NAPI at all. */
+
+static inline __kc_netif_napi_add(struct net_device *dev, struct napi_struct *napi,
+				  int (*poll)(struct napi_struct *, int), int weight)
+{
+	dev->poll = poll;
+	dev->weight = weight;
+	napi->poll = poll;
+	napi->weight = weight;
+	napi->dev = dev;
+}
+#define netif_napi_del(_a) do {} while (0)
+#endif /* NAPI */
+
+#undef dev_get_by_name
+#define dev_get_by_name(_a, _b) dev_get_by_name(_b)
+#define __netif_subqueue_stopped(_a, _b) netif_subqueue_stopped(_a, _b)
+#ifndef DMA_BIT_MASK
+#define DMA_BIT_MASK(n)	(((n) == 64) ? DMA_64BIT_MASK : ((1ULL<<(n))-1))
+#endif
+
+#ifdef NETIF_F_TSO6
+#define skb_is_gso_v6 _kc_skb_is_gso_v6
+static inline int _kc_skb_is_gso_v6(const struct sk_buff *skb)
+{
+	return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
+}
+#endif /* NETIF_F_TSO6 */
+
+#ifndef KERN_CONT
+#define KERN_CONT	""
+#endif
+#ifndef pr_err
+#define pr_err(fmt, arg...) \
+	printk(KERN_ERR fmt, ##arg)
+#endif
+
+#ifndef rounddown_pow_of_two
+#define rounddown_pow_of_two(n) \
+	__builtin_constant_p(n) ? ( \
+		(n == 1) ? 0 : \
+		(1UL << ilog2(n))) : \
+		(1UL << (fls_long(n) - 1))
+#endif
+
+#else /* < 2.6.24 */
+#define HAVE_ETHTOOL_GET_SSET_COUNT
+#define HAVE_NETDEV_NAPI_LIST
+#endif /* < 2.6.24 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) )
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) )
+#define INCLUDE_PM_QOS_PARAMS_H
+#include <linux/pm_qos_params.h>
+#else /* >= 3.2.0 */
+#include <linux/pm_qos.h>
+#endif /* else >= 3.2.0 */
+#endif /* > 2.6.24 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) )
+#define PM_QOS_CPU_DMA_LATENCY	1
+
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) )
+#include <linux/latency.h>
+#define PM_QOS_DEFAULT_VALUE	INFINITE_LATENCY
+#define pm_qos_add_requirement(pm_qos_class, name, value) \
+		set_acceptable_latency(name, value)
+#define pm_qos_remove_requirement(pm_qos_class, name) \
+		remove_acceptable_latency(name)
+#define pm_qos_update_requirement(pm_qos_class, name, value) \
+		modify_acceptable_latency(name, value)
+#else
+#define PM_QOS_DEFAULT_VALUE	-1
+#define pm_qos_add_requirement(pm_qos_class, name, value)
+#define pm_qos_remove_requirement(pm_qos_class, name)
+#define pm_qos_update_requirement(pm_qos_class, name, value) { \
+	if (value != PM_QOS_DEFAULT_VALUE) { \
+		printk(KERN_WARNING "%s: unable to set PM QoS requirement\n", \
+			pci_name(adapter->pdev)); \
+	} \
+}
+
+#endif /* > 2.6.18 */
+
+#define pci_enable_device_mem(pdev) pci_enable_device(pdev)
+
+#ifndef DEFINE_PCI_DEVICE_TABLE
+#define DEFINE_PCI_DEVICE_TABLE(_table) struct pci_device_id _table[]
+#endif /* DEFINE_PCI_DEVICE_TABLE */
+
+#ifndef strict_strtol
+#define strict_strtol(s, b, r) _kc_strict_strtol(s, b, r)
+static inline int _kc_strict_strtol(const char *buf, unsigned int base, long *res)
+{
+	/* adapted from strict_strtoul() in 2.6.25 */
+	char *tail;
+	long val;
+	size_t len;
+
+	*res = 0;
+	len = strlen(buf);
+	if (!len)
+		return -EINVAL;
+	val = simple_strtol(buf, &tail, base);
+	if (tail == buf)
+		return -EINVAL;
+	if ((*tail == '\0') ||
+	    ((len == (size_t)(tail - buf) + 1) && (*tail == '\n'))) {
+		*res = val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#ifndef TXGBE_PROCFS
+#define TXGBE_PROCFS
+#endif /* TXGBE_PROCFS */
+#endif /* >= 2.6.0 */
+
+#else /* < 2.6.25 */
+
+#if IS_ENABLED(CONFIG_SYSFS)
+#ifndef TXGBE_SYSFS
+#define TXGBE_SYSFS
+#endif /* TXGBE_SYSFS */
+#endif /* CONFIG_SYSFS */
+#if IS_ENABLED(CONFIG_HWMON)
+#ifndef TXGBE_HWMON
+#define TXGBE_HWMON
+#endif /* TXGBE_HWMON */
+#endif /* CONFIG_HWMON */
+
+#endif /* < 2.6.25 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) )
+#ifndef clamp_t
+#define clamp_t(type, val, min, max) ({		\
+	type __val = (val);			\
+	type __min = (min);			\
+	type __max = (max);			\
+	__val = __val < __min ? __min : __val;	\
+	__val > __max ? __max : __val; })
+#endif /* clamp_t */
+#undef kzalloc_node
+#define kzalloc_node(_size, _flags, _node) kzalloc(_size, _flags)
+
+void _kc_pci_disable_link_state(struct pci_dev *dev, int state);
+#define pci_disable_link_state(p, s) _kc_pci_disable_link_state(p, s)
+#else /* < 2.6.26 */
+#define NETDEV_CAN_SET_GSO_MAX_SIZE
+#ifdef HAVE_PCI_ASPM_H
+#include <linux/pci-aspm.h>
+#endif
+#define HAVE_NETDEV_VLAN_FEATURES
+#ifndef PCI_EXP_LNKCAP_ASPMS
+#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
+#endif /* PCI_EXP_LNKCAP_ASPMS */
+#endif /* < 2.6.26 */
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) )
+static inline void _kc_ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+					     __u32 speed)
+{
+	ep->speed = (__u16)speed;
+	/* ep->speed_hi = (__u16)(speed >> 16); */
+}
+#define ethtool_cmd_speed_set _kc_ethtool_cmd_speed_set
+
+static inline __u32 _kc_ethtool_cmd_speed(struct ethtool_cmd *ep)
+{
+	/* no speed_hi before 2.6.27, and probably no need for it yet */
+	return (__u32)ep->speed;
+}
+#define ethtool_cmd_speed _kc_ethtool_cmd_speed
+
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) )
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) && defined(CONFIG_PM))
+#define ANCIENT_PM 1
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)) && \
+       (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) && \
+       defined(CONFIG_PM_SLEEP))
+#define NEWER_PM 1
+#endif
+#if defined(ANCIENT_PM) || defined(NEWER_PM)
+#undef device_set_wakeup_enable
+#define device_set_wakeup_enable(dev, val) \
+	do { \
+		u16 pmc = 0; \
+		int pm = pci_find_capability(adapter->pdev, PCI_CAP_ID_PM); \
+		if (pm) { \
+			pci_read_config_word(adapter->pdev, pm + PCI_PM_PMC, \
+				&pmc); \
+		} \
+		(dev)->power.can_wakeup = !!(pmc >> 11); \
+		(dev)->power.should_wakeup = (val && (pmc >> 11)); \
+	} while (0)
+#endif /* 2.6.15-2.6.22 and CONFIG_PM or 2.6.23-2.6.25 and CONFIG_PM_SLEEP */
+#endif /* 2.6.15 through 2.6.27 */
+#ifndef netif_napi_del
+#define netif_napi_del(_a) do {} while (0)
+#ifdef NAPI
+#ifdef CONFIG_NETPOLL
+#undef netif_napi_del
+#define netif_napi_del(_a) list_del(&(_a)->dev_list);
+#endif
+#endif
+#endif /* netif_napi_del */
+#ifdef dma_mapping_error
+#undef dma_mapping_error
+#endif
+#define dma_mapping_error(dev, dma_addr) pci_dma_mapping_error(dma_addr)
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+#define HAVE_TX_MQ
+#endif
+
+#ifndef DMA_ATTR_WEAK_ORDERING
+#define DMA_ATTR_WEAK_ORDERING 0
+#endif
+
+#ifdef HAVE_TX_MQ
+void _kc_netif_tx_stop_all_queues(struct net_device *);
+void _kc_netif_tx_wake_all_queues(struct net_device *);
+void _kc_netif_tx_start_all_queues(struct net_device *);
+#define netif_tx_stop_all_queues(a) _kc_netif_tx_stop_all_queues(a)
+#define netif_tx_wake_all_queues(a) _kc_netif_tx_wake_all_queues(a)
+#define netif_tx_start_all_queues(a) _kc_netif_tx_start_all_queues(a)
+#undef netif_stop_subqueue
+#define netif_stop_subqueue(_ndev,_qi) do { \
+	if (netif_is_multiqueue((_ndev))) \
+		netif_stop_subqueue((_ndev), (_qi)); \
+	else \
+		netif_stop_queue((_ndev)); \
+	} while (0)
+#undef netif_start_subqueue
+#define netif_start_subqueue(_ndev,_qi) do { \
+	if (netif_is_multiqueue((_ndev))) \
+		netif_start_subqueue((_ndev), (_qi)); \
+	else \
+		netif_start_queue((_ndev)); \
+	} while (0)
+#else /* HAVE_TX_MQ */
+#define netif_tx_stop_all_queues(a) netif_stop_queue(a)
+#define netif_tx_wake_all_queues(a) netif_wake_queue(a)
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) )
+#define netif_tx_start_all_queues(a) netif_start_queue(a)
+#else
+#define netif_tx_start_all_queues(a) do {} while (0)
+#endif
+#define netif_stop_subqueue(_ndev,_qi) netif_stop_queue((_ndev))
+#define netif_start_subqueue(_ndev,_qi) netif_start_queue((_ndev))
+#endif /* HAVE_TX_MQ */
+#ifndef NETIF_F_MULTI_QUEUE
+#define NETIF_F_MULTI_QUEUE 0
+#define netif_is_multiqueue(a) 0
+#define netif_wake_subqueue(a, b)
+#endif /* NETIF_F_MULTI_QUEUE */
+
+#ifndef __WARN_printf
+void __kc_warn_slowpath(const char *file, const int line,
+		const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+#define __WARN_printf(arg...) __kc_warn_slowpath(__FILE__, __LINE__, arg)
+#endif /* __WARN_printf */
+
+#ifndef WARN
+#define WARN(condition, format...) ({						\
+	int __ret_warn_on = !!(condition);				\
+	if (unlikely(__ret_warn_on))					\
+		__WARN_printf(format);					\
+	unlikely(__ret_warn_on);					\
+})
+#endif /* WARN */
+#undef HAVE_TXGBE_DEBUG_FS
+#undef HAVE_TGB_DEBUG_FS
+#else /* < 2.6.27 */
+#define ethtool_cmd_speed_set _kc_ethtool_cmd_speed_set
+static inline void _kc_ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+					     __u32 speed)
+{
+	ep->speed = (__u16)(speed & 0xFFFF);
+	ep->speed_hi = (__u16)(speed >> 16);
+}
+#define HAVE_TX_MQ
+#define HAVE_NETDEV_SELECT_QUEUE
+#ifdef CONFIG_DEBUG_FS
+#define HAVE_TXGBE_DEBUG_FS
+#define HAVE_TGB_DEBUG_FS
+#endif /* CONFIG_DEBUG_FS */
+#endif /* < 2.6.27 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) )
+#define pci_ioremap_bar(pdev, bar)	ioremap(pci_resource_start(pdev, bar), \
+					        pci_resource_len(pdev, bar))
+#define pci_wake_from_d3 _kc_pci_wake_from_d3
+#define pci_prepare_to_sleep _kc_pci_prepare_to_sleep
+int _kc_pci_wake_from_d3(struct pci_dev *dev, bool enable);
+int _kc_pci_prepare_to_sleep(struct pci_dev *dev);
+#define netdev_alloc_page(a) alloc_page(GFP_ATOMIC)
+#ifndef __skb_queue_head_init
+static inline void __kc_skb_queue_head_init(struct sk_buff_head *list)
+{
+	list->prev = list->next = (struct sk_buff *)list;
+	list->qlen = 0;
+}
+#define __skb_queue_head_init(_q) __kc_skb_queue_head_init(_q)
+#endif
+
+#define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
+#define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
+
+#define PCI_EXP_DEVCAP_FLR	0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL_BCR_FLR	0x8000 /* Bridge Configuration Retry / FLR */
+
+#endif /* < 2.6.28 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) )
+#ifndef swap
+#define swap(a, b) \
+	do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
+#endif
+#define pci_request_selected_regions_exclusive(pdev, bars, name) \
+		pci_request_selected_regions(pdev, bars, name)
+#ifndef CONFIG_NR_CPUS
+#define CONFIG_NR_CPUS 1
+#endif /* CONFIG_NR_CPUS */
+#ifndef pcie_aspm_enabled
+#define pcie_aspm_enabled()   (1)
+#endif /* pcie_aspm_enabled */
+
+#define  PCI_EXP_SLTSTA_PDS	0x0040	/* Presence Detect State */
+
+#ifndef PCI_EXP_LNKSTA_CLS
+#define  PCI_EXP_LNKSTA_CLS    0x000f  /* Current Link Speed */
+#endif
+#ifndef PCI_EXP_LNKSTA_NLW
+#define  PCI_EXP_LNKSTA_NLW    0x03f0  /* Negotiated Link Width */
+#endif
+
+#ifndef pci_clear_master
+void _kc_pci_clear_master(struct pci_dev *dev);
+#define pci_clear_master(dev)	_kc_pci_clear_master(dev)
+#endif
+
+#ifndef PCI_EXP_LNKCTL_ASPMC
+#define  PCI_EXP_LNKCTL_ASPMC	0x0003	/* ASPM Control */
+#endif
+
+#ifndef PCI_EXP_LNKCAP_MLW
+#define PCI_EXP_LNKCAP_MLW	0x000003f0 /* Maximum Link Width */
+#endif
+
+#else /* < 2.6.29 */
+#ifndef HAVE_NET_DEVICE_OPS
+#define HAVE_NET_DEVICE_OPS
+#endif
+#ifdef CONFIG_DCB
+#define HAVE_PFC_MODE_ENABLE
+#endif /* CONFIG_DCB */
+#endif /* < 2.6.29 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) )
+#define NO_PTP_SUPPORT
+#define skb_rx_queue_recorded(a) false
+#define skb_get_rx_queue(a) 0
+#define skb_record_rx_queue(a, b) do {} while (0)
+#define skb_tx_hash(n, s) ___kc_skb_tx_hash((n), (s), (n)->real_num_tx_queues)
+#undef CONFIG_FCOE
+#undef CONFIG_FCOE_MODULE
+#ifndef CONFIG_PCI_IOV
+#undef pci_enable_sriov
+#define pci_enable_sriov(a, b) -ENOTSUPP
+#undef pci_disable_sriov
+#define pci_disable_sriov(a) do {} while (0)
+#endif /* CONFIG_PCI_IOV */
+#ifndef pr_cont
+#define pr_cont(fmt, ...) \
+	printk(KERN_CONT fmt, ##__VA_ARGS__)
+#endif /* pr_cont */
+static inline void _kc_synchronize_irq(unsigned int a)
+{
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) )
+	synchronize_irq();
+#else /* < 2.5.28 */
+	synchronize_irq(a);
+#endif /* < 2.5.28 */
+}
+#undef synchronize_irq
+#define synchronize_irq(a) _kc_synchronize_irq(a)
+
+#define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
+
+#ifdef nr_cpus_node
+#undef nr_cpus_node
+#define nr_cpus_node(node) cpumask_weight(cpumask_of_node(node))
+#endif
+
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,5))
+#define HAVE_PCI_DEV_IS_VIRTFN_BIT
+#endif /* RHEL >= 5.5 */
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,5)))
+static inline bool pci_is_root_bus(struct pci_bus *pbus)
+{
+	return !(pbus->parent);
+}
+#endif
+
+#else /* < 2.6.30 */
+#define HAVE_ASPM_QUIRKS
+#define HAVE_PCI_DEV_IS_VIRTFN_BIT
+#endif /* < 2.6.30 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) )
+#define ETH_P_1588 0x88F7
+#define ETH_P_FIP  0x8914
+#ifndef netdev_uc_count
+#define netdev_uc_count(dev) ((dev)->uc_count)
+#endif
+#ifndef netdev_for_each_uc_addr
+#define netdev_for_each_uc_addr(uclist, dev) \
+	for (uclist = dev->uc_list; uclist; uclist = uclist->next)
+#endif
+#ifndef PORT_OTHER
+#define PORT_OTHER 0xff
+#endif
+#ifndef MDIO_PHY_ID_PRTAD
+#define MDIO_PHY_ID_PRTAD 0x03e0
+#endif
+#ifndef MDIO_PHY_ID_DEVAD
+#define MDIO_PHY_ID_DEVAD 0x001f
+#endif
+#ifndef skb_dst
+#define skb_dst(s) ((s)->dst)
+#endif
+
+#ifndef SUPPORTED_1000baseKX_Full
+#define SUPPORTED_1000baseKX_Full	BIT(17)
+#endif
+#ifndef SUPPORTED_10000baseKX4_Full
+#define SUPPORTED_10000baseKX4_Full	BIT(18)
+#endif
+#ifndef SUPPORTED_10000baseKR_Full
+#define SUPPORTED_10000baseKR_Full	BIT(19)
+#endif
+
+#ifndef ADVERTISED_1000baseKX_Full
+#define ADVERTISED_1000baseKX_Full	BIT(17)
+#endif
+#ifndef ADVERTISED_10000baseKX4_Full
+#define ADVERTISED_10000baseKX4_Full	BIT(18)
+#endif
+#ifndef ADVERTISED_10000baseKR_Full
+#define ADVERTISED_10000baseKR_Full	BIT(19)
+#endif
+
+static inline unsigned long dev_trans_start(struct net_device *dev)
+{
+	return dev->trans_start;
+}
+#else /* < 2.6.31 */
+#ifndef HAVE_NETDEV_STORAGE_ADDRESS
+#define HAVE_NETDEV_STORAGE_ADDRESS
+#endif
+#ifndef HAVE_NETDEV_HW_ADDR
+#define HAVE_NETDEV_HW_ADDR
+#endif
+#ifndef HAVE_TRANS_START_IN_QUEUE
+#define HAVE_TRANS_START_IN_QUEUE
+#endif
+#ifndef HAVE_INCLUDE_LINUX_MDIO_H
+#define HAVE_INCLUDE_LINUX_MDIO_H
+#endif
+#include <linux/mdio.h>
+#endif /* < 2.6.31 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) )
+#undef netdev_tx_t
+#define netdev_tx_t int
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef NETIF_F_FCOE_MTU
+#define NETIF_F_FCOE_MTU       BIT(26)
+#endif
+#endif /* CONFIG_FCOE || CONFIG_FCOE_MODULE */
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+static inline int _kc_pm_runtime_get_sync()
+{
+	return 1;
+}
+#define pm_runtime_get_sync(dev)	_kc_pm_runtime_get_sync()
+#else /* 2.6.0 => 2.6.32 */
+static inline int _kc_pm_runtime_get_sync(struct device __always_unused *dev)
+{
+	return 1;
+}
+#ifndef pm_runtime_get_sync
+#define pm_runtime_get_sync(dev)	_kc_pm_runtime_get_sync(dev)
+#endif
+#endif /* 2.6.0 => 2.6.32 */
+#ifndef pm_runtime_put
+#define pm_runtime_put(dev)		do {} while (0)
+#endif
+#ifndef pm_runtime_put_sync
+#define pm_runtime_put_sync(dev)	do {} while (0)
+#endif
+#ifndef pm_runtime_resume
+#define pm_runtime_resume(dev)		do {} while (0)
+#endif
+#ifndef pm_schedule_suspend
+#define pm_schedule_suspend(dev, t)	do {} while (0)
+#endif
+#ifndef pm_runtime_set_suspended
+#define pm_runtime_set_suspended(dev)	do {} while (0)
+#endif
+#ifndef pm_runtime_disable
+#define pm_runtime_disable(dev)		do {} while (0)
+#endif
+#ifndef pm_runtime_put_noidle
+#define pm_runtime_put_noidle(dev)	do {} while (0)
+#endif
+#ifndef pm_runtime_set_active
+#define pm_runtime_set_active(dev)	do {} while (0)
+#endif
+#ifndef pm_runtime_enable
+#define pm_runtime_enable(dev)	do {} while (0)
+#endif
+#ifndef pm_runtime_get_noresume
+#define pm_runtime_get_noresume(dev)	do {} while (0)
+#endif
+#else /* < 2.6.32 */
+#if (RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,2)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
+#define HAVE_RHEL6_NET_DEVICE_EXTENDED
+#endif /* RHEL >= 6.2 && RHEL < 7.0 */
+#if (RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,6)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
+#define HAVE_RHEL6_NET_DEVICE_OPS_EXT
+#define HAVE_NDO_SET_FEATURES
+#endif /* RHEL >= 6.6 && RHEL < 7.0 */
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef HAVE_NETDEV_OPS_FCOE_ENABLE
+#define HAVE_NETDEV_OPS_FCOE_ENABLE
+#endif
+#endif /* CONFIG_FCOE || CONFIG_FCOE_MODULE */
+#ifdef CONFIG_DCB
+#ifndef HAVE_DCBNL_OPS_GETAPP
+#define HAVE_DCBNL_OPS_GETAPP
+#endif
+#endif /* CONFIG_DCB */
+#include <linux/pm_runtime.h>
+/* IOV bad DMA target work arounds require at least this kernel rev support */
+#define HAVE_PCIE_TYPE
+#endif /* < 2.6.32 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) )
+#ifndef pci_pcie_cap
+#define pci_pcie_cap(pdev) pci_find_capability(pdev, PCI_CAP_ID_EXP)
+#endif
+#ifndef IPV4_FLOW
+#define IPV4_FLOW 0x10
+#endif /* IPV4_FLOW */
+#ifndef IPV6_FLOW
+#define IPV6_FLOW 0x11
+#endif /* IPV6_FLOW */
+/* Features back-ported to RHEL6 or SLES11 SP1 after 2.6.32 */
+#if ( (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)) || \
+      (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,1,0)) )
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef HAVE_NETDEV_OPS_FCOE_GETWWN
+#define HAVE_NETDEV_OPS_FCOE_GETWWN
+#endif
+#endif /* CONFIG_FCOE || CONFIG_FCOE_MODULE */
+#endif /* RHEL6 or SLES11 SP1 */
+#ifndef __percpu
+#define __percpu
+#endif /* __percpu */
+
+#ifndef PORT_DA
+#define PORT_DA PORT_OTHER
+#endif /* PORT_DA */
+#ifndef PORT_NONE
+#define PORT_NONE PORT_OTHER
+#endif
+
+#if ((RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,3)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0))))
+#if !defined(CONFIG_X86_32) && !defined(CONFIG_NEED_DMA_MAP_STATE)
+#undef DEFINE_DMA_UNMAP_ADDR
+#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME)	dma_addr_t ADDR_NAME
+#undef DEFINE_DMA_UNMAP_LEN
+#define DEFINE_DMA_UNMAP_LEN(LEN_NAME)		__u32 LEN_NAME
+#undef dma_unmap_addr
+#define dma_unmap_addr(PTR, ADDR_NAME)		((PTR)->ADDR_NAME)
+#undef dma_unmap_addr_set
+#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL)	(((PTR)->ADDR_NAME) = (VAL))
+#undef dma_unmap_len
+#define dma_unmap_len(PTR, LEN_NAME)		((PTR)->LEN_NAME)
+#undef dma_unmap_len_set
+#define dma_unmap_len_set(PTR, LEN_NAME, VAL)	(((PTR)->LEN_NAME) = (VAL))
+#endif /* CONFIG_X86_64 && !CONFIG_NEED_DMA_MAP_STATE */
+#endif /* RHEL_RELEASE_CODE */
+
+#if (!(RHEL_RELEASE_CODE && \
+       (((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,8)) && \
+         (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,0))) || \
+        ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1)) && \
+         (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0))))))
+static inline bool pci_is_pcie(struct pci_dev *dev)
+{
+	return !!pci_pcie_cap(dev);
+}
+#endif /* RHEL_RELEASE_CODE */
+
+#if (!(RHEL_RELEASE_CODE && \
+      (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,2))))
+#define sk_tx_queue_get(_sk) (-1)
+#define sk_tx_queue_set(_sk, _tx_queue) do {} while(0)
+#endif /* !(RHEL >= 6.2) */
+
+#if (RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
+#define HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
+#define HAVE_ETHTOOL_GRXFHINDIR_SIZE
+#define HAVE_ETHTOOL_SET_PHYS_ID
+#define HAVE_ETHTOOL_GET_TS_INFO
+#if (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,5))
+#define HAVE_ETHTOOL_GSRSSH
+#define HAVE_RHEL6_SRIOV_CONFIGURE
+#define HAVE_RXFH_NONCONST
+#endif /* RHEL > 6.5 */
+#endif /* RHEL >= 6.4 && RHEL < 7.0 */
+
+#else /* < 2.6.33 */
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef HAVE_NETDEV_OPS_FCOE_GETWWN
+#define HAVE_NETDEV_OPS_FCOE_GETWWN
+#endif
+#endif /* CONFIG_FCOE || CONFIG_FCOE_MODULE */
+#endif /* < 2.6.33 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) )
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,0))
+#ifndef pci_num_vf
+#define pci_num_vf(pdev) _kc_pci_num_vf(pdev)
+int _kc_pci_num_vf(struct pci_dev *dev);
+#endif
+#endif /* RHEL_RELEASE_CODE */
+
+#ifndef dev_is_pci
+#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
+#endif
+
+#ifndef ETH_FLAG_NTUPLE
+#define ETH_FLAG_NTUPLE NETIF_F_NTUPLE
+#endif
+
+#ifndef netdev_mc_count
+#define netdev_mc_count(dev) ((dev)->mc_count)
+#endif
+#ifndef netdev_mc_empty
+#define netdev_mc_empty(dev) (netdev_mc_count(dev) == 0)
+#endif
+#ifndef netdev_for_each_mc_addr
+#define netdev_for_each_mc_addr(mclist, dev) \
+	for (mclist = dev->mc_list; mclist; mclist = mclist->next)
+#endif
+#ifndef netdev_uc_count
+#define netdev_uc_count(dev) ((dev)->uc.count)
+#endif
+#ifndef netdev_uc_empty
+#define netdev_uc_empty(dev) (netdev_uc_count(dev) == 0)
+#endif
+#ifndef netdev_for_each_uc_addr
+#define netdev_for_each_uc_addr(ha, dev) \
+	list_for_each_entry(ha, &dev->uc.list, list)
+#endif
+#ifndef dma_set_coherent_mask
+#define dma_set_coherent_mask(dev,mask) \
+	pci_set_consistent_dma_mask(to_pci_dev(dev),(mask))
+#endif
+#ifndef pci_dev_run_wake
+#define pci_dev_run_wake(pdev)	(0)
+#endif
+
+/* netdev logging taken from include/linux/netdevice.h */
+#ifndef netdev_name
+static inline const char *_kc_netdev_name(const struct net_device *dev)
+{
+	if (dev->reg_state != NETREG_REGISTERED)
+		return "(unregistered net_device)";
+	return dev->name;
+}
+#define netdev_name(netdev)	_kc_netdev_name(netdev)
+#endif /* netdev_name */
+
+#undef netdev_printk
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+#define netdev_printk(level, netdev, format, args...)		\
+do {								\
+	struct pci_dev *pdev = _kc_netdev_to_pdev(netdev);	\
+	printk(level "%s: " format, pci_name(pdev), ##args);	\
+} while(0)
+#elif ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) )
+#define netdev_printk(level, netdev, format, args...)		\
+do {								\
+	struct pci_dev *pdev = _kc_netdev_to_pdev(netdev);	\
+	struct device *dev = pci_dev_to_dev(pdev);		\
+	dev_printk(level, dev, "%s: " format,			\
+		   netdev_name(netdev), ##args);		\
+} while(0)
+#else /* 2.6.21 => 2.6.34 */
+#define netdev_printk(level, netdev, format, args...)		\
+	dev_printk(level, (netdev)->dev.parent,			\
+		   "%s: " format,				\
+		   netdev_name(netdev), ##args)
+#endif /* <2.6.0 <2.6.21 <2.6.34 */
+#undef netdev_emerg
+#define netdev_emerg(dev, format, args...)			\
+	netdev_printk(KERN_EMERG, dev, format, ##args)
+#undef netdev_alert
+#define netdev_alert(dev, format, args...)			\
+	netdev_printk(KERN_ALERT, dev, format, ##args)
+#undef netdev_crit
+#define netdev_crit(dev, format, args...)			\
+	netdev_printk(KERN_CRIT, dev, format, ##args)
+#undef netdev_err
+#define netdev_err(dev, format, args...)			\
+	netdev_printk(KERN_ERR, dev, format, ##args)
+#undef netdev_warn
+#define netdev_warn(dev, format, args...)			\
+	netdev_printk(KERN_WARNING, dev, format, ##args)
+#undef netdev_notice
+#define netdev_notice(dev, format, args...)			\
+	netdev_printk(KERN_NOTICE, dev, format, ##args)
+#undef netdev_info
+#define netdev_info(dev, format, args...)			\
+	netdev_printk(KERN_INFO, dev, format, ##args)
+#undef netdev_dbg
+#if defined(DEBUG)
+#define netdev_dbg(__dev, format, args...)			\
+	netdev_printk(KERN_DEBUG, __dev, format, ##args)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
+#define netdev_dbg(__dev, format, args...)			\
+do {								\
+	dynamic_dev_dbg((__dev)->dev.parent, "%s: " format,	\
+			netdev_name(__dev), ##args);		\
+} while (0)
+#else /* DEBUG */
+#define netdev_dbg(__dev, format, args...)			\
+({								\
+	if (0)							\
+		netdev_printk(KERN_DEBUG, __dev, format, ##args); \
+	0;							\
+})
+#endif /* DEBUG */
+
+#undef netif_printk
+#define netif_printk(priv, type, level, dev, fmt, args...)	\
+do {								\
+	if (netif_msg_##type(priv))				\
+		netdev_printk(level, (dev), fmt, ##args);	\
+} while (0)
+
+#undef netif_emerg
+#define netif_emerg(priv, type, dev, fmt, args...)		\
+	netif_level(emerg, priv, type, dev, fmt, ##args)
+#undef netif_alert
+#define netif_alert(priv, type, dev, fmt, args...)		\
+	netif_level(alert, priv, type, dev, fmt, ##args)
+#undef netif_crit
+#define netif_crit(priv, type, dev, fmt, args...)		\
+	netif_level(crit, priv, type, dev, fmt, ##args)
+#undef netif_err
+#define netif_err(priv, type, dev, fmt, args...)		\
+	netif_level(err, priv, type, dev, fmt, ##args)
+#undef netif_warn
+#define netif_warn(priv, type, dev, fmt, args...)		\
+	netif_level(warn, priv, type, dev, fmt, ##args)
+#undef netif_notice
+#define netif_notice(priv, type, dev, fmt, args...)		\
+	netif_level(notice, priv, type, dev, fmt, ##args)
+#undef netif_info
+#define netif_info(priv, type, dev, fmt, args...)		\
+	netif_level(info, priv, type, dev, fmt, ##args)
+#undef netif_dbg
+#define netif_dbg(priv, type, dev, fmt, args...)		\
+	netif_level(dbg, priv, type, dev, fmt, ##args)
+
+#ifdef SET_SYSTEM_SLEEP_PM_OPS
+#define HAVE_SYSTEM_SLEEP_PM_OPS
+#endif
+
+#ifndef for_each_set_bit
+#define for_each_set_bit(bit, addr, size) \
+	for ((bit) = find_first_bit((addr), (size)); \
+		(bit) < (size); \
+		(bit) = find_next_bit((addr), (size), (bit) + 1))
+#endif /* for_each_set_bit */
+
+#ifndef DEFINE_DMA_UNMAP_ADDR
+#define DEFINE_DMA_UNMAP_ADDR DECLARE_PCI_UNMAP_ADDR
+#define DEFINE_DMA_UNMAP_LEN DECLARE_PCI_UNMAP_LEN
+#define dma_unmap_addr pci_unmap_addr
+#define dma_unmap_addr_set pci_unmap_addr_set
+#define dma_unmap_len pci_unmap_len
+#define dma_unmap_len_set pci_unmap_len_set
+#endif /* DEFINE_DMA_UNMAP_ADDR */
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6, 3))
+#ifdef TGB_HWMON
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define sysfs_attr_init(attr)				\
+	do {						\
+		static struct lock_class_key __key;	\
+		(attr)->key = &__key;			\
+	} while (0)
+#else
+#define sysfs_attr_init(attr) do {} while (0)
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+#endif /* TGB_HWMON */
+#endif /* RHEL_RELEASE_CODE */
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+static inline bool _kc_pm_runtime_suspended()
+{
+	return false;
+}
+#define pm_runtime_suspended(dev)	_kc_pm_runtime_suspended()
+#else /* 2.6.0 => 2.6.34 */
+static inline bool _kc_pm_runtime_suspended(struct device __always_unused *dev)
+{
+	return false;
+}
+#ifndef pm_runtime_suspended
+#define pm_runtime_suspended(dev)	_kc_pm_runtime_suspended(dev)
+#endif
+#endif /* 2.6.0 => 2.6.34 */
+
+#ifndef pci_bus_speed
+/* override pci_bus_speed introduced in 2.6.19 with an expanded enum type */
+enum _kc_pci_bus_speed {
+	_KC_PCIE_SPEED_2_5GT		= 0x14,
+	_KC_PCIE_SPEED_5_0GT		= 0x15,
+	_KC_PCIE_SPEED_8_0GT		= 0x16,
+	_KC_PCI_SPEED_UNKNOWN		= 0xff,
+};
+#define pci_bus_speed		_kc_pci_bus_speed
+#define PCIE_SPEED_2_5GT	_KC_PCIE_SPEED_2_5GT
+#define PCIE_SPEED_5_0GT	_KC_PCIE_SPEED_5_0GT
+#define PCIE_SPEED_8_0GT	_KC_PCIE_SPEED_8_0GT
+#define PCI_SPEED_UNKNOWN	_KC_PCI_SPEED_UNKNOWN
+#endif /* pci_bus_speed */
+
+#else /* < 2.6.34 */
+#define HAVE_SYSTEM_SLEEP_PM_OPS
+#ifndef HAVE_SET_RX_MODE
+#define HAVE_SET_RX_MODE
+#endif
+
+#endif /* < 2.6.34 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) )
+ssize_t _kc_simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
+				   const void __user *from, size_t count);
+#define simple_write_to_buffer _kc_simple_write_to_buffer
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)))
+static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+{
+#ifdef HAVE_PCI_DEV_IS_VIRTFN_BIT
+#ifdef CONFIG_PCI_IOV
+	if (dev->is_virtfn)
+		dev = dev->physfn;
+#endif /* CONFIG_PCI_IOV */
+#endif /* HAVE_PCI_DEV_IS_VIRTFN_BIT */
+	return dev;
+}
+#endif /* ! RHEL >= 6.4 */
+
+#ifndef PCI_EXP_LNKSTA_NLW_SHIFT
+#define PCI_EXP_LNKSTA_NLW_SHIFT 4
+#endif
+
+#ifndef numa_node_id
+#define numa_node_id() 0
+#endif
+#ifndef numa_mem_id
+#define numa_mem_id numa_node_id
+#endif
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)))
+#ifdef HAVE_TX_MQ
+#include <net/sch_generic.h>
+#ifndef CONFIG_NETDEVICES_MULTIQUEUE
+int _kc_netif_set_real_num_tx_queues(struct net_device *, unsigned int);
+#else /* CONFIG_NETDEVICES_MULTI_QUEUE */
+static inline int _kc_netif_set_real_num_tx_queues(struct net_device *dev,
+						   unsigned int txq)
+{
+	dev->egress_subqueue_count = txq;
+	return 0;
+}
+#endif /* CONFIG_NETDEVICES_MULTI_QUEUE */
+#else /* HAVE_TX_MQ */
+static inline int _kc_netif_set_real_num_tx_queues(struct net_device __always_unused *dev,
+						   unsigned int __always_unused txq)
+{
+	return 0;
+}
+#endif /* HAVE_TX_MQ */
+#define netif_set_real_num_tx_queues(dev, txq) \
+	_kc_netif_set_real_num_tx_queues(dev, txq)
+#endif /* !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)) */
+#ifndef ETH_FLAG_RXHASH
+#define ETH_FLAG_RXHASH (1<<28)
+#endif /* ETH_FLAG_RXHASH */
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0))
+#define HAVE_IRQ_AFFINITY_HINT
+#endif
+struct device_node;
+#else /* < 2.6.35 */
+#define HAVE_STRUCT_DEVICE_OF_NODE
+#define HAVE_PM_QOS_REQUEST_LIST
+#define HAVE_IRQ_AFFINITY_HINT
+#include <linux/of.h>
+#endif /* < 2.6.35 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) )
+int _kc_ethtool_op_set_flags(struct net_device *, u32, u32);
+#define ethtool_op_set_flags _kc_ethtool_op_set_flags
+u32 _kc_ethtool_op_get_flags(struct net_device *);
+#define ethtool_op_get_flags _kc_ethtool_op_get_flags
+
+enum {
+	WQ_UNBOUND = 0,
+	WQ_RESCUER = 0,
+};
+
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#ifdef NET_IP_ALIGN
+#undef NET_IP_ALIGN
+#endif
+#define NET_IP_ALIGN 0
+#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
+
+#ifdef NET_SKB_PAD
+#undef NET_SKB_PAD
+#endif
+
+#if (L1_CACHE_BYTES > 32)
+#define NET_SKB_PAD L1_CACHE_BYTES
+#else
+#define NET_SKB_PAD 32
+#endif
+
+static inline struct sk_buff *_kc_netdev_alloc_skb_ip_align(struct net_device *dev,
+							    unsigned int length)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(length + NET_SKB_PAD + NET_IP_ALIGN, GFP_ATOMIC);
+	if (skb) {
+#if (NET_IP_ALIGN + NET_SKB_PAD)
+		skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD);
+#endif
+		skb->dev = dev;
+	}
+	return skb;
+}
+
+#ifdef netdev_alloc_skb_ip_align
+#undef netdev_alloc_skb_ip_align
+#endif
+#define netdev_alloc_skb_ip_align(n, l) _kc_netdev_alloc_skb_ip_align(n, l)
+
+#undef netif_level
+#define netif_level(level, priv, type, dev, fmt, args...)	\
+do {								\
+	if (netif_msg_##type(priv))				\
+		netdev_##level(dev, fmt, ##args);		\
+} while (0)
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,3)))
+#undef usleep_range
+#define usleep_range(min, max)	msleep(DIV_ROUND_UP(min, 1000))
+#endif
+
+#define u64_stats_update_begin(a) do { } while(0)
+#define u64_stats_update_end(a) do { } while(0)
+#define u64_stats_fetch_begin(a) do { } while(0)
+#define u64_stats_fetch_retry_bh(a,b) (0)
+#define u64_stats_fetch_begin_bh(a) (0)
+
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,1))
+#define HAVE_8021P_SUPPORT
+#endif
+
+/* RHEL6.4 and SLES11sp2 backported skb_tx_timestamp */
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(11,2,0)))
+static inline void skb_tx_timestamp(struct sk_buff __always_unused *skb)
+{
+	return;
+}
+#endif
+
+#else /* < 2.6.36 */
+
+#define msleep(x)	do { if (x > 20)				\
+				msleep(x);				\
+			     else					\
+				usleep_range(1000 * x, 2000 * x);	\
+			} while (0)
+
+#define HAVE_PM_QOS_REQUEST_ACTIVE
+#define HAVE_8021P_SUPPORT
+#define HAVE_NDO_GET_STATS64
+#endif /* < 2.6.36 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) )
+#define HAVE_NON_CONST_PCI_DRIVER_NAME
+#ifndef netif_set_real_num_tx_queues
+static inline int _kc_netif_set_real_num_tx_queues(struct net_device *dev,
+						   unsigned int txq)
+{
+	netif_set_real_num_tx_queues(dev, txq);
+	return 0;
+}
+#define netif_set_real_num_tx_queues(dev, txq) \
+	_kc_netif_set_real_num_tx_queues(dev, txq)
+#endif
+#ifndef netif_set_real_num_rx_queues
+static inline int __kc_netif_set_real_num_rx_queues(struct net_device __always_unused *dev,
+						    unsigned int __always_unused rxq)
+{
+	return 0;
+}
+#define netif_set_real_num_rx_queues(dev, rxq) \
+	__kc_netif_set_real_num_rx_queues((dev), (rxq))
+#endif
+#ifndef ETHTOOL_RXNTUPLE_ACTION_CLEAR
+#define ETHTOOL_RXNTUPLE_ACTION_CLEAR (-2)
+#endif
+#ifndef VLAN_N_VID
+#define VLAN_N_VID	VLAN_GROUP_ARRAY_LEN
+#endif /* VLAN_N_VID */
+#ifndef ETH_FLAG_TXVLAN
+#define ETH_FLAG_TXVLAN BIT(7)
+#endif /* ETH_FLAG_TXVLAN */
+#ifndef ETH_FLAG_RXVLAN
+#define ETH_FLAG_RXVLAN BIT(8)
+#endif /* ETH_FLAG_RXVLAN */
+
+#define WQ_MEM_RECLAIM WQ_RESCUER
+
+static inline void _kc_skb_checksum_none_assert(struct sk_buff *skb)
+{
+	WARN_ON(skb->ip_summed != CHECKSUM_NONE);
+}
+#define skb_checksum_none_assert(skb) _kc_skb_checksum_none_assert(skb)
+
+static inline void *_kc_vzalloc_node(unsigned long size, int node)
+{
+	void *addr = vmalloc_node(size, node);
+	if (addr)
+		memset(addr, 0, size);
+	return addr;
+}
+#define vzalloc_node(_size, _node) _kc_vzalloc_node(_size, _node)
+
+static inline void *_kc_vzalloc(unsigned long size)
+{
+	void *addr = vmalloc(size);
+	if (addr)
+		memset(addr, 0, size);
+	return addr;
+}
+#define vzalloc(_size) _kc_vzalloc(_size)
+
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,7)) || \
+     (RHEL_RELEASE_CODE == RHEL_RELEASE_VERSION(6,0)))
+static inline __be16 vlan_get_protocol(const struct sk_buff *skb)
+{
+	if (vlan_tx_tag_present(skb) ||
+	    skb->protocol != cpu_to_be16(ETH_P_8021Q))
+		return skb->protocol;
+
+	if (skb_headlen(skb) < sizeof(struct vlan_ethhdr))
+		return 0;
+
+	return ((struct vlan_ethhdr*)skb->data)->h_vlan_encapsulated_proto;
+}
+#endif /* !RHEL5.7+ || RHEL6.0 */
+
+#ifdef HAVE_HW_TIME_STAMP
+#define SKBTX_HW_TSTAMP BIT(0)
+#define SKBTX_IN_PROGRESS BIT(2)
+#define SKB_SHARED_TX_IS_UNION
+#endif
+
+#ifndef device_wakeup_enable
+#define device_wakeup_enable(dev)	device_set_wakeup_enable(dev, true)
+#endif
+
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,4,18) )
+#ifndef HAVE_VLAN_RX_REGISTER
+#define HAVE_VLAN_RX_REGISTER
+#endif
+#endif /* > 2.4.18 */
+#endif /* < 2.6.37 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) )
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) )
+#define skb_checksum_start_offset(skb) skb_transport_offset(skb)
+#else /* 2.6.22 -> 2.6.37 */
+static inline int _kc_skb_checksum_start_offset(const struct sk_buff *skb)
+{
+        return skb->csum_start - skb_headroom(skb);
+}
+#define skb_checksum_start_offset(skb) _kc_skb_checksum_start_offset(skb)
+#endif /* 2.6.22 -> 2.6.37 */
+#if IS_ENABLED(CONFIG_DCB)
+#ifndef IEEE_8021QAZ_MAX_TCS
+#define IEEE_8021QAZ_MAX_TCS 8
+#endif
+#ifndef DCB_CAP_DCBX_HOST
+#define DCB_CAP_DCBX_HOST		0x01
+#endif
+#ifndef DCB_CAP_DCBX_LLD_MANAGED
+#define DCB_CAP_DCBX_LLD_MANAGED	0x02
+#endif
+#ifndef DCB_CAP_DCBX_VER_CEE
+#define DCB_CAP_DCBX_VER_CEE		0x04
+#endif
+#ifndef DCB_CAP_DCBX_VER_IEEE
+#define DCB_CAP_DCBX_VER_IEEE		0x08
+#endif
+#ifndef DCB_CAP_DCBX_STATIC
+#define DCB_CAP_DCBX_STATIC		0x10
+#endif
+#endif /* CONFIG_DCB */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,2))
+#define CONFIG_XPS
+#endif /* RHEL_RELEASE_VERSION(6,2) */
+#endif /* < 2.6.38 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) )
+#ifndef TC_BITMASK
+#define TC_BITMASK 15
+#endif
+#ifndef NETIF_F_RXCSUM
+#define NETIF_F_RXCSUM		BIT(29)
+#endif
+#ifndef skb_queue_reverse_walk_safe
+#define skb_queue_reverse_walk_safe(queue, skb, tmp)				\
+		for (skb = (queue)->prev, tmp = skb->prev;			\
+		     skb != (struct sk_buff *)(queue);				\
+		     skb = tmp, tmp = skb->prev)
+#endif
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef FCOE_MTU
+#define FCOE_MTU	2158
+#endif
+#endif
+#if IS_ENABLED(CONFIG_DCB)
+#ifndef IEEE_8021QAZ_APP_SEL_ETHERTYPE
+#define IEEE_8021QAZ_APP_SEL_ETHERTYPE	1
+#endif
+#endif
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)))
+#define kstrtoul(a, b, c)  ((*(c)) = simple_strtoul((a), NULL, (b)), 0)
+#define kstrtouint(a, b, c)  ((*(c)) = simple_strtoul((a), NULL, (b)), 0)
+#define kstrtou32(a, b, c)  ((*(c)) = simple_strtoul((a), NULL, (b)), 0)
+#endif /* !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) */
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,0)))
+u16 ___kc_skb_tx_hash(struct net_device *, const struct sk_buff *, u16);
+#define __skb_tx_hash(n, s, q) ___kc_skb_tx_hash((n), (s), (q))
+u8 _kc_netdev_get_num_tc(struct net_device *dev);
+#define netdev_get_num_tc(dev) _kc_netdev_get_num_tc(dev)
+int _kc_netdev_set_num_tc(struct net_device *dev, u8 num_tc);
+#define netdev_set_num_tc(dev, tc) _kc_netdev_set_num_tc((dev), (tc))
+#define netdev_reset_tc(dev) _kc_netdev_set_num_tc((dev), 0)
+#define netdev_set_tc_queue(dev, tc, cnt, off) do {} while (0)
+u8 _kc_netdev_get_prio_tc_map(struct net_device *dev, u8 up);
+#define netdev_get_prio_tc_map(dev, up) _kc_netdev_get_prio_tc_map(dev, up)
+#define netdev_set_prio_tc_map(dev, up, tc) do {} while (0)
+#else /* RHEL6.1 or greater */
+#ifndef HAVE_MQPRIO
+#define HAVE_MQPRIO
+#endif /* HAVE_MQPRIO */
+#if IS_ENABLED(CONFIG_DCB)
+#ifndef HAVE_DCBNL_IEEE
+#define HAVE_DCBNL_IEEE
+#ifndef IEEE_8021QAZ_TSA_STRICT
+#define IEEE_8021QAZ_TSA_STRICT		0
+#endif
+#ifndef IEEE_8021QAZ_TSA_ETS
+#define IEEE_8021QAZ_TSA_ETS		2
+#endif
+#ifndef IEEE_8021QAZ_APP_SEL_ETHERTYPE
+#define IEEE_8021QAZ_APP_SEL_ETHERTYPE	1
+#endif
+#endif
+#endif /* CONFIG_DCB */
+#endif /* !(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,0)) */
+
+#ifndef udp_csum
+#define udp_csum __kc_udp_csum
+static inline __wsum __kc_udp_csum(struct sk_buff *skb)
+{
+	__wsum csum = csum_partial(skb_transport_header(skb),
+				   sizeof(struct udphdr), skb->csum);
+
+	for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) {
+		csum = csum_add(csum, skb->csum);
+	}
+	return csum;
+}
+#endif /* udp_csum */
+#else /* < 2.6.39 */
+#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifndef HAVE_NETDEV_OPS_FCOE_DDP_TARGET
+#define HAVE_NETDEV_OPS_FCOE_DDP_TARGET
+#endif
+#endif /* CONFIG_FCOE || CONFIG_FCOE_MODULE */
+#ifndef HAVE_MQPRIO
+#define HAVE_MQPRIO
+#endif
+#ifndef HAVE_SETUP_TC
+#define HAVE_SETUP_TC
+#endif
+#ifdef CONFIG_DCB
+#ifndef HAVE_DCBNL_IEEE
+#define HAVE_DCBNL_IEEE
+#endif
+#endif /* CONFIG_DCB */
+#ifndef HAVE_NDO_SET_FEATURES
+#define HAVE_NDO_SET_FEATURES
+#endif
+#define HAVE_IRQ_AFFINITY_NOTIFY
+#endif /* < 2.6.39 */
+
+/*****************************************************************************/
+/* use < 2.6.40 because of a Fedora 15 kernel update where they
+ * updated the kernel version to 2.6.40.x and they back-ported 3.0 features
+ * like set_phys_id for ethtool.
+ */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,40) )
+#ifdef ETHTOOL_GRXRINGS
+#ifndef FLOW_EXT
+#define	FLOW_EXT	0x80000000
+union _kc_ethtool_flow_union {
+	struct ethtool_tcpip4_spec		tcp_ip4_spec;
+	struct ethtool_usrip4_spec		usr_ip4_spec;
+	__u8					hdata[60];
+};
+struct _kc_ethtool_flow_ext {
+	__be16	vlan_etype;
+	__be16	vlan_tci;
+	__be32	data[2];
+};
+struct _kc_ethtool_rx_flow_spec {
+	__u32		flow_type;
+	union _kc_ethtool_flow_union h_u;
+	struct _kc_ethtool_flow_ext h_ext;
+	union _kc_ethtool_flow_union m_u;
+	struct _kc_ethtool_flow_ext m_ext;
+	__u64		ring_cookie;
+	__u32		location;
+};
+#define ethtool_rx_flow_spec _kc_ethtool_rx_flow_spec
+#endif /* FLOW_EXT */
+#endif
+
+#define pci_disable_link_state_locked pci_disable_link_state
+
+#ifndef PCI_LTR_VALUE_MASK
+#define  PCI_LTR_VALUE_MASK	0x000003ff
+#endif
+#ifndef PCI_LTR_SCALE_MASK
+#define  PCI_LTR_SCALE_MASK	0x00001c00
+#endif
+#ifndef PCI_LTR_SCALE_SHIFT
+#define  PCI_LTR_SCALE_SHIFT	10
+#endif
+
+#else /* < 2.6.40 */
+#define HAVE_ETHTOOL_SET_PHYS_ID
+#endif /* < 2.6.40 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) )
+#define USE_LEGACY_PM_SUPPORT
+#ifndef kfree_rcu
+#define kfree_rcu(_ptr, _rcu_head) kfree(_ptr)
+#endif /* kfree_rcu */
+#ifndef kstrtol_from_user
+#define kstrtol_from_user(s, c, b, r) _kc_kstrtol_from_user(s, c, b, r)
+static inline int _kc_kstrtol_from_user(const char __user *s, size_t count,
+					unsigned int base, long *res)
+{
+	/* sign, base 2 representation, newline, terminator */
+	char buf[1 + sizeof(long) * 8 + 1 + 1];
+
+	count = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, s, count))
+		return -EFAULT;
+	buf[count] = '\0';
+	return strict_strtol(buf, base, res);
+}
+#endif
+
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,0) || \
+     RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,7)))
+/* 20000base_blah_full Supported and Advertised Registers */
+#define SUPPORTED_20000baseMLD2_Full	BIT(21)
+#define SUPPORTED_20000baseKR2_Full	BIT(22)
+#define ADVERTISED_20000baseMLD2_Full	BIT(21)
+#define ADVERTISED_20000baseKR2_Full	BIT(22)
+#endif /* RHEL_RELEASE_CODE */
+#endif /* < 3.0.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) )
+#ifndef __netdev_alloc_skb_ip_align
+#define __netdev_alloc_skb_ip_align(d,l,_g) netdev_alloc_skb_ip_align(d,l)
+#endif /* __netdev_alloc_skb_ip_align */
+#define dcb_ieee_setapp(dev, app) dcb_setapp(dev, app)
+#define dcb_ieee_delapp(dev, app) 0
+#define dcb_ieee_getapp_mask(dev, app) (1 << app->priority)
+
+/* 1000BASE-T Control register */
+#define CTL1000_AS_MASTER	0x0800
+#define CTL1000_ENABLE_MASTER	0x1000
+
+/* kernels less than 3.0.0 don't have this */
+#ifndef ETH_P_8021AD
+#define ETH_P_8021AD	0x88A8
+#endif
+
+/* Stub definition for !CONFIG_OF is introduced later */
+#ifdef CONFIG_OF
+static inline struct device_node *
+pci_device_to_OF_node(struct pci_dev __maybe_unused *pdev)
+{
+#ifdef HAVE_STRUCT_DEVICE_OF_NODE
+	return pdev ? pdev->dev.of_node : NULL;
+#else
+	return NULL;
+#endif /* !HAVE_STRUCT_DEVICE_OF_NODE */
+}
+#endif /* CONFIG_OF */
+#else /* < 3.1.0 */
+#ifndef HAVE_DCBNL_IEEE_DELAPP
+#define HAVE_DCBNL_IEEE_DELAPP
+#endif
+#endif /* < 3.1.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) )
+#ifndef dma_zalloc_coherent
+#define dma_zalloc_coherent(d, s, h, f) _kc_dma_zalloc_coherent(d, s, h, f)
+static inline void *_kc_dma_zalloc_coherent(struct device *dev, size_t size,
+					    dma_addr_t *dma_handle, gfp_t flag)
+{
+	void *ret = dma_alloc_coherent(dev, size, dma_handle, flag);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+#endif
+#ifdef ETHTOOL_GRXRINGS
+#define HAVE_ETHTOOL_GET_RXNFC_VOID_RULE_LOCS
+#endif /* ETHTOOL_GRXRINGS */
+
+#ifndef skb_frag_size
+#define skb_frag_size(frag)	_kc_skb_frag_size(frag)
+static inline unsigned int _kc_skb_frag_size(const skb_frag_t *frag)
+{
+	return frag->size;
+}
+#endif /* skb_frag_size */
+
+#ifndef skb_frag_size_sub
+#define skb_frag_size_sub(frag, delta)	_kc_skb_frag_size_sub(frag, delta)
+static inline void _kc_skb_frag_size_sub(skb_frag_t *frag, int delta)
+{
+	frag->size -= delta;
+}
+#endif /* skb_frag_size_sub */
+
+#ifndef skb_frag_page
+#define skb_frag_page(frag)	_kc_skb_frag_page(frag)
+static inline struct page *_kc_skb_frag_page(const skb_frag_t *frag)
+{
+	return frag->page;
+}
+#endif /* skb_frag_page */
+
+#ifndef skb_frag_address
+#define skb_frag_address(frag)	_kc_skb_frag_address(frag)
+static inline void *_kc_skb_frag_address(const skb_frag_t *frag)
+{
+	return page_address(skb_frag_page(frag)) + frag->page_offset;
+}
+#endif /* skb_frag_address */
+
+#ifndef skb_frag_dma_map
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) )
+#include <linux/dma-mapping.h>
+#endif
+#define skb_frag_dma_map(dev,frag,offset,size,dir) \
+		_kc_skb_frag_dma_map(dev,frag,offset,size,dir)
+static inline dma_addr_t _kc_skb_frag_dma_map(struct device *dev,
+					      const skb_frag_t *frag,
+					      size_t offset, size_t size,
+					      enum dma_data_direction dir)
+{
+	return dma_map_page(dev, skb_frag_page(frag),
+			    frag->page_offset + offset, size, dir);
+}
+#endif /* skb_frag_dma_map */
+
+#ifndef __skb_frag_unref
+#define __skb_frag_unref(frag) __kc_skb_frag_unref(frag)
+static inline void __kc_skb_frag_unref(skb_frag_t *frag)
+{
+	put_page(skb_frag_page(frag));
+}
+#endif /* __skb_frag_unref */
+
+#ifndef SPEED_UNKNOWN
+#define SPEED_UNKNOWN	-1
+#endif
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN	0xff
+#endif
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,3)) ||\
+     (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0)))
+#ifndef HAVE_PCI_DEV_FLAGS_ASSIGNED
+#define HAVE_PCI_DEV_FLAGS_ASSIGNED
+#endif
+#endif
+#else /* < 3.2.0 */
+#ifndef HAVE_PCI_DEV_FLAGS_ASSIGNED
+#define HAVE_PCI_DEV_FLAGS_ASSIGNED
+#define HAVE_VF_SPOOFCHK_CONFIGURE
+#endif
+#ifndef HAVE_SKB_L4_RXHASH
+#define HAVE_SKB_L4_RXHASH
+#endif
+#define HAVE_IOMMU_PRESENT
+#define HAVE_PM_QOS_REQUEST_LIST_NEW
+#endif /* < 3.2.0 */
+
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE == RHEL_RELEASE_VERSION(6, 2))
+#undef txgbe_get_netdev_tc_txq
+#define txgbe_get_netdev_tc_txq(dev, tc) (&netdev_extended(dev)->qos_data.tc_to_txq[tc])
+#endif
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) )
+/* NOTE: the order of parameters to _kc_alloc_workqueue() is different than
+ * alloc_workqueue() to avoid compiler warning from -Wvarargs
+ */
+static inline struct workqueue_struct * __attribute__ ((format(printf, 3, 4)))
+_kc_alloc_workqueue(__maybe_unused int flags, __maybe_unused int max_active,
+		    const char *fmt, ...)
+{
+	struct workqueue_struct *wq;
+	va_list args, temp;
+	unsigned int len;
+	char *p;
+
+	va_start(args, fmt);
+	va_copy(temp, args);
+	len = vsnprintf(NULL, 0, fmt, temp);
+	va_end(temp);
+
+	p = kmalloc(len + 1, GFP_KERNEL);
+	if (!p) {
+		va_end(args);
+		return NULL;
+	}
+
+	vsnprintf(p, len + 1, fmt, args);
+	va_end(args);
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) )
+	wq = create_workqueue(p);
+#else
+	wq = alloc_workqueue(p, flags, max_active);
+#endif
+	kfree(p);
+
+	return wq;
+}
+#ifdef alloc_workqueue
+#undef alloc_workqueue
+#endif
+#define alloc_workqueue(fmt, flags, max_active, args...) \
+	_kc_alloc_workqueue(flags, max_active, fmt, ##args)
+
+#if !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,5))
+typedef u32 netdev_features_t;
+#endif
+#undef PCI_EXP_TYPE_RC_EC
+#define  PCI_EXP_TYPE_RC_EC	0xa	/* Root Complex Event Collector */
+#ifndef CONFIG_BQL
+#define netdev_tx_completed_queue(_q, _p, _b) do {} while (0)
+#define netdev_completed_queue(_n, _p, _b) do {} while (0)
+#define netdev_tx_sent_queue(_q, _b) do {} while (0)
+#define netdev_sent_queue(_n, _b) do {} while (0)
+#define netdev_tx_reset_queue(_q) do {} while (0)
+#define netdev_reset_queue(_n) do {} while (0)
+#endif
+#if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0))
+#define HAVE_ETHTOOL_GRXFHINDIR_SIZE
+#endif /* SLE_VERSION(11,3,0) */
+#define netif_xmit_stopped(_q) netif_tx_queue_stopped(_q)
+#if !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,4,0))
+static inline int __kc_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
+					u8 *nexthdrp,
+					__be16 __always_unused *frag_offp)
+{
+	return ipv6_skip_exthdr(skb, start, nexthdrp);
+}
+#undef ipv6_skip_exthdr
+#define ipv6_skip_exthdr(a,b,c,d) __kc_ipv6_skip_exthdr((a), (b), (c), (d))
+#endif /* !SLES11sp4 or greater */
+
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(11,3,0)))
+static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
+{
+	return index % n_rx_rings;
+}
+#endif
+
+#else /* ! < 3.3.0 */
+#define HAVE_ETHTOOL_GRXFHINDIR_SIZE
+#define HAVE_INT_NDO_VLAN_RX_ADD_VID
+#ifdef ETHTOOL_SRXNTUPLE
+#undef ETHTOOL_SRXNTUPLE
+#endif
+#endif /* < 3.3.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) )
+#ifndef NETIF_F_RXFCS
+#define NETIF_F_RXFCS	0
+#endif /* NETIF_F_RXFCS */
+#ifndef NETIF_F_RXALL
+#define NETIF_F_RXALL	0
+#endif /* NETIF_F_RXALL */
+
+#if !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0))
+#define NUMTCS_RETURNS_U8
+
+int _kc_simple_open(struct inode *inode, struct file *file);
+#define simple_open _kc_simple_open
+#endif /* !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0)) */
+
+#ifndef skb_add_rx_frag
+#define skb_add_rx_frag _kc_skb_add_rx_frag
+void _kc_skb_add_rx_frag(struct sk_buff * skb, int i, struct page *page,
+			 int off, int size, unsigned int truesize);
+#endif
+#ifdef NET_ADDR_RANDOM
+#define eth_hw_addr_random(N) do { \
+	eth_random_addr(N->dev_addr); \
+	N->addr_assign_type |= NET_ADDR_RANDOM; \
+	} while (0)
+#else /* NET_ADDR_RANDOM */
+#define eth_hw_addr_random(N) eth_random_addr(N->dev_addr)
+#endif /* NET_ADDR_RANDOM */
+
+#ifndef for_each_set_bit_from
+#define for_each_set_bit_from(bit, addr, size) \
+	for ((bit) = find_next_bit((addr), (size), (bit)); \
+			(bit) < (size); \
+			(bit) = find_next_bit((addr), (size), (bit) + 1))
+#endif /* for_each_set_bit_from */
+
+#else /* < 3.4.0 */
+#include <linux/kconfig.h>
+#endif /* >= 3.4.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) ) || \
+    ( RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4) )
+#if !defined(NO_PTP_SUPPORT) && IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+#define HAVE_PTP_1588_CLOCK
+#endif /* !NO_PTP_SUPPORT && IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
+#endif /* >= 3.0.0 || RHEL_RELEASE > 6.4 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) )
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#ifndef BITS_PER_LONG_LONG
+#define BITS_PER_LONG_LONG 64
+#endif
+
+#ifndef ether_addr_equal
+static inline bool __kc_ether_addr_equal(const u8 *addr1, const u8 *addr2)
+{
+	return !compare_ether_addr(addr1, addr2);
+}
+#define ether_addr_equal(_addr1, _addr2) __kc_ether_addr_equal((_addr1),(_addr2))
+#endif
+
+/* Definitions for !CONFIG_OF_NET are introduced in 3.10 */
+#ifdef CONFIG_OF_NET
+static inline int of_get_phy_mode(struct device_node __always_unused *np)
+{
+	return -ENODEV;
+}
+
+static inline const void *
+of_get_mac_address(struct device_node __always_unused *np)
+{
+	return NULL;
+}
+#endif
+#else
+#include <linux/of_net.h>
+#define HAVE_FDB_OPS
+#define HAVE_ETHTOOL_GET_TS_INFO
+#endif /* < 3.5.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) )
+#define PCI_EXP_LNKCAP2		44	/* Link Capability 2 */
+
+#ifndef MDIO_EEE_100TX
+#define MDIO_EEE_100TX		0x0002	/* 100TX EEE cap */
+#endif
+#ifndef MDIO_EEE_1000T
+#define MDIO_EEE_1000T		0x0004	/* 1000T EEE cap */
+#endif
+#ifndef MDIO_EEE_10GT
+#define MDIO_EEE_10GT		0x0008	/* 10GT EEE cap */
+#endif
+#ifndef MDIO_EEE_1000KX
+#define MDIO_EEE_1000KX		0x0010	/* 1000KX EEE cap */
+#endif
+#ifndef MDIO_EEE_10GKX4
+#define MDIO_EEE_10GKX4		0x0020	/* 10G KX4 EEE cap */
+#endif
+#ifndef MDIO_EEE_10GKR
+#define MDIO_EEE_10GKR		0x0040	/* 10G KR EEE cap */
+#endif
+
+#ifndef __GFP_MEMALLOC
+#define __GFP_MEMALLOC 0
+#endif
+
+#ifndef eth_broadcast_addr
+#define eth_broadcast_addr _kc_eth_broadcast_addr
+static inline void _kc_eth_broadcast_addr(u8 *addr)
+{
+	memset(addr, 0xff, ETH_ALEN);
+}
+#endif
+
+#ifndef eth_random_addr
+#define eth_random_addr _kc_eth_random_addr
+static inline void _kc_eth_random_addr(u8 *addr)
+{
+        get_random_bytes(addr, ETH_ALEN);
+        addr[0] &= 0xfe; /* clear multicast */
+        addr[0] |= 0x02; /* set local assignment */
+}
+#endif /* eth_random_addr */
+
+#ifndef DMA_ATTR_SKIP_CPU_SYNC
+#define DMA_ATTR_SKIP_CPU_SYNC 0
+#endif
+#else /* < 3.6.0 */
+#define HAVE_STRUCT_PAGE_PFMEMALLOC
+#endif /* < 3.6.0 */
+
+/******************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) )
+#include <linux/workqueue.h>
+#ifndef ADVERTISED_40000baseKR4_Full
+/* these defines were all added in one commit, so should be safe
+ * to trigger activiation on one define
+ */
+#define SUPPORTED_40000baseKR4_Full	BIT(23)
+#define SUPPORTED_40000baseCR4_Full	BIT(24)
+#define SUPPORTED_40000baseSR4_Full	BIT(25)
+#define SUPPORTED_40000baseLR4_Full	BIT(26)
+#define ADVERTISED_40000baseKR4_Full	BIT(23)
+#define ADVERTISED_40000baseCR4_Full	BIT(24)
+#define ADVERTISED_40000baseSR4_Full	BIT(25)
+#define ADVERTISED_40000baseLR4_Full	BIT(26)
+#endif
+
+#ifndef mmd_eee_cap_to_ethtool_sup_t
+/**
+ * mmd_eee_cap_to_ethtool_sup_t
+ * @eee_cap: value of the MMD EEE Capability register
+ *
+ * A small helper function that translates MMD EEE Capability (3.20) bits
+ * to ethtool supported settings.
+ */
+static inline u32 __kc_mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap)
+{
+	u32 supported = 0;
+
+	if (eee_cap & MDIO_EEE_100TX)
+		supported |= SUPPORTED_100baseT_Full;
+	if (eee_cap & MDIO_EEE_1000T)
+		supported |= SUPPORTED_1000baseT_Full;
+	if (eee_cap & MDIO_EEE_10GT)
+		supported |= SUPPORTED_10000baseT_Full;
+	if (eee_cap & MDIO_EEE_1000KX)
+		supported |= SUPPORTED_1000baseKX_Full;
+	if (eee_cap & MDIO_EEE_10GKX4)
+		supported |= SUPPORTED_10000baseKX4_Full;
+	if (eee_cap & MDIO_EEE_10GKR)
+		supported |= SUPPORTED_10000baseKR_Full;
+
+	return supported;
+}
+#define mmd_eee_cap_to_ethtool_sup_t(eee_cap) \
+	__kc_mmd_eee_cap_to_ethtool_sup_t(eee_cap)
+#endif /* mmd_eee_cap_to_ethtool_sup_t */
+
+#ifndef mmd_eee_adv_to_ethtool_adv_t
+/**
+ * mmd_eee_adv_to_ethtool_adv_t
+ * @eee_adv: value of the MMD EEE Advertisement/Link Partner Ability registers
+ *
+ * A small helper function that translates the MMD EEE Advertisement (7.60)
+ * and MMD EEE Link Partner Ability (7.61) bits to ethtool advertisement
+ * settings.
+ */
+static inline u32 __kc_mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv)
+{
+	u32 adv = 0;
+
+	if (eee_adv & MDIO_EEE_100TX)
+		adv |= ADVERTISED_100baseT_Full;
+	if (eee_adv & MDIO_EEE_1000T)
+		adv |= ADVERTISED_1000baseT_Full;
+	if (eee_adv & MDIO_EEE_10GT)
+		adv |= ADVERTISED_10000baseT_Full;
+	if (eee_adv & MDIO_EEE_1000KX)
+		adv |= ADVERTISED_1000baseKX_Full;
+	if (eee_adv & MDIO_EEE_10GKX4)
+		adv |= ADVERTISED_10000baseKX4_Full;
+	if (eee_adv & MDIO_EEE_10GKR)
+		adv |= ADVERTISED_10000baseKR_Full;
+
+	return adv;
+}
+
+#define mmd_eee_adv_to_ethtool_adv_t(eee_adv) \
+	__kc_mmd_eee_adv_to_ethtool_adv_t(eee_adv)
+#endif /* mmd_eee_adv_to_ethtool_adv_t */
+
+#ifndef ethtool_adv_to_mmd_eee_adv_t
+/**
+ * ethtool_adv_to_mmd_eee_adv_t
+ * @adv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement settings
+ * to EEE advertisements for the MMD EEE Advertisement (7.60) and
+ * MMD EEE Link Partner Ability (7.61) registers.
+ */
+static inline u16 __kc_ethtool_adv_to_mmd_eee_adv_t(u32 adv)
+{
+	u16 reg = 0;
+
+	if (adv & ADVERTISED_100baseT_Full)
+		reg |= MDIO_EEE_100TX;
+	if (adv & ADVERTISED_1000baseT_Full)
+		reg |= MDIO_EEE_1000T;
+	if (adv & ADVERTISED_10000baseT_Full)
+		reg |= MDIO_EEE_10GT;
+	if (adv & ADVERTISED_1000baseKX_Full)
+		reg |= MDIO_EEE_1000KX;
+	if (adv & ADVERTISED_10000baseKX4_Full)
+		reg |= MDIO_EEE_10GKX4;
+	if (adv & ADVERTISED_10000baseKR_Full)
+		reg |= MDIO_EEE_10GKR;
+
+	return reg;
+}
+#define ethtool_adv_to_mmd_eee_adv_t(adv) __kc_ethtool_adv_to_mmd_eee_adv_t(adv)
+#endif /* ethtool_adv_to_mmd_eee_adv_t */
+
+#ifndef pci_pcie_type
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) )
+static inline u8 pci_pcie_type(struct pci_dev *pdev)
+{
+	int pos;
+	u16 reg16;
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	BUG_ON(!pos);
+	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+	return (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+#else /* < 2.6.24 */
+#define pci_pcie_type(x)	(x)->pcie_type
+#endif /* < 2.6.24 */
+#endif /* pci_pcie_type */
+
+#if ( ! ( RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4) ) ) && \
+    ( ! ( SLE_VERSION_CODE >= SLE_VERSION(11,3,0) ) ) && \
+    ( LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) )
+#define ptp_clock_register(caps, args...) ptp_clock_register(caps)
+#endif
+
+#ifndef pcie_capability_read_word
+int __kc_pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
+#define pcie_capability_read_word(d,p,v) __kc_pcie_capability_read_word(d,p,v)
+#endif /* pcie_capability_read_word */
+
+#ifndef pcie_capability_read_dword
+int __kc_pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val);
+#define pcie_capability_read_dword(d,p,v) __kc_pcie_capability_read_dword(d,p,v)
+#endif
+
+#ifndef pcie_capability_write_word
+int __kc_pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val);
+#define pcie_capability_write_word(d,p,v) __kc_pcie_capability_write_word(d,p,v)
+#endif /* pcie_capability_write_word */
+
+#ifndef pcie_capability_clear_and_set_word
+int __kc_pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+					    u16 clear, u16 set);
+#define pcie_capability_clear_and_set_word(d,p,c,s) \
+	__kc_pcie_capability_clear_and_set_word(d,p,c,s)
+#endif /* pcie_capability_clear_and_set_word */
+
+#ifndef pcie_capability_clear_word
+int __kc_pcie_capability_clear_word(struct pci_dev *dev, int pos,
+					     u16 clear);
+#define pcie_capability_clear_word(d, p, c) \
+	__kc_pcie_capability_clear_word(d, p, c)
+#endif /* pcie_capability_clear_word */
+
+#ifndef PCI_EXP_LNKSTA2
+#define PCI_EXP_LNKSTA2		50	/* Link Status 2 */
+#endif
+
+#if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0))
+#define USE_CONST_DEV_UC_CHAR
+#define HAVE_NDO_FDB_ADD_NLATTR
+#endif
+
+#if !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,8))
+#define napi_gro_flush(_napi, _flush_old) napi_gro_flush(_napi)
+#endif /* !RHEL6.8+ */
+
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,6))
+#include <linux/hashtable.h>
+#else
+
+#define DEFINE_HASHTABLE(name, bits)						\
+	struct hlist_head name[1 << (bits)] =					\
+			{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
+
+#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits)				\
+	struct hlist_head name[1 << (bits)] __read_mostly =			\
+			{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
+
+#define DECLARE_HASHTABLE(name, bits)                                   	\
+	struct hlist_head name[1 << (bits)]
+
+#define HASH_SIZE(name) (ARRAY_SIZE(name))
+#define HASH_BITS(name) ilog2(HASH_SIZE(name))
+
+/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
+#define hash_min(val, bits)							\
+	(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
+
+static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
+{
+	unsigned int i;
+
+	for (i = 0; i < sz; i++)
+		INIT_HLIST_HEAD(&ht[i]);
+}
+
+#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
+
+#define hash_add(hashtable, node, key)						\
+	hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
+
+static inline bool hash_hashed(struct hlist_node *node)
+{
+	return !hlist_unhashed(node);
+}
+
+static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
+{
+	unsigned int i;
+
+	for (i = 0; i < sz; i++)
+		if (!hlist_empty(&ht[i]))
+			return false;
+
+	return true;
+}
+
+#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
+
+static inline void hash_del(struct hlist_node *node)
+{
+	hlist_del_init(node);
+}
+#endif /* RHEL >= 6.6 */
+
+/* We don't have @flags support prior to 3.7, so we'll simply ignore the flags
+ * parameter on these older kernels.
+ */
+#define __setup_timer(_timer, _fn, _data, _flags)	\
+	setup_timer((_timer), (_fn), (_data))		\
+
+#if ( ! ( RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) ) ) && \
+	( ! ( SLE_VERSION_CODE >= SLE_VERSION(12,0,0) ) )
+
+#ifndef mod_delayed_work
+/**
+ * __mod_delayed_work - modify delay or queue delayed work
+ * @wq: workqueue to use
+ * @dwork: delayed work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * Return: %true if @dwork was pending and was rescheduled;
+ *         %false if it wasn't pending
+ *
+ * Note: the dwork parameter was declared as a void*
+ *       to avoid comptibility problems with early 2.6 kernels
+ *       where struct delayed_work is not declared. Unlike the original
+ *       implementation flags are not preserved and it shouldn't be
+ *       used in the interrupt context.
+ */
+static inline bool __mod_delayed_work(struct workqueue_struct *wq,
+				    void *dwork,
+				    unsigned long delay)
+{
+	bool ret = cancel_delayed_work(dwork);
+	queue_delayed_work(wq, dwork, delay);
+	return ret;
+}
+#define mod_delayed_work(wq, dwork, delay) __mod_delayed_work(wq, dwork, delay)
+#endif /* mod_delayed_work */
+
+#endif /* !(RHEL >= 6.7) && !(SLE >= 12.0) */
+#else /* >= 3.7.0 */
+#include <linux/hashtable.h>
+#define HAVE_CONST_STRUCT_PCI_ERROR_HANDLERS
+#define USE_CONST_DEV_UC_CHAR
+#define HAVE_NDO_FDB_ADD_NLATTR
+#endif /* >= 3.7.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) )
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,5)) && \
+     !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,4,0)))
+#ifndef pci_sriov_set_totalvfs
+static inline int __kc_pci_sriov_set_totalvfs(struct pci_dev __always_unused *dev, u16 __always_unused numvfs)
+{
+	return 0;
+}
+#define pci_sriov_set_totalvfs(a, b) __kc_pci_sriov_set_totalvfs((a), (b))
+#endif
+#endif /* !(RHEL_RELEASE_CODE >= 6.5 && SLE_VERSION_CODE >= 11.4) */
+#ifndef PCI_EXP_LNKCTL_ASPM_L0S
+#define  PCI_EXP_LNKCTL_ASPM_L0S  0x01	/* L0s Enable */
+#endif
+#ifndef PCI_EXP_LNKCTL_ASPM_L1
+#define  PCI_EXP_LNKCTL_ASPM_L1   0x02	/* L1 Enable */
+#endif
+#define HAVE_CONFIG_HOTPLUG
+/* Reserved Ethernet Addresses per IEEE 802.1Q */
+static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) = {
+	0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+
+#ifndef is_link_local_ether_addr
+static inline bool __kc_is_link_local_ether_addr(const u8 *addr)
+{
+	__be16 *a = (__be16 *)addr;
+	static const __be16 *b = (const __be16 *)eth_reserved_addr_base;
+	static const __be16 m = cpu_to_be16(0xfff0);
+
+	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
+}
+#define is_link_local_ether_addr(addr) __kc_is_link_local_ether_addr(addr)
+#endif /* is_link_local_ether_addr */
+
+#ifndef FLOW_MAC_EXT
+#define FLOW_MAC_EXT	0x40000000
+#endif /* FLOW_MAC_EXT */
+
+#if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,4,0))
+#define HAVE_SRIOV_CONFIGURE
+#endif
+
+#ifndef PCI_EXP_LNKCAP_SLS_2_5GB
+#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
+#endif
+
+#ifndef PCI_EXP_LNKCAP_SLS_5_0GB
+#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
+#endif
+
+#undef PCI_EXP_LNKCAP2_SLS_2_5GB
+#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */
+
+#undef PCI_EXP_LNKCAP2_SLS_5_0GB
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */
+
+#undef PCI_EXP_LNKCAP2_SLS_8_0GB
+#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
+
+#else /* >= 3.8.0 */
+#ifndef __devinit
+#define __devinit
+#endif
+
+#ifndef __devinitdata
+#define __devinitdata
+#endif
+
+#ifndef __devinitconst
+#define __devinitconst
+#endif
+
+#ifndef __devexit
+#define __devexit
+#endif
+
+#ifndef __devexit_p
+#define __devexit_p
+#endif
+
+#ifndef HAVE_ENCAP_CSUM_OFFLOAD
+#define HAVE_ENCAP_CSUM_OFFLOAD
+#endif
+
+#ifndef HAVE_GRE_ENCAP_OFFLOAD
+#define HAVE_GRE_ENCAP_OFFLOAD
+#endif
+
+#ifndef HAVE_SRIOV_CONFIGURE
+#define HAVE_SRIOV_CONFIGURE 
+#endif
+
+#define HAVE_BRIDGE_ATTRIBS
+#ifndef BRIDGE_MODE_VEB
+#define BRIDGE_MODE_VEB		0	/* Default loopback mode */
+#endif /* BRIDGE_MODE_VEB */
+#ifndef BRIDGE_MODE_VEPA
+#define BRIDGE_MODE_VEPA	1	/* 802.1Qbg defined VEPA mode */
+#endif /* BRIDGE_MODE_VEPA */
+#endif /* >= 3.8.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) )
+
+#undef BUILD_BUG_ON
+#ifdef __CHECKER__
+#define BUILD_BUG_ON(condition) (0)
+#else /* __CHECKER__ */
+#ifndef __compiletime_warning
+#if defined(__GNUC__) && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40400)
+#define __compiletime_warning(message) __attribute__((warning(message)))
+#else /* __GNUC__ */
+#define __compiletime_warning(message)
+#endif /* __GNUC__ */
+#endif /* __compiletime_warning */
+#ifndef __compiletime_error
+#if defined(__GNUC__) && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40400)
+#define __compiletime_error(message) __attribute__((error(message)))
+#define __compiletime_error_fallback(condition) do { } while (0)
+#else /* __GNUC__ */
+#define __compiletime_error(message)
+#define __compiletime_error_fallback(condition) \
+	do { ((void)sizeof(char[1 - 2 * condition])); } while (0)
+#endif /* __GNUC__ */
+#else /* __compiletime_error */
+#define __compiletime_error_fallback(condition) do { } while (0)
+#endif /* __compiletime_error */
+#define __compiletime_assert(condition, msg, prefix, suffix)		\
+	do {								\
+		bool __cond = !(condition);				\
+		extern void prefix ## suffix(void) __compiletime_error(msg); \
+		if (__cond)						\
+			prefix ## suffix();				\
+		__compiletime_error_fallback(__cond);			\
+	} while (0)
+
+#define _compiletime_assert(condition, msg, prefix, suffix) \
+	__compiletime_assert(condition, msg, prefix, suffix)
+#define compiletime_assert(condition, msg) \
+	_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
+#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else /* __OPTIMIZE__ */
+#define BUILD_BUG_ON(condition) \
+	BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
+#endif /* __OPTIMIZE__ */
+#endif /* __CHECKER__ */
+
+#undef hlist_entry
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#undef hlist_entry_safe
+#define hlist_entry_safe(ptr, type, member) \
+	({ typeof(ptr) ____ptr = (ptr); \
+	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+	})
+
+#undef hlist_for_each_entry
+#define hlist_for_each_entry(pos, head, member)                             \
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \
+	     pos;                                                           \
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#undef hlist_for_each_entry_safe
+#define hlist_for_each_entry_safe(pos, n, head, member) 		    \
+	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);   \
+	     pos && ({ n = pos->member.next; 1; });			    \
+	     pos = hlist_entry_safe(n, typeof(*pos), member))
+
+#undef hlist_for_each_entry_continue
+#define hlist_for_each_entry_continue(pos, member)			\
+	for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
+	     pos;							\
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#undef hlist_for_each_entry_from
+#define hlist_for_each_entry_from(pos, member)				\
+	for (; pos;							\
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#undef hash_for_each
+#define hash_for_each(name, bkt, obj, member)				\
+	for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
+			(bkt)++)\
+		hlist_for_each_entry(obj, &name[bkt], member)
+
+#undef hash_for_each_safe
+#define hash_for_each_safe(name, bkt, tmp, obj, member)			\
+	for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
+			(bkt)++)\
+		hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
+
+#undef hash_for_each_possible
+#define hash_for_each_possible(name, obj, member, key)			\
+	hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)
+
+#undef hash_for_each_possible_safe
+#define hash_for_each_possible_safe(name, obj, tmp, member, key)	\
+	hlist_for_each_entry_safe(obj, tmp,\
+		&name[hash_min(key, HASH_BITS(name))], member)
+
+#ifdef CONFIG_XPS
+int __kc_netif_set_xps_queue(struct net_device *, const struct cpumask *, u16);
+#define netif_set_xps_queue(_dev, _mask, _idx) __kc_netif_set_xps_queue((_dev), (_mask), (_idx))
+#else /* CONFIG_XPS */
+#define netif_set_xps_queue(_dev, _mask, _idx) do {} while (0)
+#endif /* CONFIG_XPS */
+
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#define _kc_hashrnd 0xd631614b /* not so random hash salt */
+u16 __kc_netdev_pick_tx(struct net_device *dev, struct sk_buff *skb);
+#define __netdev_pick_tx __kc_netdev_pick_tx
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+#else
+#define HAVE_BRIDGE_FILTER
+#define HAVE_FDB_DEL_NLATTR
+#endif /* < 3.9.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) )
+#ifndef NAPI_POLL_WEIGHT
+#define NAPI_POLL_WEIGHT 64
+#endif
+#ifdef CONFIG_PCI_IOV
+int __kc_pci_vfs_assigned(struct pci_dev *dev);
+#else
+static inline int __kc_pci_vfs_assigned(struct pci_dev __always_unused *dev)
+{
+	return 0;
+}
+#endif
+#define pci_vfs_assigned(dev) __kc_pci_vfs_assigned(dev)
+
+#ifndef list_first_entry_or_null
+#define list_first_entry_or_null(ptr, type, member) \
+	(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+#endif
+
+#ifndef VLAN_TX_COOKIE_MAGIC
+static inline struct sk_buff *__kc__vlan_hwaccel_put_tag(struct sk_buff *skb,
+							 u16 vlan_tci)
+{
+#ifdef VLAN_TAG_PRESENT
+	vlan_tci |= VLAN_TAG_PRESENT;
+#endif
+	skb->vlan_tci = vlan_tci;
+        return skb;
+}
+#define __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci) \
+	__kc__vlan_hwaccel_put_tag(skb, vlan_tci)
+#endif
+
+#ifdef HAVE_FDB_OPS
+#if defined(HAVE_NDO_FDB_ADD_NLATTR)
+int __kc_ndo_dflt_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			  struct net_device *dev,
+			  const unsigned char *addr, u16 flags);
+#elif defined(USE_CONST_DEV_UC_CHAR)
+int __kc_ndo_dflt_fdb_add(struct ndmsg *ndm, struct net_device *dev,
+			  const unsigned char *addr, u16 flags);
+#else
+int __kc_ndo_dflt_fdb_add(struct ndmsg *ndm, struct net_device *dev,
+			  unsigned char *addr, u16 flags);
+#endif /* HAVE_NDO_FDB_ADD_NLATTR */
+#if defined(HAVE_FDB_DEL_NLATTR)
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+			  struct net_device *dev,
+			  const unsigned char *addr);
+#elif defined(USE_CONST_DEV_UC_CHAR)
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct net_device *dev,
+			  const unsigned char *addr);
+#else
+int __kc_ndo_dflt_fdb_del(struct ndmsg *ndm, struct net_device *dev,
+			  unsigned char *addr);
+#endif /* HAVE_FDB_DEL_NLATTR */
+#define ndo_dflt_fdb_add __kc_ndo_dflt_fdb_add
+#define ndo_dflt_fdb_del __kc_ndo_dflt_fdb_del
+#endif /* HAVE_FDB_OPS */
+
+#ifndef PCI_DEVID
+#define PCI_DEVID(bus, devfn)  ((((u16)(bus)) << 8) | (devfn))
+#endif
+
+/* The definitions for these functions when CONFIG_OF_NET is defined are
+ * pulled in from <linux/of_net.h>. For kernels older than 3.5 we already have
+ * backports for when CONFIG_OF_NET is true. These are separated and
+ * duplicated in order to cover all cases so that all kernels get either the
+ * real definitions (when CONFIG_OF_NET is defined) or the stub definitions
+ * (when CONFIG_OF_NET is not defined, or the kernel is too old to have real
+ * definitions).
+ */
+#ifndef CONFIG_OF_NET
+static inline int of_get_phy_mode(struct device_node __always_unused *np)
+{
+	return -ENODEV;
+}
+
+static inline const void *
+of_get_mac_address(struct device_node __always_unused *np)
+{
+	return NULL;
+}
+#endif
+
+#else /* >= 3.10.0 */
+#define HAVE_ENCAP_TSO_OFFLOAD
+#define USE_DEFAULT_FDB_DEL_DUMP
+#define HAVE_SKB_INNER_NETWORK_HEADER
+#if (RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)))
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0))
+#define HAVE_RHEL7_PCI_DRIVER_RH
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2))
+#define HAVE_RHEL7_PCI_RESET_NOTIFY
+#endif /* RHEL >= 7.2 */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3))
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5))
+#define HAVE_GENEVE_RX_OFFLOAD
+#endif /* RHEL < 7.5 */
+#define HAVE_ETHTOOL_FLOW_UNION_IP6_SPEC
+#if defined(__aarch64__)
+#else
+#ifndef CONFIG_PPC64
+#define HAVE_RHEL7_NET_DEVICE_OPS_EXT
+#endif
+#endif
+#if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_GENEVE)
+#define HAVE_UDP_ENC_TUNNEL
+#endif /* !HAVE_UDP_ENC_TUNNEL && CONFIG_GENEVE */
+#endif /* RHEL >= 7.3 */
+
+/* new hooks added to net_device_ops_extended in RHEL7.4 */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 4))
+#if defined (__aarch64__)
+#else
+#ifndef CONFIG_PPC64
+#define HAVE_RHEL7_NETDEV_OPS_EXT_NDO_SET_VF_VLAN
+#define HAVE_RHEL7_NETDEV_OPS_EXT_NDO_UDP_TUNNEL
+#define HAVE_UDP_ENC_RX_OFFLOAD
+#endif
+#endif
+#endif /* RHEL >= 7.4 */
+#else  /* RHEL >= 8.0 */
+#define HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+#define NO_NETDEV_BPF_PROG_ATTACHED
+#define HAVE_NDO_SELECT_QUEUE_SB_DEV
+#endif /* RHEL >= 8.0 */
+#endif /* RHEL >= 7.0 */
+#endif /* >= 3.10.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) )
+#define netdev_notifier_info_to_dev(ptr) ptr
+#ifndef time_in_range64
+#define time_in_range64(a, b, c) \
+	(time_after_eq64(a, b) && \
+	 time_before_eq64(a, c))
+#endif /* time_in_range64 */
+#if ((RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,11)) ||\
+     (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,4,0)))
+#define HAVE_NDO_SET_VF_LINK_STATE
+#elif (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,5))
+#else
+enum {
+	IFLA_VF_LINK_STATE_AUTO,	/* link state of the uplink */
+	IFLA_VF_LINK_STATE_ENABLE,	/* link always up */
+	IFLA_VF_LINK_STATE_DISABLE,	/* link always down */
+	__IFLA_VF_LINK_STATE_MAX,
+};
+#endif
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+#define HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK
+#endif
+#else /* >= 3.11.0 */
+#define HAVE_NDO_SET_VF_LINK_STATE
+#define HAVE_SKB_INNER_PROTOCOL
+#define HAVE_MPLS_FEATURES
+#endif /* >= 3.11.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) )
+int __kc_pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
+			       enum pcie_link_width *width);
+#ifndef pcie_get_minimum_link
+#define pcie_get_minimum_link(_p, _s, _w) __kc_pcie_get_minimum_link(_p, _s, _w)
+#endif
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,7))
+int _kc_pci_wait_for_pending_transaction(struct pci_dev *dev);
+#define pci_wait_for_pending_transaction _kc_pci_wait_for_pending_transaction
+#endif /* <RHEL6.7 */
+
+#else /* >= 3.12.0 */
+#if ( SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,0,0))
+#define HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK
+#endif
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) )
+#define HAVE_VXLAN_RX_OFFLOAD
+#if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_VXLAN)
+#define HAVE_UDP_ENC_TUNNEL
+#endif
+#endif /* < 4.8.0 */
+#define HAVE_NDO_GET_PHYS_PORT_ID
+#define HAVE_NETIF_SET_XPS_QUEUE_CONST_MASK
+#endif /* >= 3.12.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) )
+#define dma_set_mask_and_coherent(_p, _m) __kc_dma_set_mask_and_coherent(_p, _m)
+int __kc_dma_set_mask_and_coherent(struct device *dev, u64 mask);
+#ifndef u64_stats_init
+#define u64_stats_init(a) do { } while(0)
+#endif
+#undef BIT_ULL
+#define BIT_ULL(n) (1ULL << (n))
+
+#if (!(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,0,0)) && \
+     !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)))
+static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
+{
+	dev = pci_physfn(dev);
+	if (pci_is_root_bus(dev->bus))
+		return NULL;
+
+	return dev->bus->self;
+}
+#endif
+
+#if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,1,0))
+#undef HAVE_STRUCT_PAGE_PFMEMALLOC
+#define HAVE_DCBNL_OPS_SETAPP_RETURN_INT
+#endif
+#ifndef list_next_entry
+#define list_next_entry(pos, member) \
+	list_entry((pos)->member.next, typeof(*(pos)), member)
+#endif
+#ifndef list_prev_entry
+#define list_prev_entry(pos, member) \
+	list_entry((pos)->member.prev, typeof(*(pos)), member)
+#endif
+
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20) )
+#define devm_kcalloc(dev, cnt, size, flags) \
+	devm_kzalloc(dev, cnt * size, flags)
+#endif /* > 2.6.20 */
+
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)))
+#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member)
+#endif
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0))
+bool _kc_pci_device_is_present(struct pci_dev *pdev);
+#define pci_device_is_present _kc_pci_device_is_present
+#endif /* <RHEL7.0 */
+#else /* >= 3.13.0 */
+#define HAVE_VXLAN_CHECKS
+#if (UBUNTU_VERSION_CODE && UBUNTU_VERSION_CODE >= UBUNTU_VERSION(3,13,0,24))
+#define HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK
+#else
+#define HAVE_NDO_SELECT_QUEUE_ACCEL
+#endif
+#define HAVE_HWMON_DEVICE_REGISTER_WITH_GROUPS
+#endif
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) )
+
+#ifndef U16_MAX
+#define U16_MAX ((u16)~0U)
+#endif
+
+#ifndef U32_MAX
+#define U32_MAX ((u32)~0U)
+#endif
+
+#ifndef U64_MAX
+#define U64_MAX ((u64)~0ULL)
+#endif
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)))
+#define dev_consume_skb_any(x) dev_kfree_skb_any(x)
+#define dev_consume_skb_irq(x) dev_kfree_skb_irq(x)
+#endif
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)) && \
+     !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,0,0)))
+
+/* it isn't expected that this would be a #define unless we made it so */
+#ifndef skb_set_hash
+
+#define PKT_HASH_TYPE_NONE	0
+#define PKT_HASH_TYPE_L2	1
+#define PKT_HASH_TYPE_L3	2
+#define PKT_HASH_TYPE_L4	3
+
+enum _kc_pkt_hash_types {
+	_KC_PKT_HASH_TYPE_NONE = PKT_HASH_TYPE_NONE,
+	_KC_PKT_HASH_TYPE_L2 = PKT_HASH_TYPE_L2,
+	_KC_PKT_HASH_TYPE_L3 = PKT_HASH_TYPE_L3,
+	_KC_PKT_HASH_TYPE_L4 = PKT_HASH_TYPE_L4,
+};
+#define pkt_hash_types         _kc_pkt_hash_types
+
+#define skb_set_hash __kc_skb_set_hash
+static inline void __kc_skb_set_hash(struct sk_buff __maybe_unused *skb,
+				     u32 __maybe_unused hash,
+				     int __maybe_unused type)
+{
+#ifdef HAVE_SKB_L4_RXHASH
+	skb->l4_rxhash = (type == PKT_HASH_TYPE_L4);
+#endif
+#ifdef NETIF_F_RXHASH
+	skb->rxhash = hash;
+#endif
+}
+#endif /* !skb_set_hash */
+
+#else	/* RHEL_RELEASE_CODE >= 7.0 || SLE_VERSION_CODE >= 12.0 */
+
+#if ((RHEL_RELEASE_CODE && RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,0)) ||\
+     (SLE_VERSION_CODE && SLE_VERSION_CODE <= SLE_VERSION(12,1,0)))
+/* GPLv2 code taken from 5.10-rc2 kernel source include/linux/pci.h, Copyright
+ * original authors.
+ */
+#if 0
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+					struct msix_entry *entries, int nvec)
+{
+	int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
+	if (rc < 0)
+		return rc;
+	return 0;
+}
+#endif
+#endif /* <=EL7.0 || <=SLES 12.1 */
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#ifndef HAVE_VXLAN_RX_OFFLOAD
+#define HAVE_VXLAN_RX_OFFLOAD
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+#endif
+
+#if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_VXLAN)
+#define HAVE_UDP_ENC_TUNNEL
+#endif
+
+#ifndef HAVE_VXLAN_CHECKS
+#define HAVE_VXLAN_CHECKS
+#endif /* HAVE_VXLAN_CHECKS */
+#endif /* !(RHEL_RELEASE_CODE >= 7.0 && SLE_VERSION_CODE >= 12.0) */
+
+#if ((RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)) ||\
+     (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,0,0)))
+#define HAVE_NDO_DFWD_OPS
+#endif
+
+#ifndef pci_enable_msix_range
+int __kc_pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
+			       int minvec, int maxvec);
+#define pci_enable_msix_range __kc_pci_enable_msix_range
+#endif
+
+#ifndef ether_addr_copy
+#define ether_addr_copy __kc_ether_addr_copy
+static inline void __kc_ether_addr_copy(u8 *dst, const u8 *src)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+	*(u32 *)dst = *(const u32 *)src;
+	*(u16 *)(dst + 4) = *(const u16 *)(src + 4);
+#else
+	u16 *a = (u16 *)dst;
+	const u16 *b = (const u16 *)src;
+
+	a[0] = b[0];
+	a[1] = b[1];
+	a[2] = b[2];
+#endif
+}
+#endif /* ether_addr_copy */
+int __kc_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
+		       int target, unsigned short *fragoff, int *flags);
+#define ipv6_find_hdr(a, b, c, d, e) __kc_ipv6_find_hdr((a), (b), (c), (d), (e))
+
+#ifndef OPTIMIZE_HIDE_VAR
+#ifdef __GNUC__
+#define OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "=r" (var) : "0" (var))
+#else
+#include <linux/barrier.h>
+#define OPTIMIZE_HIDE_VAR(var)	barrier()
+#endif
+#endif
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,0)) && \
+     !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(10,4,0)))
+static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
+{
+#ifdef NETIF_F_RXHASH
+	return skb->rxhash;
+#else
+	return 0;
+#endif /* NETIF_F_RXHASH */
+}
+#endif /* !RHEL > 5.9 && !SLES >= 10.4 */
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5))
+#define request_firmware_direct	request_firmware
+#endif /* !RHEL || RHEL < 7.5 */
+
+#else /* >= 3.14.0 */
+
+/* for ndo_dfwd_ ops add_station, del_station and _start_xmit */
+#ifndef HAVE_NDO_DFWD_OPS
+#define HAVE_NDO_DFWD_OPS
+#endif
+#define HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK
+#endif /* 3.14.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0) )
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) )
+#define HAVE_SKBUFF_RXHASH
+#endif /* >= 2.6.35 */
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,1)) && \
+     !(UBUNTU_VERSION_CODE && UBUNTU_VERSION_CODE >= UBUNTU_VERSION(3,13,0,30)))
+#define u64_stats_fetch_begin_irq u64_stats_fetch_begin_bh
+#define u64_stats_fetch_retry_irq u64_stats_fetch_retry_bh
+#endif
+
+char *_kc_devm_kstrdup(struct device *dev, const char *s, gfp_t gfp);
+#define devm_kstrdup(dev, s, gfp) _kc_devm_kstrdup(dev, s, gfp)
+
+#else /* >= 3.15.0 */
+#define HAVE_NET_GET_RANDOM_ONCE
+#define HAVE_PTP_1588_CLOCK_PINS
+#define HAVE_NETDEV_PORT
+#endif /* 3.15.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) )
+#ifndef smp_mb__before_atomic
+#define smp_mb__before_atomic() smp_mb()
+#define smp_mb__after_atomic()  smp_mb()
+#endif
+#ifndef __dev_uc_sync
+#ifdef HAVE_SET_RX_MODE
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+int __kc_hw_addr_sync_dev(struct netdev_hw_addr_list *list,
+		struct net_device *dev,
+		int (*sync)(struct net_device *, const unsigned char *),
+		int (*unsync)(struct net_device *, const unsigned char *));
+void __kc_hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
+		struct net_device *dev,
+		int (*unsync)(struct net_device *, const unsigned char *));
+#endif
+#ifndef NETDEV_HW_ADDR_T_MULTICAST
+int __kc_dev_addr_sync_dev(struct dev_addr_list **list, int *count,
+		struct net_device *dev,
+		int (*sync)(struct net_device *, const unsigned char *),
+		int (*unsync)(struct net_device *, const unsigned char *));
+void __kc_dev_addr_unsync_dev(struct dev_addr_list **list, int *count,
+		struct net_device *dev,
+		int (*unsync)(struct net_device *, const unsigned char *));
+#endif
+#endif /* HAVE_SET_RX_MODE */
+
+static inline int __kc_dev_uc_sync(struct net_device __maybe_unused *dev,
+				   int __maybe_unused (*sync)(struct net_device *, const unsigned char *),
+				   int __maybe_unused (*unsync)(struct net_device *, const unsigned char *))
+{
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+	return __kc_hw_addr_sync_dev(&dev->uc, dev, sync, unsync);
+#elif defined(HAVE_SET_RX_MODE)
+	return __kc_dev_addr_sync_dev(&dev->uc_list, &dev->uc_count,
+				      dev, sync, unsync);
+#else
+	return 0;
+#endif
+}
+#define __dev_uc_sync __kc_dev_uc_sync
+
+static inline void __kc_dev_uc_unsync(struct net_device __maybe_unused *dev,
+				      int __maybe_unused (*unsync)(struct net_device *, const unsigned char *))
+{
+#ifdef HAVE_SET_RX_MODE
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+	__kc_hw_addr_unsync_dev(&dev->uc, dev, unsync);
+#else /* NETDEV_HW_ADDR_T_MULTICAST */
+	__kc_dev_addr_unsync_dev(&dev->uc_list, &dev->uc_count, dev, unsync);
+#endif /* NETDEV_HW_ADDR_T_UNICAST */
+#endif /* HAVE_SET_RX_MODE */
+}
+#define __dev_uc_unsync __kc_dev_uc_unsync
+
+static inline int __kc_dev_mc_sync(struct net_device __maybe_unused *dev,
+				   int __maybe_unused (*sync)(struct net_device *, const unsigned char *),
+				   int __maybe_unused (*unsync)(struct net_device *, const unsigned char *))
+{
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+	return __kc_hw_addr_sync_dev(&dev->mc, dev, sync, unsync);
+#elif defined(HAVE_SET_RX_MODE)
+	return __kc_dev_addr_sync_dev(&dev->mc_list, &dev->mc_count,
+				      dev, sync, unsync);
+#else
+	return 0;
+#endif
+
+}
+#define __dev_mc_sync __kc_dev_mc_sync
+
+static inline void __kc_dev_mc_unsync(struct net_device __maybe_unused *dev,
+				      int __maybe_unused (*unsync)(struct net_device *, const unsigned char *))
+{
+#ifdef HAVE_SET_RX_MODE
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+	__kc_hw_addr_unsync_dev(&dev->mc, dev, unsync);
+#else /* NETDEV_HW_ADDR_T_MULTICAST */
+	__kc_dev_addr_unsync_dev(&dev->mc_list, &dev->mc_count, dev, unsync);
+#endif /* NETDEV_HW_ADDR_T_MULTICAST */
+#endif /* HAVE_SET_RX_MODE */
+}
+#define __dev_mc_unsync __kc_dev_mc_unsync
+#endif /* __dev_uc_sync */
+
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,1))
+#define HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+#endif
+
+#ifndef NETIF_F_GSO_UDP_TUNNEL_CSUM
+/* if someone backports this, hopefully they backport as a #define.
+ * declare it as zero on older kernels so that if it get's or'd in
+ * it won't effect anything, therefore preventing core driver changes
+ */
+#define NETIF_F_GSO_UDP_TUNNEL_CSUM 0
+#define SKB_GSO_UDP_TUNNEL_CSUM 0
+#endif
+void *__kc_devm_kmemdup(struct device *dev, const void *src, size_t len,
+			gfp_t gfp);
+#define devm_kmemdup __kc_devm_kmemdup
+
+#else
+#if ( ( LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0) ) && \
+      ! ( SLE_VERSION_CODE && ( SLE_VERSION_CODE >= SLE_VERSION(12,4,0)) ) )
+#define HAVE_PCI_ERROR_HANDLER_RESET_NOTIFY
+#endif /* >= 3.16.0 && < 4.13.0 && !(SLES >= 12sp4) */
+#define HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+#endif /* 3.16.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) )
+#if !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,8) && \
+      RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) && \
+    !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2))
+#ifndef timespec64
+#define timespec64 timespec
+static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
+{
+	return ts;
+}
+static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
+{
+	return ts64;
+}
+#define timespec64_equal timespec_equal
+#define timespec64_compare timespec_compare
+#define set_normalized_timespec64 set_normalized_timespec
+#define timespec64_add_safe timespec_add_safe
+#define timespec64_add timespec_add
+#define timespec64_sub timespec_sub
+#define timespec64_valid timespec_valid
+#define timespec64_valid_strict timespec_valid_strict
+#define timespec64_to_ns timespec_to_ns
+#define ns_to_timespec64 ns_to_timespec
+#define ktime_to_timespec64 ktime_to_timespec
+#define ktime_get_ts64 ktime_get_ts
+#define ktime_get_real_ts64 ktime_get_real_ts
+#define timespec64_add_ns timespec_add_ns
+#endif /* timespec64 */
+#endif /* !(RHEL6.8<RHEL7.0) && !RHEL7.2+ */
+
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,8) && \
+     RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0))
+static inline void ktime_get_real_ts64(struct timespec64 *ts)
+{
+	*ts = ktime_to_timespec64(ktime_get_real());
+}
+
+static inline void ktime_get_ts64(struct timespec64 *ts)
+{
+	*ts = ktime_to_timespec64(ktime_get());
+}
+#endif
+
+#if !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+#define hlist_add_behind(_a, _b) hlist_add_after(_b, _a)
+#endif
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5))
+#endif /* RHEL_RELEASE_CODE < RHEL7.5 */
+
+#if RHEL_RELEASE_CODE && \
+	RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,3) && \
+	RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,3)
+static inline u64 ktime_get_ns(void)
+{
+	return ktime_to_ns(ktime_get());
+}
+
+static inline u64 ktime_get_real_ns(void)
+{
+	return ktime_to_ns(ktime_get_real());
+}
+
+static inline u64 ktime_get_boot_ns(void)
+{
+	return ktime_to_ns(ktime_get_boottime());
+}
+#endif /* RHEL < 7.3 */
+
+#else
+#define HAVE_DCBNL_OPS_SETAPP_RETURN_INT
+#include <linux/time64.h>
+#define HAVE_RHASHTABLE
+#endif /* 3.17.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) )
+#ifndef NO_PTP_SUPPORT
+#include <linux/errqueue.h>
+struct sk_buff *__kc_skb_clone_sk(struct sk_buff *skb);
+void __kc_skb_complete_tx_timestamp(struct sk_buff *skb,
+				    struct skb_shared_hwtstamps *hwtstamps);
+#define skb_clone_sk __kc_skb_clone_sk
+#define skb_complete_tx_timestamp __kc_skb_complete_tx_timestamp
+#endif
+#if (!(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2))))
+u32 __kc_eth_get_headlen(const struct net_device *dev, unsigned char *data,
+			 unsigned int max_len);
+#else
+unsigned int __kc_eth_get_headlen(unsigned char *data, unsigned int max_len);
+#endif /* !RHEL >= 8.2 */
+
+#define eth_get_headlen __kc_eth_get_headlen
+#ifndef ETH_P_XDSA
+#define ETH_P_XDSA 0x00F8
+#endif
+/* RHEL 7.1 backported csum_level, but SLES 12 and 12-SP1 did not */
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,1))
+#define HAVE_SKBUFF_CSUM_LEVEL
+#endif /* >= RH 7.1 */
+
+/* RHEL 7.3 backported xmit_more */
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3))
+#define HAVE_SKB_XMIT_MORE
+#endif /* >= RH 7.3 */
+
+#undef GENMASK
+#define GENMASK(h, l) \
+	(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+#undef GENMASK_ULL
+#define GENMASK_ULL(h, l) \
+	(((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
+
+#else /*  3.18.0 */
+#define HAVE_SKBUFF_CSUM_LEVEL
+#define HAVE_SKB_XMIT_MORE
+#define HAVE_SKB_INNER_PROTOCOL_TYPE
+#endif /* 3.18.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,18,4) )
+#else
+#define HAVE_NDO_FEATURES_CHECK
+#endif /* 3.18.4 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,18,13) )
+#ifndef WRITE_ONCE
+#define WRITE_ONCE(x, val) ({ ACCESS_ONCE(x) = (val); })
+#endif
+#endif /* 3.18.13 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) )
+/* netdev_phys_port_id renamed to netdev_phys_item_id */
+#define netdev_phys_item_id netdev_phys_port_id
+
+static inline void _kc_napi_complete_done(struct napi_struct *napi,
+					  int __always_unused work_done) {
+	napi_complete(napi);
+}
+/* don't use our backport if the distro kernels already have it */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(12,3,0))) || \
+    (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5)))
+#define napi_complete_done _kc_napi_complete_done
+#endif
+
+int _kc_bitmap_print_to_pagebuf(bool list, char *buf,
+				const unsigned long *maskp, int nmaskbits);
+#define bitmap_print_to_pagebuf _kc_bitmap_print_to_pagebuf
+
+#ifndef NETDEV_RSS_KEY_LEN
+#define NETDEV_RSS_KEY_LEN (13 * 4)
+#endif
+#if (!(RHEL_RELEASE_CODE && \
+      ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) || \
+       (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)))))
+#define netdev_rss_key_fill(buffer, len) __kc_netdev_rss_key_fill(buffer, len)
+#endif /* RHEL_RELEASE_CODE */
+void __kc_netdev_rss_key_fill(void *buffer, size_t len);
+#define SPEED_20000 20000
+#define SPEED_40000 40000
+#ifndef dma_rmb
+#define dma_rmb() rmb()
+#endif
+#ifndef dev_alloc_pages
+#ifndef NUMA_NO_NODE
+#define NUMA_NO_NODE -1
+#endif
+#define dev_alloc_pages(_order) alloc_pages_node(NUMA_NO_NODE, (GFP_ATOMIC | __GFP_COLD | __GFP_COMP | __GFP_MEMALLOC), (_order))
+#endif
+#ifndef dev_alloc_page
+#define dev_alloc_page() dev_alloc_pages(0)
+#endif
+#if !defined(eth_skb_pad) && !defined(skb_put_padto)
+/**
+ *     __kc_skb_put_padto - increase size and pad an skbuff up to a minimal size
+ *     @skb: buffer to pad
+ *     @len: minimal length
+ *
+ *     Pads up a buffer to ensure the trailing bytes exist and are
+ *     blanked. If the buffer already contains sufficient data it
+ *     is untouched. Otherwise it is extended. Returns zero on
+ *     success. The skb is freed on error.
+ */
+static inline int __kc_skb_put_padto(struct sk_buff *skb, unsigned int len)
+{
+	unsigned int size = skb->len;
+
+	if (unlikely(size < len)) {
+		len -= size;
+		if (skb_pad(skb, len))
+			return -ENOMEM;
+		__skb_put(skb, len);
+	}
+	return 0;
+}
+#define skb_put_padto(skb, len) __kc_skb_put_padto(skb, len)
+
+static inline int __kc_eth_skb_pad(struct sk_buff *skb)
+{
+	return __kc_skb_put_padto(skb, ETH_ZLEN);
+}
+#define eth_skb_pad(skb) __kc_eth_skb_pad(skb)
+#endif /* eth_skb_pad && skb_put_padto */
+
+#ifndef SKB_ALLOC_NAPI
+/* RHEL 7.2 backported napi_alloc_skb and friends */
+static inline struct sk_buff *__kc_napi_alloc_skb(struct napi_struct *napi, unsigned int length)
+{
+	return netdev_alloc_skb_ip_align(napi->dev, length);
+}
+#define napi_alloc_skb(napi,len) __kc_napi_alloc_skb(napi,len)
+#define __napi_alloc_skb(napi,len,mask) __kc_napi_alloc_skb(napi,len)
+#endif /* SKB_ALLOC_NAPI */
+#define HAVE_CONFIG_PM_RUNTIME
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,7)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
+#define HAVE_RXFH_HASHFUNC
+#endif /* 6.7 < RHEL < 7.0 */
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,1))
+#define HAVE_RXFH_HASHFUNC
+#define NDO_DFLT_BRIDGE_GETLINK_HAS_BRFLAGS
+#endif /* RHEL > 7.1 */
+#ifndef napi_schedule_irqoff
+#define napi_schedule_irqoff	napi_schedule
+#endif
+#ifndef READ_ONCE
+#define READ_ONCE(_x) ACCESS_ONCE(_x)
+#endif
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+#define HAVE_NDO_FDB_ADD_VID
+#endif
+#ifndef ETH_MODULE_SFF_8636
+#define ETH_MODULE_SFF_8636		0x3
+#endif
+#ifndef ETH_MODULE_SFF_8636_LEN
+#define ETH_MODULE_SFF_8636_LEN		256
+#endif
+#ifndef ETH_MODULE_SFF_8436
+#define ETH_MODULE_SFF_8436		0x4
+#endif
+#ifndef ETH_MODULE_SFF_8436_LEN
+#define ETH_MODULE_SFF_8436_LEN		256
+#endif
+#ifndef writel_relaxed
+#define writel_relaxed	writel
+#endif
+#else /* 3.19.0 */
+#define HAVE_NDO_FDB_ADD_VID
+#define HAVE_RXFH_HASHFUNC
+#define NDO_DFLT_BRIDGE_GETLINK_HAS_BRFLAGS
+#endif /* 3.19.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,20,0) )
+/* vlan_tx_xx functions got renamed to skb_vlan */
+#ifndef skb_vlan_tag_get
+#define skb_vlan_tag_get vlan_tx_tag_get
+#endif
+#ifndef skb_vlan_tag_present
+#define skb_vlan_tag_present vlan_tx_tag_present
+#endif
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,1))
+#define HAVE_INCLUDE_LINUX_TIMECOUNTER_H
+#endif
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+#define HAVE_NDO_BRIDGE_SET_DEL_LINK_FLAGS
+#endif
+#else
+#define HAVE_INCLUDE_LINUX_TIMECOUNTER_H
+#define HAVE_NDO_BRIDGE_SET_DEL_LINK_FLAGS
+#endif /* 3.20.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) )
+/* Definition for CONFIG_OF was introduced earlier */
+#if !defined(CONFIG_OF) && \
+    !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+static inline struct device_node *
+pci_device_to_OF_node(const struct pci_dev __always_unused *pdev) { return NULL; }
+#else /* !CONFIG_OF && RHEL < 7.3 */
+#define HAVE_DDP_PROFILE_UPLOAD_SUPPORT
+#endif /* !CONFIG_OF && RHEL < 7.3 */
+#else /* < 4.0 */
+#define HAVE_DDP_PROFILE_UPLOAD_SUPPORT
+#endif /* < 4.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) )
+#ifndef NO_PTP_SUPPORT
+#ifdef HAVE_INCLUDE_LINUX_TIMECOUNTER_H
+#include <linux/timecounter.h>
+#else
+#include <linux/clocksource.h>
+#endif
+static inline void __kc_timecounter_adjtime(struct timecounter *tc, s64 delta)
+{
+	tc->nsec += delta;
+}
+
+static inline struct net_device *
+of_find_net_device_by_node(struct device_node __always_unused *np)
+{
+	return NULL;
+}
+
+#define timecounter_adjtime __kc_timecounter_adjtime
+#endif
+#if ((RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2))) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,2,0))))
+#define HAVE_NDO_SET_VF_RSS_QUERY_EN
+#endif
+#if RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+#define HAVE_NDO_BRIDGE_GETLINK_NLFLAGS
+#define HAVE_RHEL7_EXTENDED_NDO_SET_TX_MAXRATE
+#define HAVE_NDO_SET_TX_MAXRATE
+#endif
+#if !((RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,8) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) && \
+      (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)) && \
+      (SLE_VERSION_CODE > SLE_VERSION(12,1,0)))
+unsigned int _kc_cpumask_local_spread(unsigned int i, int node);
+#define cpumask_local_spread _kc_cpumask_local_spread
+#endif
+#ifdef HAVE_RHASHTABLE
+#define rhashtable_loopup_fast(ht, key, params)		\
+	do {						\
+		(void)params;				\
+		rhashtable_lookup((ht), (key));		\
+	} while (0)
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) )
+#define rhashtable_insert_fast(ht, obj, params)			\
+	do {							\
+		(void)params;					\
+		rhashtable_insert((ht), (obj), GFP_KERNEL);	\
+	} while (0)
+
+#define rhashtable_remove_fast(ht, obj, params)			\
+	do {							\
+		(void)params;					\
+		rhashtable_remove((ht), (obj), GFP_KERNEL);	\
+	} while (0)
+
+#else /* >= 3,19,0 */
+#define rhashtable_insert_fast(ht, obj, params)			\
+	do {							\
+		(void)params;					\
+		rhashtable_insert((ht), (obj));			\
+	} while (0)
+
+#define rhashtable_remove_fast(ht, obj, params)			\
+	do {							\
+		(void)params;					\
+		rhashtable_remove((ht), (obj));			\
+	} while (0)
+
+#endif /* 3,19,0 */
+#endif /* HAVE_RHASHTABLE */
+#else /* >= 4,1,0 */
+#define HAVE_NDO_GET_PHYS_PORT_NAME
+#define HAVE_PTP_CLOCK_INFO_GETTIME64
+#define HAVE_NDO_BRIDGE_GETLINK_NLFLAGS
+#define HAVE_PASSTHRU_FEATURES_CHECK
+#define HAVE_NDO_SET_VF_RSS_QUERY_EN
+#define HAVE_NDO_SET_TX_MAXRATE
+#endif /* 4,1,0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,1,9))
+#if (!(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)) && \
+     !((SLE_VERSION_CODE == SLE_VERSION(11,3,0)) && \
+       (SLE_LOCALVERSION_CODE >= SLE_LOCALVERSION(0,47,71))) && \
+     !((SLE_VERSION_CODE == SLE_VERSION(11,4,0)) && \
+       (SLE_LOCALVERSION_CODE >= SLE_LOCALVERSION(65,0,0))) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,1,0)))
+static inline bool page_is_pfmemalloc(struct page __maybe_unused *page)
+{
+#ifdef HAVE_STRUCT_PAGE_PFMEMALLOC
+	return page->pfmemalloc;
+#else
+	return false;
+#endif
+}
+#endif /* !RHEL7.2+ && !SLES11sp3(3.0.101-0.47.71+ update) && !SLES11sp4(3.0.101-65+ update) & !SLES12sp1+ */
+#else
+#undef HAVE_STRUCT_PAGE_PFMEMALLOC
+#endif /* 4.1.9 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,1,0)))
+#define ETHTOOL_RX_FLOW_SPEC_RING	0x00000000FFFFFFFFULL
+#define ETHTOOL_RX_FLOW_SPEC_RING_VF	0x000000FF00000000ULL
+#define ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF 32
+static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie)
+{
+	return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie;
+};
+
+static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
+{
+	return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >>
+				ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
+};
+#endif /* ! RHEL >= 7.2 && ! SLES >= 12.1 */
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+#define HAVE_NDO_DFLT_BRIDGE_GETLINK_VLAN_SUPPORT
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27))
+#if (!((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,8) && \
+	RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) || \
+       RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)))
+static inline bool pci_ari_enabled(struct pci_bus *bus)
+{
+	return bus->self && bus->self->ari_enabled;
+}
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2))
+#define HAVE_VF_STATS
+#endif /* (RHEL7.2+) */
+#endif /* !(RHEL6.8+ || RHEL7.2+) */
+#else
+static inline bool pci_ari_enabled(struct pci_bus *bus)
+{
+	return false;
+}
+#endif /* 2.6.27 */
+#else
+#define HAVE_NDO_DFLT_BRIDGE_GETLINK_VLAN_SUPPORT
+#define HAVE_VF_STATS
+#endif /* 4.2.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,2,0)))
+/**
+ * _kc_flow_dissector_key_ipv4_addrs:
+ * @src: source ip address
+ * @dst: destination ip address
+ */
+struct _kc_flow_dissector_key_ipv4_addrs {
+	__be32 src;
+	__be32 dst;
+};
+
+/**
+ * _kc_flow_dissector_key_ipv6_addrs:
+ * @src: source ip address
+ * @dst: destination ip address
+ */
+struct _kc_flow_dissector_key_ipv6_addrs {
+	struct in6_addr src;
+	struct in6_addr dst;
+};
+
+/**
+ * _kc_flow_dissector_key_addrs:
+ * @v4addrs: IPv4 addresses
+ * @v6addrs: IPv6 addresses
+ */
+struct _kc_flow_dissector_key_addrs {
+	union {
+		struct _kc_flow_dissector_key_ipv4_addrs v4addrs;
+		struct _kc_flow_dissector_key_ipv6_addrs v6addrs;
+	};
+};
+
+/**
+ * _kc_flow_dissector_key_tp_ports:
+ *	@ports: port numbers of Transport header
+ *		src: source port number
+ *		dst: destination port number
+ */
+struct _kc_flow_dissector_key_ports {
+	union {
+		__be32 ports;
+		struct {
+			__be16 src;
+			__be16 dst;
+		};
+	};
+};
+
+/**
+ * _kc_flow_dissector_key_basic:
+ * @n_proto: Network header protocol (eg. IPv4/IPv6)
+ * @ip_proto: Transport header protocol (eg. TCP/UDP)
+ * @padding: padding for alignment
+ */
+struct _kc_flow_dissector_key_basic {
+	__be16	n_proto;
+	u8	ip_proto;
+	u8	padding;
+};
+
+struct _kc_flow_keys {
+	struct _kc_flow_dissector_key_basic basic;
+	struct _kc_flow_dissector_key_ports ports;
+	struct _kc_flow_dissector_key_addrs addrs;
+};
+
+/* These are all the include files for kernels inside this #ifdef block that
+ * have any reference to the in kernel definition of struct flow_keys. The
+ * reason for putting them here is to make 100% sure that these files do not get
+ * included after re-defining flow_keys to _kc_flow_keys. This is done to
+ * prevent any possible ABI issues that this structure re-definition could case.
+ */
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)) || \
+      RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) || \
+      SLE_VERSION_CODE >= SLE_VERSION(11,4,0))
+#include <net/flow_keys.h>
+#endif /* (>= 3.3.0 && < 4.2.0) || >= RHEL 6.7  || >= SLE 11.4 */
+#if (LINUX_VERSION_CODE == KERNEL_VERSION(4,2,0))
+#include <net/flow_dissector.h>
+#endif /* 4.2.0 */
+#include <linux/skbuff.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/flow.h>
+
+#define flow_keys _kc_flow_keys
+bool
+_kc_skb_flow_dissect_flow_keys(const struct sk_buff *skb,
+			       struct flow_keys *flow,
+			       unsigned int __always_unused flags);
+#define skb_flow_dissect_flow_keys	_kc_skb_flow_dissect_flow_keys
+#endif /* ! >= RHEL 7.4 && ! >= SLES 12.2 */
+
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)) || \
+     (SLE_VERSION_CODE >= SLE_VERSION(12,2,0)))
+#include <net/dst_metadata.h>
+#endif /* >= RHEL7.3 || >= SLE12sp2 */
+#else /* >= 4.3.0 */
+#include <net/dst_metadata.h>
+#endif /* 4.3.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3))
+#define HAVE_NDO_SET_VF_TRUST
+#endif /* (RHEL_RELEASE >= 7.3) */
+#ifndef CONFIG_64BIT
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
+#include <asm-generic/io-64-nonatomic-lo-hi.h>	/* 32-bit readq/writeq */
+#else /* 3.3.0 => 4.3.x */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+#include <asm-generic/int-ll64.h>
+#endif /* 2.6.26 => 3.3.0 */
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+	const volatile u32 __iomem *p = addr;
+	u32 low, high;
+
+	low = readl(p);
+	high = readl(p + 1);
+
+	return low + ((u64)high << 32);
+}
+#define readq readq
+#endif
+
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+	writel(val, addr);
+	writel(val >> 32, addr + 4);
+}
+#define writeq writeq
+#endif
+#endif /* < 3.3.0 */
+#endif /* !CONFIG_64BIT */
+#else /* < 4.4.0 */
+#define HAVE_NDO_SET_VF_TRUST
+
+#ifndef CONFIG_64BIT
+#include <linux/io-64-nonatomic-lo-hi.h>	/* 32-bit readq/writeq */
+#endif /* !CONFIG_64BIT */
+#endif /* 4.4.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0))
+/* protect against a likely backport */
+#ifndef NETIF_F_CSUM_MASK
+#define NETIF_F_CSUM_MASK NETIF_F_ALL_CSUM
+#endif /* NETIF_F_CSUM_MASK */
+#ifndef NETIF_F_SCTP_CRC
+#define NETIF_F_SCTP_CRC NETIF_F_SCTP_CSUM
+#endif /* NETIF_F_SCTP_CRC */
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)))
+#define eth_platform_get_mac_address _kc_eth_platform_get_mac_address
+int _kc_eth_platform_get_mac_address(struct device *dev __maybe_unused,
+				     u8 *mac_addr __maybe_unused);
+#endif /* !(RHEL_RELEASE >= 7.3) */
+#else /* 4.5.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) )
+#define HAVE_GENEVE_RX_OFFLOAD
+#if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_GENEVE)
+#define HAVE_UDP_ENC_TUNNEL
+#endif
+#endif /* < 4.8.0 */
+#define HAVE_NETIF_NAPI_ADD_CALLS_NAPI_HASH_ADD
+#define HAVE_NETDEV_UPPER_INFO
+#endif /* 4.5.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0))
+#if !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,3))
+static inline unsigned char *skb_checksum_start(const struct sk_buff *skb)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
+	return skb->head + skb->csum_start;
+#else /* < 2.6.22 */
+	return skb_transport_header(skb);
+#endif
+}
+#endif
+
+#if !(UBUNTU_VERSION_CODE && \
+		UBUNTU_VERSION_CODE >= UBUNTU_VERSION(4,4,0,21)) && \
+	!(RHEL_RELEASE_CODE && \
+		(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))) && \
+	!(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+static inline void napi_consume_skb(struct sk_buff *skb,
+				    int __always_unused budget)
+{
+	dev_consume_skb_any(skb);
+}
+
+#endif /* UBUNTU 4,4,0,21, RHEL 7.2, SLES12 SP3 */
+#if !((LINUX_VERSION_CODE == KERNEL_VERSION(4, 4, 131)) && \
+	(defined(TXGBE_SUPPORT_KYLIN_FT) || defined(TXGBE_SUPPORT_KYLIN_LX)) )
+#if !(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) && \
+	!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+{
+	* sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
+}
+#endif
+#endif
+#if !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))) && \
+	!(SLE_VERSION_CODE && (SLE_VERSION_CODE > SLE_VERSION(12,3,0)))
+static inline void page_ref_inc(struct page *page)
+{
+	get_page(page);
+}
+#else
+#define HAVE_PAGE_COUNT_BULK_UPDATE
+#endif
+#ifndef IPV4_USER_FLOW
+#define	IPV4_USER_FLOW	0x0d	/* spec only (usr_ip4_spec) */
+#endif
+
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+#define HAVE_TC_SETUP_CLSFLOWER
+#define HAVE_TC_FLOWER_ENC
+#endif
+
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,7)) || \
+     (SLE_VERSION_CODE >= SLE_VERSION(12,2,0)))
+#define HAVE_TC_SETUP_CLSU32
+#endif
+
+#if (SLE_VERSION_CODE >= SLE_VERSION(12,2,0))
+#define HAVE_TC_SETUP_CLSFLOWER
+#endif
+
+#else /* >= 4.6.0 */
+#define HAVE_PAGE_COUNT_BULK_UPDATE
+#define HAVE_ETHTOOL_FLOW_UNION_IP6_SPEC
+#define HAVE_PTP_CROSSTIMESTAMP
+#define HAVE_TC_SETUP_CLSFLOWER
+#define HAVE_TC_SETUP_CLSU32
+#endif /* 4.6.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0))
+#if ((SLE_VERSION_CODE >= SLE_VERSION(12,3,0)) ||\
+     (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)))
+#define HAVE_NETIF_TRANS_UPDATE
+#endif /* SLES12sp3+ || RHEL7.4+ */
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)) ||\
+     (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#define HAVE_ETHTOOL_25G_BITS
+#define HAVE_ETHTOOL_50G_BITS
+#define HAVE_ETHTOOL_100G_BITS
+#endif /* RHEL7.3+ || SLES12sp3+ */
+#else /* 4.7.0 */
+#define HAVE_NETIF_TRANS_UPDATE
+#define HAVE_ETHTOOL_25G_BITS
+#define HAVE_ETHTOOL_50G_BITS
+#define HAVE_ETHTOOL_100G_BITS
+#define HAVE_TCF_MIRRED_REDIRECT
+#endif /* 4.7.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0))
+#if !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+enum udp_parsable_tunnel_type {
+	UDP_TUNNEL_TYPE_VXLAN,
+	UDP_TUNNEL_TYPE_GENEVE,
+};
+struct udp_tunnel_info {
+	unsigned short type;
+	sa_family_t sa_family;
+	__be16 port;
+};
+#endif
+
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))
+#define HAVE_TCF_EXTS_TO_LIST
+#endif
+
+#if (UBUNTU_VERSION_CODE && UBUNTU_VERSION_CODE < UBUNTU_VERSION(4,8,0,0))
+#define tc_no_actions(_exts) true
+#define tc_for_each_action(_a, _exts) while (0)
+#endif
+#if !((LINUX_VERSION_CODE == KERNEL_VERSION(4, 4, 131)) && \
+	(defined(TXGBE_SUPPORT_KYLIN_FT) || defined(TXGBE_SUPPORT_KYLIN_LX)) )
+#if !(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12, 3, 0))) &&\
+	!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 4))
+static inline int
+#ifdef HAVE_NON_CONST_PCI_DRIVER_NAME
+pci_request_io_regions(struct pci_dev *pdev, char *name)
+#else
+pci_request_io_regions(struct pci_dev *pdev, const char *name)
+#endif
+{
+	return pci_request_selected_regions(pdev,
+			    pci_select_bars(pdev, IORESOURCE_IO), name);
+}
+
+static inline void
+pci_release_io_regions(struct pci_dev *pdev)
+{
+	return pci_release_selected_regions(pdev,
+			    pci_select_bars(pdev, IORESOURCE_IO));
+}
+
+static inline int
+#ifdef HAVE_NON_CONST_PCI_DRIVER_NAME
+pci_request_mem_regions(struct pci_dev *pdev, char *name)
+#else
+pci_request_mem_regions(struct pci_dev *pdev, const char *name)
+#endif
+{
+	return pci_request_selected_regions(pdev,
+			    pci_select_bars(pdev, IORESOURCE_MEM), name);
+}
+
+static inline void
+pci_release_mem_regions(struct pci_dev *pdev)
+{
+	return pci_release_selected_regions(pdev,
+			    pci_select_bars(pdev, IORESOURCE_MEM));
+}
+#endif /* !SLE_VERSION(12,3,0) */
+#endif /* !TXGBE_SUPPORT_KYLIN_FT */
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)) ||\
+     (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#define HAVE_ETHTOOL_NEW_50G_BITS
+#endif /* RHEL7.4+ || SLES12sp3+ */
+#else
+#define HAVE_UDP_ENC_RX_OFFLOAD
+#define HAVE_TCF_EXTS_TO_LIST
+#define HAVE_ETHTOOL_NEW_50G_BITS
+#endif /* 4.8.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0))
+#ifdef HAVE_TC_SETUP_CLSFLOWER
+#if (!(RHEL_RELEASE_CODE) && !(SLE_VERSION_CODE) || \
+    (SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(12,3,0))))
+#define HAVE_TC_FLOWER_VLAN_IN_TAGS
+#endif /* !RHEL_RELEASE_CODE && !SLE_VERSION_CODE || <SLE_VERSION(12,3,0) */
+#endif /* HAVE_TC_SETUP_CLSFLOWER */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+#define HAVE_ETHTOOL_NEW_1G_BITS
+#define HAVE_ETHTOOL_NEW_10G_BITS
+#endif /* RHEL7.4+ */
+#if (!(SLE_VERSION_CODE) && !(RHEL_RELEASE_CODE)) || \
+     SLE_VERSION_CODE && (SLE_VERSION_CODE <= SLE_VERSION(12,3,0)) || \
+     RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,5))
+#define time_is_before_jiffies64(a)	time_after64(get_jiffies_64(), a)
+#endif /* !SLE_VERSION_CODE && !RHEL_RELEASE_CODE || (SLES <= 12.3.0) || (RHEL <= 7.5) */
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,4))
+static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
+{
+	dst[0] = mask & ULONG_MAX;
+
+	if (sizeof(mask) > sizeof(unsigned long))
+		dst[1] = mask >> 32;
+}
+#endif /* <RHEL7.4 */
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,3,0)) && \
+     !(UBUNTU_VERSION_CODE >= UBUNTU_VERSION(4,13,0,16)))
+#if !(defined(TXGBE_SUPPORT_KYLIN_FT)) && !(defined(TXGBE_SUPPORT_KYLIN_LX))
+
+static inline bool eth_type_vlan(__be16 ethertype)
+{
+	switch (ethertype) {
+	case htons(ETH_P_8021Q):
+#ifdef ETH_P_8021AD
+	case htons(ETH_P_8021AD):
+#endif
+		return true;
+	default:
+		return false;
+	}
+}
+#endif
+#endif /* Linux < 4.9 || RHEL < 7.4 || SLES < 12.3 || Ubuntu < 4.3.0-16 */
+#else /* >=4.9 */
+#define HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
+#define HAVE_FLOW_DISSECTOR_KEY_VLAN_PRIO
+#define HAVE_ETHTOOL_NEW_1G_BITS
+#define HAVE_ETHTOOL_NEW_10G_BITS
+#endif /* KERNEL_VERSION(4.9.0) */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0))
+/* SLES 12.3 and RHEL 7.5 backported this interface */
+#if (!SLE_VERSION_CODE && !RHEL_RELEASE_CODE) || \
+    (SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(12,3,0))) || \
+    (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5)))
+static inline bool _kc_napi_complete_done2(struct napi_struct *napi,
+					   int __always_unused work_done)
+{
+	/* it was really hard to get napi_complete_done to be safe to call
+	 * recursively without running into our own kcompat, so just use
+	 * napi_complete
+	 */
+	napi_complete(napi);
+
+	/* true means that the stack is telling the driver to go-ahead and
+	 * re-enable interrupts
+	 */
+	return true;
+}
+
+#ifdef napi_complete_done
+#undef napi_complete_done
+#endif
+#define napi_complete_done _kc_napi_complete_done2
+#endif /* sles and rhel exclusion for < 4.10 */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
+#define HAVE_DEV_WALK_API
+#define HAVE_ETHTOOL_NEW_2500MB_BITS
+#define HAVE_ETHTOOL_5G_BITS
+#endif /* RHEL7.4+ */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE == SLE_VERSION(12,3,0)))
+#define HAVE_STRUCT_DMA_ATTRS
+#endif /* (SLES == 12.3.0) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#define HAVE_NETDEVICE_MIN_MAX_MTU
+#endif /* (SLES >= 12.3.0) */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_STRUCT_DMA_ATTRS
+#define HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
+#define HAVE_NETDEVICE_MIN_MAX_MTU
+#endif
+#if (!(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) && \
+     !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))))
+#ifndef dma_map_page_attrs
+#define dma_map_page_attrs __kc_dma_map_page_attrs
+static inline dma_addr_t __kc_dma_map_page_attrs(struct device *dev,
+						 struct page *page,
+						 size_t offset, size_t size,
+						 enum dma_data_direction dir,
+						 unsigned long __always_unused attrs)
+{
+	return dma_map_page(dev, page, offset, size, dir);
+}
+#endif
+
+#ifndef dma_unmap_page_attrs
+#define dma_unmap_page_attrs __kc_dma_unmap_page_attrs
+static inline void __kc_dma_unmap_page_attrs(struct device *dev,
+					     dma_addr_t addr, size_t size,
+					     enum dma_data_direction dir,
+					     unsigned long __always_unused attrs)
+{
+	dma_unmap_page(dev, addr, size, dir);
+}
+#endif
+
+static inline void __page_frag_cache_drain(struct page *page,
+					   unsigned int count)
+{
+#ifdef HAVE_PAGE_COUNT_BULK_UPDATE
+	if (!page_ref_sub_and_test(page, count))
+		return;
+
+	init_page_count(page);
+#else
+	BUG_ON(count > 1);
+	if (!count)
+		return;
+#endif
+	__free_pages(page, compound_order(page));
+}
+#endif /* !SLE_VERSION(12,3,0) && !RHEL_VERSION(7,5) */
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE > SLE_VERSION(12,3,0))) ||\
+     (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_SWIOTLB_SKIP_CPU_SYNC
+#endif
+
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(15,0,0))) ||\
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,4))))
+#define page_frag_free __free_page_frag
+#endif
+#ifndef ETH_MIN_MTU
+#define ETH_MIN_MTU 68
+#endif /* ETH_MIN_MTU */
+#else /* >= 4.10 */
+#define HAVE_TC_FLOWER_ENC
+#define HAVE_NETDEVICE_MIN_MAX_MTU
+#define HAVE_SWIOTLB_SKIP_CPU_SYNC
+#define HAVE_NETDEV_TC_RESETS_XPS
+#define HAVE_XPS_QOS_SUPPORT
+#define HAVE_DEV_WALK_API
+#define HAVE_ETHTOOL_NEW_2500MB_BITS
+#define HAVE_ETHTOOL_5G_BITS
+/* kernel 4.10 onwards, as part of busy_poll rewrite, new state were added
+ * which is part of NAPI:state. If NAPI:state=NAPI_STATE_IN_BUSY_POLL,
+ * it means napi_poll is invoked in busy_poll context
+ */
+#define HAVE_NAPI_STATE_IN_BUSY_POLL
+#define HAVE_TCF_MIRRED_EGRESS_REDIRECT
+#endif /* 4.10.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0))
+#ifdef CONFIG_NET_RX_BUSY_POLL
+#define HAVE_NDO_BUSY_POLL
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))))
+#define HAVE_VOID_NDO_GET_STATS64
+#endif /* (SLES >= 12.3.0) && (RHEL >= 7.5) */
+
+static inline void _kc_dev_kfree_skb_irq(struct sk_buff *skb)
+{
+	if (!skb)
+		return;
+	dev_kfree_skb_irq(skb);
+}
+
+#undef dev_kfree_skb_irq
+#define dev_kfree_skb_irq _kc_dev_kfree_skb_irq
+
+static inline void _kc_dev_consume_skb_irq(struct sk_buff *skb)
+{
+	if (!skb)
+		return;
+	dev_consume_skb_irq(skb);
+}
+
+#undef dev_consume_skb_irq
+#define dev_consume_skb_irq _kc_dev_consume_skb_irq
+
+static inline void _kc_dev_kfree_skb_any(struct sk_buff *skb)
+{
+	if (!skb)
+		return;
+	dev_kfree_skb_any(skb);
+}
+
+#undef dev_kfree_skb_any
+#define dev_kfree_skb_any _kc_dev_kfree_skb_any
+
+static inline void _kc_dev_consume_skb_any(struct sk_buff *skb)
+{
+	if (!skb)
+		return;
+	dev_consume_skb_any(skb);
+}
+
+#undef dev_consume_skb_any
+#define dev_consume_skb_any _kc_dev_consume_skb_any
+
+#else /* > 4.11 */
+#define HAVE_VOID_NDO_GET_STATS64
+#define HAVE_VM_OPS_FAULT_NO_VMA
+#endif /* 4.11.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,7) && \
+     RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0))
+/* The RHEL 7.7+ NL_SET_ERR_MSG_MOD triggers unused parameter warnings */
+#undef NL_SET_ERR_MSG_MOD
+#endif
+#ifndef NL_SET_ERR_MSG_MOD
+#define NL_SET_ERR_MSG_MOD(extack, msg)						\
+	do {									\
+		uninitialized_var(extack);					\
+		pr_err(KBUILD_MODNAME ": " msg);				\
+	} while (0)
+#endif /* !NL_SET_ERR_MSG_MOD */
+#else /* >= 4.12 */
+#define HAVE_NAPI_BUSY_LOOP
+#endif /* 4.12 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0))
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE > SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_TCF_EXTS_HAS_ACTION
+#endif
+#define  PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,4,0)))
+#define HAVE_PCI_ERROR_HANDLER_RESET_PREPARE
+#endif /* SLES >= 12sp4 */
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,4,0)))
+#if !(defined(TXGBE_SUPPORT_KYLIN_FT)) && !(defined(TXGBE_SUPPORT_KYLIN_LX))
+#define UUID_SIZE 16
+typedef struct {
+	__u8 b[UUID_SIZE];
+} uuid_t;
+#define UUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)		\
+((uuid_t)								\
+{{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
+   ((b) >> 8) & 0xff, (b) & 0xff,					\
+   ((c) >> 8) & 0xff, (c) & 0xff,					\
+   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
+
+static inline bool uuid_equal(const uuid_t *u1, const uuid_t *u2)
+{
+	return memcmp(u1, u2, sizeof(uuid_t)) == 0;
+}
+#endif
+#else
+#define HAVE_METADATA_PORT_INFO
+#endif /* !(RHEL >= 7.5) && !(SLES >= 12.4) */
+#else /* > 4.13 */
+#define HAVE_METADATA_PORT_INFO
+#define HAVE_HWTSTAMP_FILTER_NTP_ALL
+#define HAVE_NDO_SETUP_TC_CHAIN_INDEX
+#define HAVE_PCI_ERROR_HANDLER_RESET_PREPARE
+#define HAVE_PTP_CLOCK_DO_AUX_WORK
+#endif /* 4.13.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0))
+#ifdef ETHTOOL_GLINKSETTINGS
+#ifndef ethtool_link_ksettings_del_link_mode
+#define ethtool_link_ksettings_del_link_mode(ptr, name, mode)		\
+	__clear_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
+#endif
+#endif /* ETHTOOL_GLINKSETTINGS */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,4,0)))
+#define HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+#endif
+
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+#define HAVE_RHEL7_NETDEV_OPS_EXT_NDO_SETUP_TC
+#endif
+
+#define TIMER_DATA_TYPE		unsigned long
+#define TIMER_FUNC_TYPE		void (*)(TIMER_DATA_TYPE)
+
+#define timer_setup(timer, callback, flags)				\
+	__setup_timer((timer), (TIMER_FUNC_TYPE)(callback),		\
+		      (TIMER_DATA_TYPE)(timer), (flags))
+
+#define from_timer(var, callback_timer, timer_fieldname) \
+	container_of(callback_timer, typeof(*var), timer_fieldname)
+
+#ifndef xdp_do_flush_map
+#define xdp_do_flush_map() do {} while (0)
+#endif
+struct _kc_xdp_buff {
+	void *data;
+	void *data_end;
+	void *data_hard_start;
+};
+#define xdp_buff _kc_xdp_buff
+struct _kc_bpf_prog {
+};
+#define bpf_prog _kc_bpf_prog
+#ifndef DIV_ROUND_DOWN_ULL
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+	({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#endif /* DIV_ROUND_DOWN_ULL */
+#else /* > 4.14 */
+#define HAVE_XDP_SUPPORT
+#define HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+#define HAVE_TCF_EXTS_HAS_ACTION
+#endif /* 4.14.0 */
+
+/*****************************************************************************/
+#ifndef ETHTOOL_GLINKSETTINGS
+
+#define __ETHTOOL_LINK_MODE_MASK_NBITS 32
+#define ETHTOOL_LINK_MASK_SIZE BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/**
+ * struct ethtool_link_ksettings
+ * @link_modes: supported and advertising, single item arrays
+ * @link_modes.supported: bitmask of supported link speeds
+ * @link_modes.advertising: bitmask of currently advertised speeds
+ * @base: base link details
+ * @base.speed: current link speed
+ * @base.port: current port type
+ * @base.duplex: current duplex mode
+ * @base.autoneg: current autonegotiation settings
+ *
+ * This struct and the following macros provide a way to support the old
+ * ethtool get/set_settings API on older kernels, but in the style of the new
+ * GLINKSETTINGS API.  In this way, the same code can be used to support both
+ * APIs as seemlessly as possible.
+ *
+ * It should be noted the old API only has support up to the first 32 bits.
+ */
+struct ethtool_link_ksettings {
+	struct {
+		u32 speed;
+		u8 port;
+		u8 duplex;
+		u8 autoneg;
+	} base;
+	struct {
+		unsigned long supported[ETHTOOL_LINK_MASK_SIZE];
+		unsigned long advertising[ETHTOOL_LINK_MASK_SIZE];
+	} link_modes;
+};
+
+#define ETHTOOL_LINK_NAME_advertising(mode) ADVERTISED_ ## mode
+#define ETHTOOL_LINK_NAME_supported(mode) SUPPORTED_ ## mode
+#define ETHTOOL_LINK_NAME(name) ETHTOOL_LINK_NAME_ ## name
+#define ETHTOOL_LINK_CONVERT(name, mode) ETHTOOL_LINK_NAME(name)(mode)
+
+/**
+ * ethtool_link_ksettings_zero_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ */
+#define ethtool_link_ksettings_zero_link_mode(ptr, name)\
+	(*((ptr)->link_modes.name) = 0x0)
+
+/**
+ * ethtool_link_ksettings_add_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to add
+ */
+#define ethtool_link_ksettings_add_link_mode(ptr, name, mode)\
+	(*((ptr)->link_modes.name) |= (typeof(*((ptr)->link_modes.name)))ETHTOOL_LINK_CONVERT(name, mode))
+
+/**
+ * ethtool_link_ksettings_del_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to delete
+ */
+#define ethtool_link_ksettings_del_link_mode(ptr, name, mode)\
+	(*((ptr)->link_modes.name) &= ~(typeof(*((ptr)->link_modes.name)))ETHTOOL_LINK_CONVERT(name, mode))
+
+/**
+ * ethtool_link_ksettings_test_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to add
+ */
+#define ethtool_link_ksettings_test_link_mode(ptr, name, mode)\
+	(!!(*((ptr)->link_modes.name) & ETHTOOL_LINK_CONVERT(name, mode)))
+
+/**
+ * _kc_ethtool_ksettings_to_cmd - Convert ethtool_link_ksettings to ethtool_cmd
+ * @ks: ethtool_link_ksettings struct
+ * @cmd: ethtool_cmd struct
+ *
+ * Convert an ethtool_link_ksettings structure into the older ethtool_cmd
+ * structure. We provide this in kcompat.h so that drivers can easily
+ * implement the older .{get|set}_settings as wrappers around the new api.
+ * Hence, we keep it prefixed with _kc_ to make it clear this isn't actually
+ * a real function in the kernel.
+ */
+static inline void
+_kc_ethtool_ksettings_to_cmd(struct ethtool_link_ksettings *ks,
+			     struct ethtool_cmd *cmd)
+{
+	cmd->supported = (u32)ks->link_modes.supported[0];
+	cmd->advertising = (u32)ks->link_modes.advertising[0];
+	ethtool_cmd_speed_set(cmd, ks->base.speed);
+	cmd->duplex = ks->base.duplex;
+	cmd->autoneg = ks->base.autoneg;
+	cmd->port = ks->base.port;
+}
+
+#endif /* !ETHTOOL_GLINKSETTINGS */
+
+/*****************************************************************************/
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE <= SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,5))))
+#define phy_speed_to_str _kc_phy_speed_to_str
+const char *_kc_phy_speed_to_str(int speed);
+#else /* (LINUX >= 4.14.0) || (SLES > 12.3.0) || (RHEL > 7.5) */
+#include <linux/phy.h>
+#endif /* (LINUX < 4.14.0) || (SLES <= 12.3.0) || (RHEL <= 7.5) */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+#if ((RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,6))) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,1,0))))
+#define HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#define HAVE_TCF_BLOCK
+#define TC_SETUP_MQPRIO 0
+#define TC_SETUP_QDISC_MQPRIO TC_SETUP_MQPRIO
+#else /* RHEL >= 7.6 || SLES >= 15.1 */
+#define TC_SETUP_MQPRIO 0
+#define TC_SETUP_QDISC_MQPRIO TC_SETUP_MQPRIO
+#endif /* !(RHEL >= 7.6) && !(SLES >= 15.1) */
+void _kc_ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
+				      struct ethtool_link_ksettings *src);
+#define ethtool_intersect_link_masks _kc_ethtool_intersect_link_masks
+#else /* >= 4.15 */
+#define HAVE_NDO_BPF
+#define HAVE_XDP_BUFF_DATA_META
+#define HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#define HAVE_TCF_BLOCK
+#endif /* 4.15.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,7)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,4,0) && \
+       SLE_VERSION_CODE < SLE_VERSION(15,0,0)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(15,1,0)))
+/* The return value of the strscpy() and strlcpy() functions is different.
+ * This could be potentially hazard for the future.
+ * To avoid this the void result is forced.
+ * So it is not possible use this function with the return value.
+ * Return value is required in kernel 4.3 through 4.15
+ */
+#define strscpy(...) (void)(strlcpy(__VA_ARGS__))
+#endif /* !RHEL >= 7.7 && !SLES12sp4+ && !SLES15sp1+ */
+
+#define pci_printk(level, pdev, fmt, arg...) \
+	dev_printk(level, &(pdev)->dev, fmt, ##arg)
+#define pci_emerg(pdev, fmt, arg...)	dev_emerg(&(pdev)->dev, fmt, ##arg)
+#define pci_alert(pdev, fmt, arg...)	dev_alert(&(pdev)->dev, fmt, ##arg)
+#define pci_crit(pdev, fmt, arg...)	dev_crit(&(pdev)->dev, fmt, ##arg)
+#define pci_err(pdev, fmt, arg...)	dev_err(&(pdev)->dev, fmt, ##arg)
+#define pci_warn(pdev, fmt, arg...)	dev_warn(&(pdev)->dev, fmt, ##arg)
+#define pci_notice(pdev, fmt, arg...)	dev_notice(&(pdev)->dev, fmt, ##arg)
+#define pci_info(pdev, fmt, arg...)	dev_info(&(pdev)->dev, fmt, ##arg)
+#define pci_dbg(pdev, fmt, arg...)	dev_dbg(&(pdev)->dev, fmt, ##arg)
+
+#ifndef array_index_nospec
+static inline unsigned long _kc_array_index_mask_nospec(unsigned long index,
+							unsigned long size)
+{
+	/*
+	 * Always calculate and emit the mask even if the compiler
+	 * thinks the mask is not needed. The compiler does not take
+	 * into account the value of @index under speculation.
+	 */
+	OPTIMIZER_HIDE_VAR(index);
+	return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+
+#define array_index_nospec(index, size)					\
+({									\
+	typeof(index) _i = (index);					\
+	typeof(size) _s = (size);					\
+	unsigned long _mask = _kc_array_index_mask_nospec(_i, _s);	\
+									\
+	BUILD_BUG_ON(sizeof(_i) > sizeof(long));			\
+	BUILD_BUG_ON(sizeof(_s) > sizeof(long));			\
+									\
+	(typeof(_i)) (_i & _mask);					\
+})
+#endif /* array_index_nospec */
+#if (!(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,6))) && \
+     !(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,1,0))))
+#ifdef HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#include <net/pkt_cls.h>
+#if 0
+static inline bool
+tc_cls_can_offload_and_chain0(const struct net_device *dev,
+			      struct tc_cls_common_offload *common)
+{
+	if (!tc_can_offload(dev))
+		return false;
+	if (common->chain_index)
+		return false;
+
+	return true;
+}
+#endif
+#endif /* HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO */
+#endif /* !(RHEL >= 7.6) && !(SLES >= 15.1) */
+#ifndef sizeof_field
+#define sizeof_field(TYPE, MEMBER) (sizeof((((TYPE *)0)->MEMBER)))
+#endif /* sizeof_field */
+#if !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(12,5,0) && \
+       SLE_VERSION_CODE < SLE_VERSION(15,0,0) || \
+       SLE_VERSION_CODE >= SLE_VERSION(15,1,0))
+/*
+ * Copy bitmap and clear tail bits in last word.
+ */
+static inline void
+bitmap_copy_clear_tail(unsigned long *dst, const unsigned long *src, unsigned int nbits)
+{
+	bitmap_copy(dst, src, nbits);
+	if (nbits % BITS_PER_LONG)
+		dst[nbits / BITS_PER_LONG] &= BITMAP_LAST_WORD_MASK(nbits);
+}
+
+/*
+ * On 32-bit systems bitmaps are represented as u32 arrays internally, and
+ * therefore conversion is not needed when copying data from/to arrays of u32.
+ */
+#if BITS_PER_LONG == 64
+void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf, unsigned int nbits);
+#else
+#define bitmap_from_arr32(bitmap, buf, nbits)			\
+	bitmap_copy_clear_tail((unsigned long *) (bitmap),	\
+			       (const unsigned long *) (buf), (nbits))
+#endif /* BITS_PER_LONG == 64 */
+#endif /* !(RHEL >= 8.0) && !(SLES >= 12.5 && SLES < 15.0 || SLES >= 15.1) */
+#else /* >= 4.16 */
+#include <linux/nospec.h>
+#define HAVE_XDP_BUFF_RXQ
+#define HAVE_TC_FLOWER_OFFLOAD_COMMON_EXTACK
+#define HAVE_TCF_MIRRED_DEV
+#define HAVE_VF_STATS_DROPPED
+#endif /* 4.16.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+#include <linux/pci_regs.h>
+#include <linux/pci.h>
+#define PCIE_SPEED_16_0GT 0x17
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
+#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
+void _kc_pcie_print_link_status(struct pci_dev *dev);
+#define pcie_print_link_status _kc_pcie_print_link_status
+#else /* >= 4.17.0 */
+#define HAVE_XDP_BUFF_IN_XDP_H
+#endif /* 4.17.0 */
+
+/*****************************************************************************/
+#if IS_ENABLED(CONFIG_NET_DEVLINK) && \
+    (LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0))
+#include <net/devlink.h>
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)) && \
+     (SLE_VERSION_CODE < SLE_VERSION(15,1,0)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,7)))
+#ifndef HAVE_DEVLINK_PORT_ATTRS_SET_PORT_FLAVOUR
+enum devlink_port_flavour {
+	DEVLINK_PORT_FLAVOUR_PHYSICAL,
+	DEVLINK_PORT_FLAVOUR_CPU,
+	DEVLINK_PORT_FLAVOUR_DSA,
+	DEVLINK_PORT_FLAVOUR_PCI_PF,
+	DEVLINK_PORT_FLAVOUR_PCI_VF,
+};
+#endif
+#endif /* <4.18.0 && <SLES15sp1 && <RHEL7.7 */
+
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0)) && \
+     (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,2)))
+struct devlink_port_phys_attrs {
+	u32 port_number; /* Same value as "split group".
+			  * A physical port which is visible to the user
+			  * for a given port flavour.
+			  */
+	u32 split_subport_number; /* If the port is split, this is the number
+				   * of subport. */
+};
+
+struct devlink_port_pci_pf_attrs {
+	u16 pf; /* Associated PCI PF for this port. */
+};
+
+struct devlink_port_pci_vf_attrs {
+	u16 pf; /* Associated PCI PF for this port. */
+	u16 vf; /* Associated PCI VF for of the PCI PF for this port. */
+};
+#endif /* <5.3.0 && <RHEL8.2*/
+
+struct _kc_devlink_port_attrs {
+	u8 split:1,
+	   splittable:1;
+	u32 lanes;
+	enum devlink_port_flavour flavour;
+	struct netdev_phys_item_id switch_id;
+	union {
+		struct devlink_port_phys_attrs phys;
+		struct devlink_port_pci_pf_attrs pci_pf;
+		struct devlink_port_pci_vf_attrs pci_vf;
+	};
+};
+#define devlink_port_attrs _kc_devlink_port_attrs
+#endif /* CONFIG_NET_DEVLINK && <5.9.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
+#ifdef NETIF_F_HW_L2FW_DOFFLOAD
+#include <linux/if_macvlan.h>
+#ifndef macvlan_supports_dest_filter
+#define macvlan_supports_dest_filter _kc_macvlan_supports_dest_filter
+static inline bool _kc_macvlan_supports_dest_filter(struct net_device *dev)
+{
+	struct macvlan_dev *macvlan = netdev_priv(dev);
+
+	return macvlan->mode == MACVLAN_MODE_PRIVATE ||
+	       macvlan->mode == MACVLAN_MODE_VEPA ||
+	       macvlan->mode == MACVLAN_MODE_BRIDGE;
+}
+#endif
+
+#if (!SLE_VERSION_CODE || (SLE_VERSION_CODE < SLE_VERSION(15,1,0)))
+#ifndef macvlan_accel_priv
+#define macvlan_accel_priv _kc_macvlan_accel_priv
+
+#endif
+
+#ifndef macvlan_release_l2fw_offload
+#define macvlan_release_l2fw_offload _kc_macvlan_release_l2fw_offload
+
+#endif
+#endif /* !SLES || SLES < 15.1 */
+#endif /* NETIF_F_HW_L2FW_DOFFLOAD */
+#else
+#include <linux/overflow.h>
+#include <net/xdp_sock.h>
+#define HAVE_XDP_FRAME_STRUCT
+#define HAVE_XDP_SOCK
+#define HAVE_NDO_XDP_XMIT_BULK_AND_FLAGS
+#define NO_NDO_XDP_FLUSH
+#define HAVE_AF_XDP_SUPPORT
+#endif /* 4.18.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) && \
+    (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(8,2)))
+#define HAVE_DEVLINK_REGIONS
+#endif /* RHEL >= 8.0 && RHEL <= 8.2 */
+#define bitmap_alloc(nbits, flags) \
+	kmalloc_array(BITS_TO_LONGS(nbits), sizeof(unsigned long), flags)
+#define bitmap_zalloc(nbits, flags) bitmap_alloc(nbits, ((flags) | __GFP_ZERO))
+#define bitmap_free(bitmap) kfree(bitmap)
+#ifdef ETHTOOL_GLINKSETTINGS
+#define ethtool_ks_clear(ptr, name) \
+	ethtool_link_ksettings_zero_link_mode(ptr, name)
+#define ethtool_ks_add_mode(ptr, name, mode) \
+	ethtool_link_ksettings_add_link_mode(ptr, name, mode)
+#define ethtool_ks_del_mode(ptr, name, mode) \
+	ethtool_link_ksettings_del_link_mode(ptr, name, mode)
+#define ethtool_ks_test(ptr, name, mode) \
+	ethtool_link_ksettings_test_link_mode(ptr, name, mode)
+#endif /* ETHTOOL_GLINKSETTINGS */
+#define HAVE_NETPOLL_CONTROLLER
+#define REQUIRE_PCI_CLEANUP_AER_ERROR_STATUS
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,1,0)))
+#define HAVE_TCF_MIRRED_DEV
+#define HAVE_NDO_SELECT_QUEUE_SB_DEV
+#define HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+#endif
+#if ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) ||\
+     (SLE_VERSION_CODE >= SLE_VERSION(15,1,0)))
+#define HAVE_TCF_EXTS_FOR_EACH_ACTION
+#undef HAVE_TCF_EXTS_TO_LIST
+#endif /* RHEL8.0+ */
+
+static inline void __kc_metadata_dst_free(void *md_dst)
+{
+	kfree(md_dst);
+}
+
+#define metadata_dst_free(md_dst) __kc_metadata_dst_free(md_dst)
+#else /* >= 4.19.0 */
+#define HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+#define NO_NETDEV_BPF_PROG_ATTACHED
+#define HAVE_NDO_SELECT_QUEUE_SB_DEV
+#define HAVE_NETDEV_SB_DEV
+#undef HAVE_TCF_EXTS_TO_LIST
+#define HAVE_TCF_EXTS_FOR_EACH_ACTION
+#define HAVE_TCF_VLAN_TPID
+#define HAVE_RHASHTABLE_TYPES
+#define HAVE_DEVLINK_REGIONS
+#define HAVE_DEVLINK_PARAMS
+#endif /* 4.19.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0))
+#define HAVE_XDP_UMEM_PROPS
+#ifdef HAVE_AF_XDP_SUPPORT
+#ifndef napi_if_scheduled_mark_missed
+static inline bool __kc_napi_if_scheduled_mark_missed(struct napi_struct *n)
+{
+	unsigned long val, new;
+
+	do {
+		val = READ_ONCE(n->state);
+		if (val & NAPIF_STATE_DISABLE)
+			return true;
+
+		if (!(val & NAPIF_STATE_SCHED))
+			return false;
+
+		new = val | NAPIF_STATE_MISSED;
+	} while (cmpxchg(&n->state, val, new) != val);
+
+	return true;
+}
+
+#define napi_if_scheduled_mark_missed __kc_napi_if_scheduled_mark_missed
+#endif /* !napi_if_scheduled_mark_missed */
+#endif /* HAVE_AF_XDP_SUPPORT */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)))
+#define HAVE_DEVLINK_ESWITCH_OPS_EXTACK
+#endif /* RHEL >= 8.0 */
+#if ((SLE_VERSION_CODE >= SLE_VERSION(12,5,0) && \
+      SLE_VERSION_CODE < SLE_VERSION(15,0,0)) || \
+     (SLE_VERSION_CODE >= SLE_VERSION(15,1,0)))
+#define HAVE_DEVLINK_ESWITCH_OPS_EXTACK
+#endif /* SLE == 12sp5 || SLE >= 15sp1 */
+#else /* >= 4.20.0 */
+#define HAVE_DEVLINK_ESWITCH_OPS_EXTACK
+#define HAVE_AF_XDP_ZC_SUPPORT
+#define HAVE_VXLAN_TYPE
+#define HAVE_ETF_SUPPORT /* Earliest TxTime First */
+#endif /* 4.20.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0))
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(8,0)))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
+#define NETLINK_MAX_COOKIE_LEN	20
+struct netlink_ext_ack {
+	const char *_msg;
+	const struct nlattr *bad_attr;
+	u8 cookie[NETLINK_MAX_COOKIE_LEN];
+	u8 cookie_len;
+};
+
+#endif /* < 4.12 */
+#if 0
+static inline int _kc_dev_open(struct net_device *netdev,
+			       struct netlink_ext_ack __always_unused *extack)
+{
+	return dev_open(netdev);
+}
+
+#define dev_open _kc_dev_open
+#endif
+static inline int
+_kc_dev_change_flags(struct net_device *netdev, unsigned int flags,
+		     struct netlink_ext_ack __always_unused *extack)
+{
+	return dev_change_flags(netdev, flags);
+}
+
+#define dev_change_flags _kc_dev_change_flags
+#endif /* !(RHEL_RELEASE_CODE && RHEL > RHEL(8,0)) */
+#if (RHEL_RELEASE_CODE && \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,7) && \
+      RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)) || \
+     (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,1)))
+#define HAVE_PTP_SYS_OFFSET_EXTENDED_IOCTL
+#else /* RHEL >= 7.7 && RHEL < 8.0 || RHEL >= 8.1 */
+struct ptp_system_timestamp {
+	struct timespec64 pre_ts;
+	struct timespec64 post_ts;
+};
+
+static inline void
+ptp_read_system_prets(struct ptp_system_timestamp __always_unused *sts)
+{
+	;
+}
+
+static inline void
+ptp_read_system_postts(struct ptp_system_timestamp __always_unused *sts)
+{
+	;
+}
+#endif /* !(RHEL >= 7.7 && RHEL != 8.0) */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,1)))
+#define HAVE_NDO_BRIDGE_SETLINK_EXTACK
+#endif /* RHEL 8.1 */
+#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2))
+#define HAVE_TC_INDIR_BLOCK
+#endif /* RHEL 8.2 */
+#else /* >= 5.0.0 */
+#define HAVE_PTP_SYS_OFFSET_EXTENDED_IOCTL
+#define HAVE_NDO_BRIDGE_SETLINK_EXTACK
+#define HAVE_DMA_ALLOC_COHERENT_ZEROES_MEM
+#define HAVE_GENEVE_TYPE
+#define HAVE_TC_INDIR_BLOCK
+#endif /* 5.0.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,1)))
+#define HAVE_TC_FLOW_RULE_INFRASTRUCTURE
+#define HAVE_NDO_FDB_ADD_EXTACK
+#define HAVE_DEVLINK_INFO_GET
+#define HAVE_DEVLINK_FLASH_UPDATE
+#else /* RHEL < 8.1 */
+#ifdef HAVE_TC_SETUP_CLSFLOWER
+#include <net/pkt_cls.h>
+
+struct flow_match {
+	struct flow_dissector	*dissector;
+	void			*mask;
+	void			*key;
+};
+
+struct flow_match_basic {
+	struct flow_dissector_key_basic *key, *mask;
+};
+
+struct flow_match_control {
+	struct flow_dissector_key_control *key, *mask;
+};
+
+struct flow_match_eth_addrs {
+	struct flow_dissector_key_eth_addrs *key, *mask;
+};
+
+#ifdef HAVE_TC_FLOWER_ENC
+struct flow_match_enc_keyid {
+	struct flow_dissector_key_keyid *key, *mask;
+};
+#endif
+
+#ifndef HAVE_TC_FLOWER_VLAN_IN_TAGS
+struct flow_match_vlan {
+	struct flow_dissector_key_vlan *key, *mask;
+};
+#endif
+
+struct flow_match_ipv4_addrs {
+	struct flow_dissector_key_ipv4_addrs *key, *mask;
+};
+
+struct flow_match_ipv6_addrs {
+	struct flow_dissector_key_ipv6_addrs *key, *mask;
+};
+
+struct flow_match_ports {
+	struct flow_dissector_key_ports *key, *mask;
+};
+
+struct flow_rule {
+	struct flow_match	match;
+#if 0
+	/* In 5.1+ kernels, action is a member of struct flow_rule but is
+	 * not compatible with how we kcompat tc_cls_flower_offload_flow_rule
+	 * below.  By not declaring it here, any driver that attempts to use
+	 * action as an element of struct flow_rule will fail to compile
+	 * instead of silently trying to access memory that shouldn't be.
+	 */
+	struct flow_action	action;
+#endif
+};
+
+void txgbe_flow_rule_match_basic(const struct flow_rule *rule,
+			   struct flow_match_basic *out);
+void txgbe_flow_rule_match_control(const struct flow_rule *rule,
+			     struct flow_match_control *out);
+void txgbe_flow_rule_match_eth_addrs(const struct flow_rule *rule,
+			       struct flow_match_eth_addrs *out);
+#ifndef HAVE_TC_FLOWER_VLAN_IN_TAGS
+void txgbe_flow_rule_match_vlan(const struct flow_rule *rule,
+			  struct flow_match_vlan *out);
+#endif
+void txgbe_flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
+				struct flow_match_ipv4_addrs *out);
+void txgbe_flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
+				struct flow_match_ipv6_addrs *out);
+void txgbe_flow_rule_match_ports(const struct flow_rule *rule,
+			   struct flow_match_ports *out);
+#ifdef HAVE_TC_FLOWER_ENC
+void txgbe_flow_rule_match_enc_ports(const struct flow_rule *rule,
+			       struct flow_match_ports *out);
+void txgbe_flow_rule_match_enc_control(const struct flow_rule *rule,
+				 struct flow_match_control *out);
+void txgbe_flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
+				    struct flow_match_ipv4_addrs *out);
+void txgbe_flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
+				    struct flow_match_ipv6_addrs *out);
+void txgbe_flow_rule_match_enc_keyid(const struct flow_rule *rule,
+			       struct flow_match_enc_keyid *out);
+#endif
+
+static inline struct flow_rule *
+tc_cls_flower_offload_flow_rule(struct tc_cls_flower_offload *tc_flow_cmd)
+{
+	return (struct flow_rule *)&tc_flow_cmd->dissector;
+}
+
+static inline bool flow_rule_match_key(const struct flow_rule *rule,
+				       enum flow_dissector_key_id key)
+{
+	return dissector_uses_key(rule->match.dissector, key);
+}
+#endif /* HAVE_TC_SETUP_CLSFLOWER */
+
+#endif /* RHEL < 8.1 */
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,1)))
+#define devlink_params_publish(devlink) do { } while (0)
+#define devlink_params_unpublish(devlink) do { } while (0)
+#endif
+
+#else /* >= 5.1.0 */
+#define HAVE_NDO_FDB_ADD_EXTACK
+#define NO_XDP_QUERY_XSK_UMEM
+#define HAVE_AF_XDP_NETDEV_UMEM
+#define HAVE_TC_FLOW_RULE_INFRASTRUCTURE
+#define HAVE_TC_FLOWER_ENC_IP
+#define HAVE_DEVLINK_INFO_GET
+#define HAVE_DEVLINK_FLASH_UPDATE
+#define HAVE_DEVLINK_PORT_PARAMS
+#endif /* 5.1.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0))
+#if (defined HAVE_SKB_XMIT_MORE) && \
+(!(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2))))
+#define netdev_xmit_more()	(skb->xmit_more)
+#else
+#define netdev_xmit_more()	(0)
+#endif
+
+#if (!(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2))))
+#ifndef eth_get_headlen
+static inline u32
+__kc_eth_get_headlen(const struct net_device __always_unused *dev, void *data,
+		     unsigned int len)
+{
+	return eth_get_headlen(data, len);
+}
+
+#define eth_get_headlen(dev, data, len) __kc_eth_get_headlen(dev, data, len)
+#endif /* !eth_get_headlen */
+#endif /* !RHEL >= 8.2 */
+
+#ifndef mmiowb
+#ifdef CONFIG_IA64
+#define mmiowb() asm volatile ("mf.a" ::: "memory")
+#else
+#define mmiowb()
+#endif
+#endif /* mmiowb */
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,2))
+#if IS_ENABLED(CONFIG_NET_DEVLINK) && !defined(devlink_port_attrs_set)
+#if 0
+static inline void
+_kc_devlink_port_attrs_set(struct devlink_port *devlink_port,
+			   struct _kc_devlink_port_attrs *attrs)
+{
+	devlink_port_attrs_set(devlink_port, attrs->flavour,
+			       attrs->phys.port_number, attrs->split,
+			       attrs->phys.split_subport_number);
+}
+
+#define devlink_port_attrs_set _kc_devlink_port_attrs_set
+#endif
+#endif /* CONFIG_NET_DEVLINK && !devlink_port_attrs_set */
+#endif /* <RHEL8.2 */
+
+#if (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(8,1))
+#define HAVE_NDO_GET_DEVLINK_PORT
+#endif /* RHEL > 8.1 */
+
+#else /* >= 5.2.0 */
+#define HAVE_NDO_SELECT_QUEUE_FALLBACK_REMOVED
+#define SPIN_UNLOCK_IMPLIES_MMIOWB
+#define HAVE_NDO_GET_DEVLINK_PORT
+#endif /* 5.2.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,3,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2)))
+#define flow_block_offload tc_block_offload
+#define flow_block_command tc_block_command
+#define flow_cls_offload tc_cls_flower_offload
+#define flow_block_binder_type tcf_block_binder_type
+#define flow_cls_common_offload tc_cls_common_offload
+#define flow_cls_offload_flow_rule tc_cls_flower_offload_flow_rule
+#define FLOW_CLS_REPLACE TC_CLSFLOWER_REPLACE
+#define FLOW_CLS_DESTROY TC_CLSFLOWER_DESTROY
+#define FLOW_CLS_STATS TC_CLSFLOWER_STATS
+#define FLOW_CLS_TMPLT_CREATE TC_CLSFLOWER_TMPLT_CREATE
+#define FLOW_CLS_TMPLT_DESTROY TC_CLSFLOWER_TMPLT_DESTROY
+#define FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS \
+		TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS
+#define FLOW_BLOCK_BIND TC_BLOCK_BIND
+#define FLOW_BLOCK_UNBIND TC_BLOCK_UNBIND
+
+#ifdef HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#include <net/pkt_cls.h>
+
+#endif /* HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO */
+#else /* RHEL >= 8.2 */
+#define HAVE_FLOW_BLOCK_API
+#define HAVE_DEVLINK_PORT_ATTR_PCI_VF
+#endif /* RHEL >= 8.2 */
+
+#ifndef ETH_P_LLDP
+#define ETH_P_LLDP	0x88CC
+#endif /* !ETH_P_LLDP */
+
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,2))
+#if IS_ENABLED(CONFIG_NET_DEVLINK)
+static inline void
+devlink_flash_update_begin_notify(struct devlink __always_unused *devlink)
+{
+}
+
+static inline void
+devlink_flash_update_end_notify(struct devlink __always_unused *devlink)
+{
+}
+
+static inline void
+devlink_flash_update_status_notify(struct devlink __always_unused *devlink,
+				   const char __always_unused *status_msg,
+				   const char __always_unused *component,
+				   unsigned long __always_unused done,
+				   unsigned long __always_unused total)
+{
+}
+#endif /* CONFIG_NET_DEVLINK */
+#endif /* <RHEL8.2 */
+#else /* >= 5.3.0 */
+#define XSK_UMEM_RETURNS_XDP_DESC
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0))
+#if !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(15,3,0))
+#define HAVE_XSK_UMEM_HAS_ADDRS
+#endif /* SLE < 15.3 */
+#endif /* < 5.8.0*/
+#define HAVE_FLOW_BLOCK_API
+#define HAVE_DEVLINK_PORT_ATTR_PCI_VF
+#if IS_ENABLED(CONFIG_DIMLIB)
+#define HAVE_CONFIG_DIMLIB
+#endif
+#endif /* 5.3.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0))
+#if (!(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,2)) && \
+     !(SLE_VERSION_CODE >= SLE_VERSION(15,2,0)))
+
+#ifndef HAVE_DEFINE_SKB_FRAG_OFF
+static inline unsigned int skb_frag_off(const skb_frag_t *frag)
+{
+	return frag->page_offset;
+}
+#endif
+
+static inline void skb_frag_off_add(skb_frag_t *frag, int delta)
+{
+	frag->page_offset += delta;
+}
+#define __flow_indr_block_cb_register __tc_indr_block_cb_register
+#define __flow_indr_block_cb_unregister __tc_indr_block_cb_unregister
+#endif /* !(RHEL >= 8.2) && !(SLES >= 15sp2) */
+#if (SLE_VERSION_CODE >= SLE_VERSION(15,2,0))
+#define HAVE_NDO_XSK_WAKEUP
+#endif /* SLES15sp2 */
+#else /* >= 5.4.0 */
+#define HAVE_NDO_XSK_WAKEUP
+#endif /* 5.4.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,5,0))
+static inline unsigned long _kc_bitmap_get_value8(const unsigned long *map,
+						  unsigned long start)
+{
+	const size_t index = BIT_WORD(start);
+	const unsigned long offset = start % BITS_PER_LONG;
+
+	return (map[index] >> offset) & 0xFF;
+}
+#define bitmap_get_value8 _kc_bitmap_get_value8
+
+static inline void _kc_bitmap_set_value8(unsigned long *map,
+					 unsigned long value,
+					 unsigned long start)
+{
+	const size_t index = BIT_WORD(start);
+	const unsigned long offset = start % BITS_PER_LONG;
+
+	map[index] &= ~(0xFFUL << offset);
+	map[index] |= value << offset;
+}
+#define bitmap_set_value8 _kc_bitmap_set_value8
+
+#endif /* 5.5.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0))
+#ifdef HAVE_AF_XDP_SUPPORT
+#define xsk_umem_release_addr		xsk_umem_discard_addr
+#define xsk_umem_release_addr_rq	xsk_umem_discard_addr_rq
+#endif /* HAVE_AF_XDP_SUPPORT */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,3)) || \
+    (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(15,3,0)))	
+#define HAVE_TX_TIMEOUT_TXQUEUE
+#endif
+#else /* >= 5.6.0 */
+#define HAVE_TX_TIMEOUT_TXQUEUE
+#endif /* 5.6.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0))
+u64 _kc_pci_get_dsn(struct pci_dev *dev);
+#define pci_get_dsn(dev) _kc_pci_get_dsn(dev)
+#if !(SLE_VERSION_CODE > SLE_VERSION(15,2,0)) && \
+    !((LINUX_VERSION_CODE == KERNEL_VERSION(5,3,18)) && \
+      (SLE_LOCALVERSION_CODE >= KERNEL_VERSION(14,0,0))) && \
+    !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,3)))
+#define pci_aer_clear_nonfatal_status	pci_cleanup_aer_uncorrect_error_status
+#endif
+
+#define cpu_latency_qos_update_request pm_qos_update_request
+#define cpu_latency_qos_add_request(arg1, arg2) pm_qos_add_request(arg1, PM_QOS_CPU_DMA_LATENCY, arg2)
+#define cpu_latency_qos_remove_request pm_qos_remove_request
+
+#ifndef DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID
+#define DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID "fw.bundle_id"
+#endif
+#else /* >= 5.7.0 */
+#define HAVE_DEVLINK_REGION_OPS_SNAPSHOT
+#define HAVE_ETHTOOL_COALESCE_PARAMS_SUPPORT
+#endif /* 5.7.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0))
+#if !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,4))) && \
+    !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(15,3,0))
+#define xdp_convert_buff_to_frame convert_to_xdp_frame
+#endif /* (RHEL < 8.4) || (SLE < 15.3) */
+#define flex_array_size(p, member, count) \
+	array_size(count, sizeof(*(p)->member) + __must_be_array((p)->member))
+#if (!(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(15,3,0)))
+#ifdef HAVE_AF_XDP_ZC_SUPPORT
+#ifndef xsk_umem_get_rx_frame_size
+static inline u32 _xsk_umem_get_rx_frame_size(struct xdp_umem *umem)
+{
+	return umem->chunk_size_nohr - XDP_PACKET_HEADROOM;
+}
+
+#define xsk_umem_get_rx_frame_size _xsk_umem_get_rx_frame_size
+#endif /* xsk_umem_get_rx_frame_size */
+#endif /* HAVE_AF_XDP_ZC_SUPPORT */
+#else /* SLE >= 15.3 */
+#define HAVE_XDP_BUFF_FRAME_SZ
+#define HAVE_MEM_TYPE_XSK_BUFF_POOL
+#endif /* SLE >= 15.3 */
+#else /* >= 5.8.0 */
+#define HAVE_TC_FLOW_INDIR_DEV
+#define HAVE_TC_FLOW_INDIR_BLOCK_CLEANUP
+#define HAVE_XDP_BUFF_FRAME_SZ
+#define HAVE_MEM_TYPE_XSK_BUFF_POOL
+#endif /* 5.8.0 */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,3)))
+#define HAVE_TC_FLOW_INDIR_DEV
+#endif
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,3,0)))
+#define HAVE_TC_FLOW_INDIR_DEV
+#endif /* SLE_VERSION_CODE && SLE_VERSION_CODE >= SLES15SP3 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0))
+#else /* >= 5.9.0 */
+#define HAVE_FLOW_INDIR_BLOCK_QDISC
+#define HAVE_UDP_TUNNEL_NIC_INFO
+#endif /* 5.9.0 */
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(8,3)))
+#define HAVE_FLOW_INDIR_BLOCK_QDISC
+#endif
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,3,0)))
+#define HAVE_FLOW_INDIR_BLOCK_QDISC
+#endif /* SLE_VERSION_CODE && SLE_VERSION_CODE >= SLES15SP3 */
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0))
+#if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(15,3,0))
+#define HAVE_DEVLINK_REGION_OPS_SNAPSHOT_OPS
+#define HAVE_DEVLINK_FLASH_UPDATE_PARAMS
+#else /* SLE >= 15.3 */
+
+#ifndef DEVLINK_FLASH_OVERWRITE_SETTINGS
+#define DEVLINK_FLASH_OVERWRITE_SETTINGS BIT(0)
+#endif
+
+#ifndef DEVLINK_FLASH_OVERWRITE_IDENTIFIERS
+#define DEVLINK_FLASH_OVERWRITE_IDENTIFIERS BIT(1)
+#endif
+#endif /* !(SLE >= 15.3) */
+
+#if (!(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,3,0))))
+#define XDP_SETUP_XSK_POOL XDP_SETUP_XSK_UMEM
+#define xsk_get_pool_from_qid xdp_get_umem_from_qid
+#define xsk_pool_get_rx_frame_size xsk_umem_get_rx_frame_size
+#define xsk_pool_set_rxq_info xsk_buff_set_rxq_info
+#define xsk_pool_dma_unmap xsk_buff_dma_unmap
+#define xsk_pool_dma_map xsk_buff_dma_map
+#define xsk_tx_peek_desc xsk_umem_consume_tx
+#define xsk_tx_release xsk_umem_consume_tx_done
+#define xsk_tx_completed xsk_umem_complete_tx
+#define xsk_uses_need_wakeup xsk_umem_uses_need_wakeup
+#ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+#include <net/xdp_sock_drv.h>
+static inline void
+_kc_xsk_buff_dma_sync_for_cpu(struct xdp_buff *xdp,
+			      void __always_unused *pool)
+{
+	xsk_buff_dma_sync_for_cpu(xdp);
+}
+
+#define xsk_buff_dma_sync_for_cpu(xdp, pool) \
+	_kc_xsk_buff_dma_sync_for_cpu(xdp, pool)
+#endif /* HAVE_MEM_TYPE_XSK_BUFF_POOL */
+#else /* SLE >= 15.3 */
+#define HAVE_NETDEV_BPF_XSK_POOL
+#endif /* SLE >= 15.3 */
+#else /* >= 5.10.0 */
+#define HAVE_DEVLINK_REGION_OPS_SNAPSHOT_OPS
+#define HAVE_DEVLINK_FLASH_UPDATE_PARAMS
+#define HAVE_NETDEV_BPF_XSK_POOL
+#endif /* 5.10.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0))
+#define HAVE_DEVLINK_FLASH_UPDATE_BEGIN_END_NOTIFY
+#else /* >= 5.11.0 */
+#define HAVE_DEVLINK_FLASH_UPDATE_PARAMS_FW
+#endif /* 5.11.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0))
+#define NEED_DEVLINK_ALLOC_SETS_DEV
+#define HAVE_DEVLINK_REGISTER_SETS_DEV
+#else /* >= 5.15.0 */
+#define HAVE_ETHTOOL_COALESCE_EXTACK
+#define HAVE_NDO_ETH_IOCTL
+#define HAVE_DEVICE_IN_MDEV_PARENT_OPS
+#endif /* 5.15.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,16,0))
+#else /* >= 5.16.0 */
+#undef HAVE_PASID_SUPPORT
+#define HAVE_DEVLINK_SET_FEATURES
+#define HAVE_DEVLINK_NOTIFY_REGISTER
+#endif /* 5.16.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,17,0))
+#define NEED_ETH_HW_ADDR_SET
+#else /* >=5.17.0*/
+#define HAVE_ETHTOOL_EXTENDED_RINGPARAMS
+#endif /* 5.17.0 */
+
+#ifdef NEED_ETH_HW_ADDR_SET
+void _kc_eth_hw_addr_set(struct net_device *dev, const void *addr);
+#ifndef eth_hw_addr_set
+#define eth_hw_addr_set(dev, addr) \
+	_kc_eth_hw_addr_set(dev, addr)
+#endif /* eth_hw_addr_set */
+#endif /* NEED_ETH_HW_ADDR_SET */
+
+/*****************************************************************************/
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,6))
+#else /* >= 8.6 */
+#define HAVE_ETHTOOL_COALESCE_EXTACK
+#endif /* 8.6 */
+
+/*****************************************************************************/
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(9,0))
+#else /* >= 9.0 */
+#define HAVE_XDP_BUFF_RXQ
+#undef HAVE_ETHTOOL_COALESCE_EXTACK
+#endif /* 9.0 */
+
+#endif /* _KCOMPAT_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat_chn_os.h b/drivers/net/ethernet/wangxun/txgbe/kcompat_chn_os.h
new file mode 100644
index 000000000000..7f7835a82ecf
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat_chn_os.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 1999 - 2022  Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _KCOMPAT_CHN_OS_H_
+#define _KCOMPAT_CHN_OS_H_
+
+/* This is the SUSE Linux Enterprise distribution specific definitions file.
+ * It defines what features need backports for a given version of the SUSE
+ * Linux Enterprise kernel.
+ *
+ * It checks a combination of the LINUX_VERSION code and the
+ * SLE_LOCALVERSION_CODE to determine what support the kernel has.
+ *
+ * It assumes that kcompat_std_defs.h has already been processed, and will
+ * #define or #undef any flags that have changed based on backports done by
+ * SUSE.
+ */
+
+#ifndef LINUX_VERSION_CODE
+#error "LINUX_VERSION_CODE is undefined"
+#endif
+
+#ifndef KERNEL_VERSION
+#error "KERNEL_VERSION is undefined"
+#endif
+
+#ifdef CONFIG_UOS_KERNEL
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
+#define HAVE_ETHTOOL_COALESCE_EXTACK
+#endif
+#endif
+
+#ifdef CONFIG_EULER_KERNEL
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
+#define HAVE_ETHTOOL_COALESCE_EXTACK
+#define HAVE_ETHTOOL_EXTENDED_RINGPARAMS
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,208))
+#define HAVE_DEFINE_SKB_FRAG_OFF
+#endif
+#endif
+
+#endif /* _KCOMPAT_SLES_DEFS_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/kcompat_ethtool.c
new file mode 100644
index 000000000000..8c26787796a9
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat_ethtool.c
@@ -0,0 +1,1148 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on kcompat_ethtool.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <asm/uaccess.h>
+
+#include "kcompat.h"
+
+#undef SUPPORTED_10000baseT_Full
+#define SUPPORTED_10000baseT_Full	(1 << 12)
+#undef ADVERTISED_10000baseT_Full
+#define ADVERTISED_10000baseT_Full	(1 << 12)
+#undef SPEED_10000
+#define SPEED_10000		10000
+
+#undef ethtool_ops
+#define ethtool_ops _kc_ethtool_ops
+
+struct _kc_ethtool_ops {
+	int  (*get_settings)(struct net_device *, struct ethtool_cmd *);
+	int  (*set_settings)(struct net_device *, struct ethtool_cmd *);
+	void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
+	int  (*get_regs_len)(struct net_device *);
+	void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
+	void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
+	int  (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
+	u32  (*get_msglevel)(struct net_device *);
+	void (*set_msglevel)(struct net_device *, u32);
+	int  (*nway_reset)(struct net_device *);
+	u32  (*get_link)(struct net_device *);
+	int  (*get_eeprom_len)(struct net_device *);
+	int  (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int  (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int  (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	int  (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	int  (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	void (*get_pauseparam)(struct net_device *,
+							struct ethtool_pauseparam*);
+	int  (*set_pauseparam)(struct net_device *,
+							struct ethtool_pauseparam*);
+	u32  (*get_rx_csum)(struct net_device *);
+	int  (*set_rx_csum)(struct net_device *, u32);
+	u32  (*get_tx_csum)(struct net_device *);
+	int  (*set_tx_csum)(struct net_device *, u32);
+	u32  (*get_sg)(struct net_device *);
+	int  (*set_sg)(struct net_device *, u32);
+	u32  (*get_tso)(struct net_device *);
+	int  (*set_tso)(struct net_device *, u32);
+	int  (*self_test_count)(struct net_device *);
+	void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
+	void (*get_strings)(struct net_device *, u32 stringset, u8 *);
+	int  (*phys_id)(struct net_device *, u32);
+	int  (*get_stats_count)(struct net_device *);
+	void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *,
+								u64 *);
+} *ethtool_ops = NULL;
+
+#undef SET_ETHTOOL_OPS
+#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops))
+
+/*
+ * Some useful ethtool_ops methods that are device independent. If we find that
+ * all drivers want to do the same thing here, we can turn these into dev_()
+ * function calls.
+ */
+
+#undef ethtool_op_get_link
+#define ethtool_op_get_link _kc_ethtool_op_get_link
+u32 _kc_ethtool_op_get_link(struct net_device *dev)
+{
+	return netif_carrier_ok(dev) ? 1 : 0;
+}
+
+#undef ethtool_op_get_tx_csum
+#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum
+u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev)
+{
+#ifdef NETIF_F_IP_CSUM
+	return (dev->features & NETIF_F_IP_CSUM) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_tx_csum
+#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum
+int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_IP_CSUM
+	if (data)
+#ifdef NETIF_F_IPV6_CSUM
+		dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+	else
+		dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+#else
+		dev->features |= NETIF_F_IP_CSUM;
+	else
+		dev->features &= ~NETIF_F_IP_CSUM;
+#endif
+#endif
+
+	return 0;
+}
+
+#undef ethtool_op_get_sg
+#define ethtool_op_get_sg _kc_ethtool_op_get_sg
+u32 _kc_ethtool_op_get_sg(struct net_device *dev)
+{
+#ifdef NETIF_F_SG
+	return (dev->features & NETIF_F_SG) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_sg
+#define ethtool_op_set_sg _kc_ethtool_op_set_sg
+int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_SG
+	if (data)
+		dev->features |= NETIF_F_SG;
+	else
+		dev->features &= ~NETIF_F_SG;
+#endif
+
+	return 0;
+}
+
+#undef ethtool_op_get_tso
+#define ethtool_op_get_tso _kc_ethtool_op_get_tso
+u32 _kc_ethtool_op_get_tso(struct net_device *dev)
+{
+#ifdef NETIF_F_TSO
+	return (dev->features & NETIF_F_TSO) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_tso
+#define ethtool_op_set_tso _kc_ethtool_op_set_tso
+int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_TSO
+	if (data)
+		dev->features |= NETIF_F_TSO;
+	else
+		dev->features &= ~NETIF_F_TSO;
+#endif
+
+	return 0;
+}
+
+/* Handlers for each ethtool command */
+
+static int ethtool_get_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd = { ETHTOOL_GSET };
+	int err;
+
+	if (!ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	err = ethtool_ops->get_settings(dev, &cmd);
+	if (err < 0)
+		return err;
+
+	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd;
+
+	if (!ethtool_ops->set_settings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+		return -EFAULT;
+
+	return ethtool_ops->set_settings(dev, &cmd);
+}
+
+static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_drvinfo info;
+	struct ethtool_ops *ops = ethtool_ops;
+
+	if (!ops->get_drvinfo)
+		return -EOPNOTSUPP;
+
+	memset(&info, 0, sizeof(info));
+	info.cmd = ETHTOOL_GDRVINFO;
+	ops->get_drvinfo(dev, &info);
+
+	if (ops->self_test_count)
+		info.testinfo_len = ops->self_test_count(dev);
+	if (ops->get_stats_count)
+		info.n_stats = ops->get_stats_count(dev);
+	if (ops->get_regs_len)
+		info.regdump_len = ops->get_regs_len(dev);
+	if (ops->get_eeprom_len)
+		info.eedump_len = ops->get_eeprom_len(dev);
+
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_regs(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_regs regs;
+	struct ethtool_ops *ops = ethtool_ops;
+	void *regbuf;
+	int reglen, ret;
+
+	if (!ops->get_regs || !ops->get_regs_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&regs, useraddr, sizeof(regs)))
+		return -EFAULT;
+
+	reglen = ops->get_regs_len(dev);
+	if (regs.len > reglen)
+		regs.len = reglen;
+
+	regbuf = kmalloc(reglen, GFP_USER);
+	if (!regbuf)
+		return -ENOMEM;
+
+	ops->get_regs(dev, &regs, regbuf);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &regs, sizeof(regs)))
+		goto out;
+	useraddr += offsetof(struct ethtool_regs, data);
+	if (copy_to_user(useraddr, regbuf, reglen))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(regbuf);
+	return ret;
+}
+
+static int ethtool_get_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+
+	if (!ethtool_ops->get_wol)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_wol(dev, &wol);
+
+	if (copy_to_user(useraddr, &wol, sizeof(wol)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol;
+
+	if (!ethtool_ops->set_wol)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&wol, useraddr, sizeof(wol)))
+		return -EFAULT;
+
+	return ethtool_ops->set_wol(dev, &wol);
+}
+
+static int ethtool_get_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+
+	if (!ethtool_ops->get_msglevel)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_msglevel(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_msglevel)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	ethtool_ops->set_msglevel(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_nway_reset(struct net_device *dev)
+{
+	if (!ethtool_ops->nway_reset)
+		return -EOPNOTSUPP;
+
+	return ethtool_ops->nway_reset(dev);
+}
+
+static int ethtool_get_link(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GLINK };
+
+	if (!ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_link(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->get_eeprom || !ops->get_eeprom_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	/* Check for wrap and zero */
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+		return -EINVAL;
+
+	data = kmalloc(eeprom.len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
+
+	ret = ops->get_eeprom(dev, &eeprom, data);
+	if (ret)
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
+		goto out;
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->set_eeprom || !ops->get_eeprom_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	/* Check for wrap and zero */
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+		return -EINVAL;
+
+	data = kmalloc(eeprom.len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
+
+	ret = ops->set_eeprom(dev, &eeprom, data);
+	if (ret)
+		goto out;
+
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
+		ret = -EFAULT;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
+
+	if (!ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_coalesce(dev, &coalesce);
+
+	if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce;
+
+	if (!ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
+		return -EFAULT;
+
+	return ethtool_ops->set_coalesce(dev, &coalesce);
+}
+
+static int ethtool_get_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
+
+	if (!ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_ringparam(dev, &ringparam);
+
+	if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam;
+
+	if (!ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
+		return -EFAULT;
+
+	return ethtool_ops->set_ringparam(dev, &ringparam);
+}
+
+static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
+
+	if (!ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_pauseparam(dev, &pauseparam);
+
+	if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam;
+
+	if (!ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
+		return -EFAULT;
+
+	return ethtool_ops->set_pauseparam(dev, &pauseparam);
+}
+
+static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GRXCSUM };
+
+	if (!ethtool_ops->get_rx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_rx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_rx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	ethtool_ops->set_rx_csum(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GTXCSUM };
+
+	if (!ethtool_ops->get_tx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_tx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_tx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_tx_csum(dev, edata.data);
+}
+
+static int ethtool_get_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GSG };
+
+	if (!ethtool_ops->get_sg)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_sg(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_sg)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_sg(dev, edata.data);
+}
+
+static int ethtool_get_tso(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GTSO };
+
+	if (!ethtool_ops->get_tso)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_tso(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_tso(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_tso)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_tso(dev, edata.data);
+}
+
+static int ethtool_self_test(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_test test;
+	struct ethtool_ops *ops = ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->self_test || !ops->self_test_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&test, useraddr, sizeof(test)))
+		return -EFAULT;
+
+	test.len = ops->self_test_count(dev);
+	data = kmalloc(test.len * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->self_test(dev, &test, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &test, sizeof(test)))
+		goto out;
+	useraddr += sizeof(test);
+	if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_strings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_gstrings gstrings;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->get_strings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
+		return -EFAULT;
+
+	switch (gstrings.string_set) {
+	case ETH_SS_TEST:
+		if (!ops->self_test_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->self_test_count(dev);
+		break;
+	case ETH_SS_STATS:
+		if (!ops->get_stats_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->get_stats_count(dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_strings(dev, gstrings.string_set, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
+		goto out;
+	useraddr += sizeof(gstrings);
+	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_phys_id(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value id;
+
+	if (!ethtool_ops->phys_id)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&id, useraddr, sizeof(id)))
+		return -EFAULT;
+
+	return ethtool_ops->phys_id(dev, id.data);
+}
+
+static int ethtool_get_stats(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_stats stats;
+	struct ethtool_ops *ops = ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->get_ethtool_stats || !ops->get_stats_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&stats, useraddr, sizeof(stats)))
+		return -EFAULT;
+
+	stats.n_stats = ops->get_stats_count(dev);
+	data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_ethtool_stats(dev, &stats, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &stats, sizeof(stats)))
+		goto out;
+	useraddr += sizeof(stats);
+	if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+/* The main entry point in this file.  Called from net/core/dev.c */
+
+#define ETHTOOL_OPS_COMPAT
+int ethtool_ioctl(struct ifreq *ifr)
+{
+	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
+	void *useraddr = (void *) ifr->ifr_data;
+	u32 ethcmd;
+
+	/*
+	 * XXX: This can be pushed down into the ethtool_* handlers that
+	 * need it.  Keep existing behavior for the moment.
+	 */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (!dev || !netif_device_present(dev))
+		return -ENODEV;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GSET:
+		return ethtool_get_settings(dev, useraddr);
+	case ETHTOOL_SSET:
+		return ethtool_set_settings(dev, useraddr);
+	case ETHTOOL_GDRVINFO:
+		return ethtool_get_drvinfo(dev, useraddr);
+	case ETHTOOL_GREGS:
+		return ethtool_get_regs(dev, useraddr);
+	case ETHTOOL_GWOL:
+		return ethtool_get_wol(dev, useraddr);
+	case ETHTOOL_SWOL:
+		return ethtool_set_wol(dev, useraddr);
+	case ETHTOOL_GMSGLVL:
+		return ethtool_get_msglevel(dev, useraddr);
+	case ETHTOOL_SMSGLVL:
+		return ethtool_set_msglevel(dev, useraddr);
+	case ETHTOOL_NWAY_RST:
+		return ethtool_nway_reset(dev);
+	case ETHTOOL_GLINK:
+		return ethtool_get_link(dev, useraddr);
+	case ETHTOOL_GEEPROM:
+		return ethtool_get_eeprom(dev, useraddr);
+	case ETHTOOL_SEEPROM:
+		return ethtool_set_eeprom(dev, useraddr);
+	case ETHTOOL_GCOALESCE:
+		return ethtool_get_coalesce(dev, useraddr);
+	case ETHTOOL_SCOALESCE:
+		return ethtool_set_coalesce(dev, useraddr);
+	case ETHTOOL_GRINGPARAM:
+		return ethtool_get_ringparam(dev, useraddr);
+	case ETHTOOL_SRINGPARAM:
+		return ethtool_set_ringparam(dev, useraddr);
+	case ETHTOOL_GPAUSEPARAM:
+		return ethtool_get_pauseparam(dev, useraddr);
+	case ETHTOOL_SPAUSEPARAM:
+		return ethtool_set_pauseparam(dev, useraddr);
+	case ETHTOOL_GRXCSUM:
+		return ethtool_get_rx_csum(dev, useraddr);
+	case ETHTOOL_SRXCSUM:
+		return ethtool_set_rx_csum(dev, useraddr);
+	case ETHTOOL_GTXCSUM:
+		return ethtool_get_tx_csum(dev, useraddr);
+	case ETHTOOL_STXCSUM:
+		return ethtool_set_tx_csum(dev, useraddr);
+	case ETHTOOL_GSG:
+		return ethtool_get_sg(dev, useraddr);
+	case ETHTOOL_SSG:
+		return ethtool_set_sg(dev, useraddr);
+	case ETHTOOL_GTSO:
+		return ethtool_get_tso(dev, useraddr);
+	case ETHTOOL_STSO:
+		return ethtool_set_tso(dev, useraddr);
+	case ETHTOOL_TEST:
+		return ethtool_self_test(dev, useraddr);
+	case ETHTOOL_GSTRINGS:
+		return ethtool_get_strings(dev, useraddr);
+	case ETHTOOL_PHYS_ID:
+		return ethtool_phys_id(dev, useraddr);
+	case ETHTOOL_GSTATS:
+		return ethtool_get_stats(dev, useraddr);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+#define mii_if_info _kc_mii_if_info
+struct _kc_mii_if_info {
+	int phy_id;
+	int advertising;
+	int phy_id_mask;
+	int reg_num_mask;
+
+	unsigned int full_duplex : 1;	/* is full duplex? */
+	unsigned int force_media : 1;	/* is autoneg. disabled? */
+
+	struct net_device *dev;
+	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
+	void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
+};
+
+struct ethtool_cmd;
+struct mii_ioctl_data;
+
+#undef mii_link_ok
+#define mii_link_ok _kc_mii_link_ok
+#undef mii_nway_restart
+#define mii_nway_restart _kc_mii_nway_restart
+#undef mii_ethtool_gset
+#define mii_ethtool_gset _kc_mii_ethtool_gset
+#undef mii_ethtool_sset
+#define mii_ethtool_sset _kc_mii_ethtool_sset
+#undef mii_check_link
+#define mii_check_link _kc_mii_check_link
+extern int _kc_mii_link_ok (struct mii_if_info *mii);
+extern int _kc_mii_nway_restart (struct mii_if_info *mii);
+extern int _kc_mii_ethtool_gset(struct mii_if_info *mii,
+								struct ethtool_cmd *ecmd);
+extern int _kc_mii_ethtool_sset(struct mii_if_info *mii,
+								struct ethtool_cmd *ecmd);
+extern void _kc_mii_check_link (struct mii_if_info *mii);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 6))
+#undef generic_mii_ioctl
+#define generic_mii_ioctl _kc_generic_mii_ioctl
+extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
+									struct mii_ioctl_data *mii_data, int cmd,
+									unsigned int *duplex_changed);
+#endif /* > 2.4.6 */
+
+
+struct _kc_pci_dev_ext {
+	struct pci_dev *dev;
+	void *pci_drvdata;
+	struct pci_driver *driver;
+};
+
+struct _kc_net_dev_ext {
+	struct net_device *dev;
+	unsigned int carrier;
+};
+
+
+/**************************************/
+/* mii support */
+
+int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+	u32 advert, bmcr, lpa, nego;
+
+	ecmd->supported =
+	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+	/* only supports twisted-pair */
+	ecmd->port = PORT_MII;
+
+	/* only supports internal transceiver */
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	/* this isn't fully supported at higher layers */
+	ecmd->phy_address = mii->phy_id;
+
+	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+	advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+	if (advert & ADVERTISE_10HALF)
+		ecmd->advertising |= ADVERTISED_10baseT_Half;
+	if (advert & ADVERTISE_10FULL)
+		ecmd->advertising |= ADVERTISED_10baseT_Full;
+	if (advert & ADVERTISE_100HALF)
+		ecmd->advertising |= ADVERTISED_100baseT_Half;
+	if (advert & ADVERTISE_100FULL)
+		ecmd->advertising |= ADVERTISED_100baseT_Full;
+
+	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+	lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+	if (bmcr & BMCR_ANENABLE) {
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+
+		nego = mii_nway_result(advert & lpa);
+		if (nego == LPA_100FULL || nego == LPA_100HALF)
+			ecmd->speed = SPEED_100;
+		else
+			ecmd->speed = SPEED_10;
+		if (nego == LPA_100FULL || nego == LPA_10FULL) {
+			ecmd->duplex = DUPLEX_FULL;
+			mii->full_duplex = 1;
+		} else {
+			ecmd->duplex = DUPLEX_HALF;
+			mii->full_duplex = 0;
+		}
+	} else {
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+		ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+	}
+
+	/* ignore maxtxpkt, maxrxpkt for now */
+
+	return 0;
+}
+
+int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+
+	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+		return -EINVAL;
+	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+	if (ecmd->port != PORT_MII)
+		return -EINVAL;
+	if (ecmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if (ecmd->phy_address != mii->phy_id)
+		return -EINVAL;
+	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+
+	/* ignore supported, maxtxpkt, maxrxpkt */
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		u32 bmcr, advert, tmp;
+
+		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
+					  ADVERTISED_10baseT_Full |
+					  ADVERTISED_100baseT_Half |
+					  ADVERTISED_100baseT_Full)) == 0)
+			return -EINVAL;
+
+		/* advertise only what has been requested */
+		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+		if (ADVERTISED_10baseT_Half)
+			tmp |= ADVERTISE_10HALF;
+		if (ADVERTISED_10baseT_Full)
+			tmp |= ADVERTISE_10FULL;
+		if (ADVERTISED_100baseT_Half)
+			tmp |= ADVERTISE_100HALF;
+		if (ADVERTISED_100baseT_Full)
+			tmp |= ADVERTISE_100FULL;
+		if (advert != tmp) {
+			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
+			mii->advertising = tmp;
+		}
+
+		/* turn on autonegotiation, and force a renegotiate */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+		mii->force_media = 0;
+	} else {
+		u32 bmcr, tmp;
+
+		/* turn off auto negotiation, set speed and duplexity */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+		if (ecmd->speed == SPEED_100)
+			tmp |= BMCR_SPEED100;
+		if (ecmd->duplex == DUPLEX_FULL) {
+			tmp |= BMCR_FULLDPLX;
+			mii->full_duplex = 1;
+		} else
+			mii->full_duplex = 0;
+		if (bmcr != tmp)
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
+
+		mii->force_media = 1;
+	}
+	return 0;
+}
+
+int _kc_mii_link_ok (struct mii_if_info *mii)
+{
+	/* first, a dummy read, needed to latch some MII phys */
+	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
+	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
+		return 1;
+	return 0;
+}
+
+int _kc_mii_nway_restart (struct mii_if_info *mii)
+{
+	int bmcr;
+	int r = -EINVAL;
+
+	/* if autoneg is off, it's an error */
+	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
+
+	if (bmcr & BMCR_ANENABLE) {
+		bmcr |= BMCR_ANRESTART;
+		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
+		r = 0;
+	}
+
+	return r;
+}
+
+void _kc_mii_check_link (struct mii_if_info *mii)
+{
+	int cur_link = mii_link_ok(mii);
+	int prev_link = netif_carrier_ok(mii->dev);
+
+	if (cur_link && !prev_link)
+		netif_carrier_on(mii->dev);
+	else if (prev_link && !cur_link)
+		netif_carrier_off(mii->dev);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 6))
+int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
+							struct mii_ioctl_data *mii_data, int cmd,
+							unsigned int *duplex_chg_out)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	if (duplex_chg_out)
+		*duplex_chg_out = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch (cmd) {
+	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		fallthrough;
+
+	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch (mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 0;
+				else
+					mii_if->force_media = 1;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
+		*duplex_chg_out = 1;
+
+	return rc;
+}
+#endif /* > 2.4.6 */
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat_gcc.h b/drivers/net/ethernet/wangxun/txgbe/kcompat_gcc.h
new file mode 100644
index 000000000000..447c08606bee
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat_gcc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 1999 - 2022 Wangxun Corporation. */
+
+#ifndef _KCOMPAT_GCC_H_
+#define _KCOMPAT_GCC_H_
+
+#ifdef __has_attribute
+#if __has_attribute(__fallthrough__)
+# define fallthrough __attribute__((__fallthrough__))
+#else
+# define fallthrough do {} while (0)  /* fallthrough */
+#endif /* __has_attribute(fallthrough) */
+#else
+# define fallthrough do {} while (0)  /* fallthrough */
+#endif /* __has_attribute */
+
+#endif /* _KCOMPAT_GCC_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/kcompat_sles_defs.h b/drivers/net/ethernet/wangxun/txgbe/kcompat_sles_defs.h
new file mode 100644
index 000000000000..79de40d93adb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/kcompat_sles_defs.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 1999 - 2022  Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _KCOMPAT_SLES_DEFS_H_
+#define _KCOMPAT_SLES_DEFS_H_
+
+/* This is the SUSE Linux Enterprise distribution specific definitions file.
+ * It defines what features need backports for a given version of the SUSE
+ * Linux Enterprise kernel.
+ *
+ * It checks a combination of the LINUX_VERSION code and the
+ * SLE_LOCALVERSION_CODE to determine what support the kernel has.
+ *
+ * It assumes that kcompat_std_defs.h has already been processed, and will
+ * #define or #undef any flags that have changed based on backports done by
+ * SUSE.
+ */
+
+#ifndef LINUX_VERSION_CODE
+#error "LINUX_VERSION_CODE is undefined"
+#endif
+
+#ifndef KERNEL_VERSION
+#error "KERNEL_VERSION is undefined"
+#endif
+
+#if !SLE_KERNEL_REVISION
+//#error "SLE_KERNEL_REVISION is 0 or undefined"
+#endif
+
+#if SLE_KERNEL_REVISION > 65535
+#error "SLE_KERNEL_REVISION is unexpectedly large"
+#endif
+
+/* SLE kernel versions are a combination of the LINUX_VERSION_CODE along with
+ * an extra digit that indicates the SUSE specific revision of that kernel.
+ * This value is found in the CONFIG_LOCALVERSION of the SUSE kernel, which is
+ * extracted by common.mk and placed into SLE_KERNEL_REVISION_CODE.
+ *
+ * We combine the value of SLE_KERNEL_REVISION along with the LINUX_VERSION code
+ * to generate the useful value that determines what specific kernel we're
+ * dealing with.
+ *
+ * Just in case the SLE_KERNEL_REVISION ever goes above 255, we reserve 16 bits
+ * instead of 8 for this value.
+ */
+#define SLE_KERNEL_CODE ((LINUX_VERSION_CODE << 16) + SLE_KERNEL_REVISION)
+#define SLE_KERNEL_VERSION(a,b,c,d) ((KERNEL_VERSION(a,b,c) << 16) + (d))
+
+/* Unlike RHEL, SUSE kernels are not always tied to a single service pack. For
+ * example, 4.12.14 was used as the base for SLE 15 SP1, SLE 12 SP4, and SLE 12
+ * SP5.
+ *
+ * You can find the patches that SUSE applied to the kernel tree at
+ * https://github.com/SUSE/kernel-source.
+ *
+ * You can find the correct kernel version for a check by using steps similar
+ * to the following
+ *
+ * 1) download the kernel-source repo
+ * 2) checkout the relevant branch, i.e SLE15-SP3
+ * 3) find the relevant backport you're interested in the patches.suse
+ *    directory
+ * 4) git log <patch file> to locate the commit that introduced the backport
+ * 5) git describe --contains to find the relevant tag that includes that
+ *    commit, i.e. rpm-5.3.18-37
+ * 6) those digits represent the SLE kernel that introduced that backport.
+ *
+ * Try to keep the checks in SLE_KERNEL_CODE order and condense where
+ * possible.
+ */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE > SLE_KERNEL_VERSION(4,12,14,23) && \
+     SLE_KERNEL_CODE < SLE_KERNEL_VERSION(4,12,14,94))
+/*
+ * 4.12.14 is used as the base for SLE 12 SP4, SLE 12 SP5, SLE 15, and SLE 15
+ * SP1. Unfortunately the revision codes do not line up cleanly. SLE 15
+ * launched with 4.12.14-23. It appears that SLE 12 SP4 and SLE 15 SP1 both
+ * diverged from this point, with SLE 12 SP4 kernels starting around
+ * 4.12.14-94. A few backports for SLE 15 SP1 landed in some alpha and beta
+ * kernels tagged between 4.12.14-25 up to 4.12.14-32. These changes did not
+ * make it into SLE 12 SP4. This was cleaned up with SLE 12 SP5 by an apparent
+ * merge in 4.12.14-111. The official launch of SLE 15 SP1 ended up with
+ * version 4.12.14-195.
+ *
+ * Because of this inconsistency and because all of these kernels appear to be
+ * alpha or beta kernel releases for SLE 15 SP1, we do not rely on version
+ * checks between this range. Issue a warning to indicate that we do not
+ * support these.
+ */
+#warning "SLE kernel versions between 4.12.14-23 and 4.12.14-94 are not supported"
+#endif
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(4,12,14,100))
+#else /* >= 4.12.14-100 */
+#undef HAVE_TCF_EXTS_TO_LIST
+#define HAVE_TCF_EXTS_FOR_EACH_ACTION
+#endif /* 4.12.14-100 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(4,12,14,111))
+#define NEED_IDA_ALLOC_MIN_MAX_RANGE_FREE
+#else /* >= 4.12.14-111 */
+#define HAVE_DEVLINK_PORT_ATTRS_SET_PORT_FLAVOUR
+#undef NEED_MACVLAN_ACCEL_PRIV
+#undef NEED_MACVLAN_RELEASE_L2FW_OFFLOAD
+#undef NEED_MACVLAN_SUPPORTS_DEST_FILTER
+#undef NEED_IDA_ALLOC_MIN_MAX_RANGE_FREE
+#endif /* 4.12.14-111 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(4,12,14,120))
+#else /* >= 4.12.14-120 */
+#define HAVE_NDO_SELECT_QUEUE_SB_DEV
+#define HAVE_TCF_MIRRED_DEV
+#define HAVE_TCF_BLOCK
+#define HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
+#define HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+#undef NEED_TC_SETUP_QDISC_MQPRIO
+#undef NEED_TC_CLS_CAN_OFFLOAD_AND_CHAIN0
+#endif /* 4.12.14-120 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(5,3,8,2))
+#else /* >= 5.3.8-2 */
+#undef NEED_BUS_FIND_DEVICE_CONST_DATA
+#undef NEED_FLOW_INDR_BLOCK_CB_REGISTER
+#undef NEED_SKB_FRAG_OFF_ACCESSORS
+#endif /* 5.3.8-2 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(5,3,18,34))
+#else /* >= 5.3.18-34 */
+#undef NEED_DEVLINK_REGION_CREATE_OPS
+#undef NEED_DEVLINK_PORT_ATTRS_SET_STRUCT
+#endif /* 5.3.18-34 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(5,3,18,37))
+#else /* >= 5.3.18-37 */
+#undef NEED_NET_PREFETCH
+#endif /* 5.3.18-37 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(5,3,18,38))
+#else /* >= 5.3.18-38 */
+#undef NEED_DEVLINK_FLASH_UPDATE_TIMEOUT_NOTIFY
+#endif /* 5.3.18-38 */
+
+/*****************************************************************************/
+#if (SLE_KERNEL_CODE < SLE_KERNEL_VERSION(5,14,21,9))
+#else /* >= 5.14.21-150400.9 */
+#undef NEED_DEVLINK_ALLOC_SETS_DEV
+#define HAVE_ETHTOOL_COALESCE_EXTACK
+#endif /* 5.14.21-150400.9 */
+
+#endif /* _KCOMPAT_SLES_DEFS_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe.h b/drivers/net/ethernet/wangxun/txgbe/txgbe.h
index 38ddbde0ed0f..e3d38a73734a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe.h
@@ -1,24 +1,1365 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
 
 #ifndef _TXGBE_H_
 #define _TXGBE_H_
 
-#include "txgbe_type.h"
+#ifndef TXGBE_NO_LRO
+#include <net/tcp.h>
+#else
+#include <net/ip.h>
+#endif
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#endif
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+#include <linux/if_vlan.h>
+#endif
+
+#include "txgbe_dcb.h"
+
+#include "kcompat.h"
+
+#ifdef HAVE_NDO_BUSY_POLL
+#include <net/busy_poll.h>
+#define BP_EXTENDED_STATS
+#endif
+
+#ifdef HAVE_SCTP
+#include <linux/sctp.h>
+#endif
+
+#ifdef HAVE_INCLUDE_LINUX_MDIO_H
+#include <linux/mdio.h>
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+#include "txgbe_fcoe.h"
+#endif /* CONFIG_FCOE */
+
+
+#ifdef HAVE_PTP_1588_CLOCK
+#ifdef HAVE_INCLUDE_LINUX_TIMECOUNTER_H
+#include <linux/timecounter.h>
+#endif /* HAVE_INCLUDE_TIMECOUNTER_H */
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+#endif /* HAVE_PTP_1588_CLOCK */
+
+/* Ether Types */
+#define TXGBE_ETH_P_LLDP                        0x88CC
+#define TXGBE_ETH_P_CNM                         0x22E7
+
+/* TX/RX descriptor defines */
+#if defined(DEFAULT_TXD) || defined(DEFAULT_TX_WORK)
+#define TXGBE_DEFAULT_TXD               DEFAULT_TXD
+#define TXGBE_DEFAULT_TX_WORK           DEFAULT_TX_WORK
+#else
+#define TXGBE_DEFAULT_TXD               512
+#define TXGBE_DEFAULT_TX_WORK   256
+#endif
+#define TXGBE_MAX_TXD                   8192
+#define TXGBE_MIN_TXD                   128
+
+#if (PAGE_SIZE < 8192)
+#define TXGBE_DEFAULT_RXD               512
+#define TXGBE_DEFAULT_RX_WORK   256
+#else
+#define TXGBE_DEFAULT_RXD               256
+#define TXGBE_DEFAULT_RX_WORK   128
+#endif
+
+#define TXGBE_MAX_RXD                   8192
+#define TXGBE_MIN_RXD                   128
+
+#define TXGBE_ETH_P_LLDP                0x88CC
+
+/* flow control */
+#define TXGBE_MIN_FCRTL                 0x40
+#define TXGBE_MAX_FCRTL                 0x7FF80
+#define TXGBE_MIN_FCRTH                 0x600
+#define TXGBE_MAX_FCRTH                 0x7FFF0
+#if defined(DEFAULT_FCPAUSE)
+#define TXGBE_DEFAULT_FCPAUSE DEFAULT_FCPAUSE   /*0x3800*/
+#else
+#define TXGBE_DEFAULT_FCPAUSE   0xFFFF
+#endif
+#define TXGBE_MIN_FCPAUSE               0
+#define TXGBE_MAX_FCPAUSE               0xFFFF
+
+/* Supported Rx Buffer Sizes */
+#define TXGBE_RXBUFFER_256       256  /* Used for skb receive header */
+#define TXGBE_RXBUFFER_2K       2048
+#define TXGBE_RXBUFFER_3K       3072
+#define TXGBE_RXBUFFER_4K       4096
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+#define TXGBE_RXBUFFER_1536     1536
+#define TXGBE_RXBUFFER_7K       7168
+#define TXGBE_RXBUFFER_8K       8192
+#define TXGBE_RXBUFFER_15K      15360
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+#define TXGBE_MAX_RXBUFFER      16384  /* largest size for single descriptor */
+
+#define TXGBE_BP_M_NULL                      0
+#define TXGBE_BP_M_SFI                       1
+#define TXGBE_BP_M_KR                        2
+#define TXGBE_BP_M_KX4                       3
+#define TXGBE_BP_M_KX                        4
+#define TXGBE_BP_M_NAUTO                     0
+#define TXGBE_BP_M_AUTO                      1
+
+
+/*
+ * NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we
+ * reserve 64 more, and skb_shared_info adds an additional 320 bytes more,
+ * this adds up to 448 bytes of extra data.
+ *
+ * Since netdev_alloc_skb now allocates a page fragment we can use a value
+ * of 256 and the resultant skb will have a truesize of 960 or less.
+ */
+#define TXGBE_RX_HDR_SIZE       TXGBE_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE      (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define TXGBE_RX_BUFFER_WRITE   16      /* Must be power of 2 */
+
+#ifdef HAVE_STRUCT_DMA_ATTRS
+#define TXGBE_RX_DMA_ATTR NULL
+#else
+#define TXGBE_RX_DMA_ATTR \
+	(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
+#endif
+
+/* assume the kernel supports 8021p to avoid stripping vlan tags */
+#ifdef TXGBE_DISABLE_8021P_SUPPORT
+#ifndef HAVE_8021P_SUPPORT
+#define HAVE_8021P_SUPPORT
+#endif
+#endif /* TXGBE_DISABLE_8021P_SUPPORT */
 
+enum txgbe_tx_flags {
+	/* cmd_type flags */
+	TXGBE_TX_FLAGS_HW_VLAN  = 0x01,
+	TXGBE_TX_FLAGS_TSO      = 0x02,
+	TXGBE_TX_FLAGS_TSTAMP   = 0x04,
+
+	/* olinfo flags */
+	TXGBE_TX_FLAGS_CC       = 0x08,
+	TXGBE_TX_FLAGS_IPV4     = 0x10,
+	TXGBE_TX_FLAGS_CSUM     = 0x20,
+	TXGBE_TX_FLAGS_OUTER_IPV4 = 0x100,
+	TXGBE_TX_FLAGS_LINKSEC	= 0x200,
+	TXGBE_TX_FLAGS_IPSEC    = 0x400,
+
+	/* software defined flags */
+	TXGBE_TX_FLAGS_SW_VLAN  = 0x40,
+	TXGBE_TX_FLAGS_FCOE     = 0x80,
+};
+
+/* VLAN info */
+#define TXGBE_TX_FLAGS_VLAN_MASK        0xffff0000
+#define TXGBE_TX_FLAGS_VLAN_PRIO_MASK   0xe0000000
+#define TXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
+#define TXGBE_TX_FLAGS_VLAN_SHIFT       16
+
+#define TXGBE_MAX_RX_DESC_POLL          10
+
+#define TXGBE_MAX_VF_MC_ENTRIES         30
+#define TXGBE_MAX_VF_FUNCTIONS          64
+#define MAX_EMULATION_MAC_ADDRS         16
+#define TXGBE_MAX_PF_MACVLANS           15
+#define TXGBE_VF_DEVICE_ID		0x1000
+
+/* must account for pools assigned to VFs. */
+#ifdef CONFIG_PCI_IOV
+#define VMDQ_P(p)       ((p) + adapter->ring_feature[RING_F_VMDQ].offset)
+#else
+#define VMDQ_P(p)       (p)
+#endif
+
+struct vf_data_storage {
+	struct pci_dev *vfdev;
+	u8 IOMEM *b4_addr;
+	u32 b4_buf[16];
+	unsigned char vf_mac_addresses[ETH_ALEN];
+	u16 vf_mc_hashes[TXGBE_MAX_VF_MC_ENTRIES];
+	u16 num_vf_mc_hashes;
+	u16 default_vf_vlan_id;
+	u16 vlans_enabled;
+	bool clear_to_send;
+	bool pf_set_mac;
+	u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+	u16 pf_qos;
+	u16 min_tx_rate;
+	u16 max_tx_rate;
+	u16 vlan_count;
+	u8 spoofchk_enabled;
+	int link_enable;
+	int link_state;
+
+#ifdef HAVE_NDO_SET_VF_RSS_QUERY_EN
+	bool rss_query_enabled;
+#endif
+	u8 trusted;
+	int xcast_mode;
+	unsigned int vf_api;
+};
+
+struct vf_macvlans {
+	struct list_head l;
+	int vf;
+	bool free;
+	bool is_macvlan;
+	u8 vf_macvlan[ETH_ALEN];
+};
+
+#ifndef TXGBE_NO_LRO
+#define TXGBE_LRO_MAX           32      /*Maximum number of LRO descriptors*/
+#define TXGBE_LRO_GLOBAL        10
+
+struct txgbe_lro_stats {
+	u32 flushed;
+	u32 coal;
+};
+
+/*
+ * txgbe_lro_header - header format to be aggregated by LRO
+ * @iph: IP header without options
+ * @tcp: TCP header
+ * @ts:  Optional TCP timestamp data in TCP options
+ *
+ * This structure relies on the check above that verifies that the header
+ * is IPv4 and does not contain any options.
+ */
+struct txgbe_lrohdr {
+	struct iphdr iph;
+	struct tcphdr th;
+	__be32 ts[0];
+};
+
+struct txgbe_lro_list {
+	struct sk_buff_head active;
+	struct txgbe_lro_stats stats;
+};
+
+#endif /* TXGBE_NO_LRO */
+#define TXGBE_MAX_TXD_PWR       14
+#define TXGBE_MAX_DATA_PER_TXD  (1 << TXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S)        DIV_ROUND_UP((S), TXGBE_MAX_DATA_PER_TXD)
+#ifndef MAX_SKB_FRAGS
+#define DESC_NEEDED     4
+#elif (MAX_SKB_FRAGS < 16)
+#define DESC_NEEDED     ((MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE)) + 4)
+#else
+#define DESC_NEEDED     (MAX_SKB_FRAGS + 4)
+#endif
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct txgbe_tx_buffer {
+	union txgbe_tx_desc *next_to_watch;
+	unsigned long time_stamp;
+	struct sk_buff *skb;
+	unsigned int bytecount;
+	unsigned short gso_segs;
+	__be16 protocol;
+	DEFINE_DMA_UNMAP_ADDR(dma);
+	DEFINE_DMA_UNMAP_LEN(len);
+	u32 tx_flags;
+};
+
+struct txgbe_rx_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	dma_addr_t page_dma;
+	struct page *page;
+	unsigned int page_offset;
+#endif
+};
+
+struct txgbe_queue_stats {
+	u64 packets;
+	u64 bytes;
+#ifdef BP_EXTENDED_STATS
+	u64 yields;
+	u64 misses;
+	u64 cleaned;
+#endif  /* BP_EXTENDED_STATS */
+};
+
+struct txgbe_tx_queue_stats {
+	u64 restart_queue;
+	u64 tx_busy;
+	u64 tx_done_old;
+};
+
+struct txgbe_rx_queue_stats {
+	u64 rsc_count;
+	u64 rsc_flush;
+	u64 non_eop_descs;
+	u64 alloc_rx_page_failed;
+	u64 alloc_rx_buff_failed;
+	u64 csum_good_cnt;
+	u64 csum_err;
+};
+
+#define TXGBE_TS_HDR_LEN 8
+enum txgbe_ring_state_t {
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	__TXGBE_RX_3K_BUFFER,
+	__TXGBE_RX_BUILD_SKB_ENABLED,
+#endif
+	__TXGBE_TX_FDIR_INIT_DONE,
+	__TXGBE_TX_XPS_INIT_DONE,
+	__TXGBE_TX_DETECT_HANG,
+	__TXGBE_HANG_CHECK_ARMED,
+	__TXGBE_RX_HS_ENABLED,
+	__TXGBE_RX_RSC_ENABLED,
+#if IS_ENABLED(CONFIG_FCOE)
+	__TXGBE_RX_FCOE,
+#endif
+};
+
+struct txgbe_fwd_adapter {
+	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+	struct net_device *vdev;
+	struct txgbe_adapter *adapter;
+	unsigned int tx_base_queue;
+	unsigned int rx_base_queue;
+	int index; /* pool index on PF */
+};
+
+#define ring_uses_build_skb(ring) \
+	test_bit(__TXGBE_RX_BUILD_SKB_ENABLED, &(ring)->state)
+
+#define ring_is_hs_enabled(ring) \
+	test_bit(__TXGBE_RX_HS_ENABLED, &(ring)->state)
+#define set_ring_hs_enabled(ring) \
+	set_bit(__TXGBE_RX_HS_ENABLED, &(ring)->state)
+#define clear_ring_hs_enabled(ring) \
+	clear_bit(__TXGBE_RX_HS_ENABLED, &(ring)->state)
+#define check_for_tx_hang(ring) \
+	test_bit(__TXGBE_TX_DETECT_HANG, &(ring)->state)
+#define set_check_for_tx_hang(ring) \
+	set_bit(__TXGBE_TX_DETECT_HANG, &(ring)->state)
+#define clear_check_for_tx_hang(ring) \
+	clear_bit(__TXGBE_TX_DETECT_HANG, &(ring)->state)
+#ifndef TXGBE_NO_HW_RSC
+#define ring_is_rsc_enabled(ring) \
+	test_bit(__TXGBE_RX_RSC_ENABLED, &(ring)->state)
+#else
+#define ring_is_rsc_enabled(ring)       false
+#endif
+#define set_ring_rsc_enabled(ring) \
+	set_bit(__TXGBE_RX_RSC_ENABLED, &(ring)->state)
+#define clear_ring_rsc_enabled(ring) \
+	clear_bit(__TXGBE_RX_RSC_ENABLED, &(ring)->state)
+
+struct txgbe_ring {
+	struct txgbe_ring *next;        /* pointer to next ring in q_vector */
+	struct txgbe_q_vector *q_vector; /* backpointer to host q_vector */
+	struct net_device *netdev;      /* netdev ring belongs to */
+	struct device *dev;             /* device for DMA mapping */
+	struct txgbe_fwd_adapter *accel;
+	void *desc;                     /* descriptor ring memory */
+	union {
+		struct txgbe_tx_buffer *tx_buffer_info;
+		struct txgbe_rx_buffer *rx_buffer_info;
+	};
+	unsigned long state;
+	u8 __iomem *tail;
+	dma_addr_t dma;                 /* phys. address of descriptor ring */
+	unsigned int size;              /* length in bytes */
+
+	u16 count;                      /* amount of descriptors */
+
+	u8 queue_index; /* needed for multiqueue queue management */
+	u8 reg_idx;                     /* holds the special value that gets
+					 * the hardware register offset
+					 * associated with this ring, which is
+					 * different for DCB and RSS modes
+					 */
+	u16 next_to_use;
+	u16 next_to_clean;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	unsigned long last_rx_timestamp;
+
+#endif
+	u16 rx_buf_len;
+	union {
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		u16 next_to_alloc;
+#endif
+		struct {
+			u8 atr_sample_rate;
+			u8 atr_count;
+		};
+	};
+
+	u8 dcb_tc;
+	struct txgbe_queue_stats stats;
+#ifdef HAVE_NDO_GET_STATS64
+	struct u64_stats_sync syncp;
+#endif
+	union {
+		struct txgbe_tx_queue_stats tx_stats;
+		struct txgbe_rx_queue_stats rx_stats;
+	};
+} ____cacheline_internodealigned_in_smp;
+
+enum txgbe_ring_f_enum {
+	RING_F_NONE = 0,
+	RING_F_VMDQ,  /* SR-IOV uses the same ring feature */
+	RING_F_RSS,
+	RING_F_FDIR,
+#if IS_ENABLED(CONFIG_FCOE)
+	RING_F_FCOE,
+#endif /* CONFIG_FCOE */
+	RING_F_ARRAY_SIZE  /* must be last in enum set */
+};
+
+#define TXGBE_MAX_DCB_INDICES           8
+#define TXGBE_MAX_RSS_INDICES           63
+#define TXGBE_MAX_VMDQ_INDICES          64
 #define TXGBE_MAX_FDIR_INDICES          63
+#if IS_ENABLED(CONFIG_FCOE)
+#define TXGBE_MAX_FCOE_INDICES          8
+#define MAX_RX_QUEUES   (TXGBE_MAX_FDIR_INDICES + TXGBE_MAX_FCOE_INDICES)
+#define MAX_TX_QUEUES   (TXGBE_MAX_FDIR_INDICES + TXGBE_MAX_FCOE_INDICES)
+#else
+#define MAX_RX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
+#define MAX_TX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
+#endif /* CONFIG_FCOE */
+#define MAX_XDP_QUEUES  (TXGBE_MAX_FDIR_INDICES + 1)
+
+#define TXGBE_MAX_L2A_QUEUES    4
+#define TXGBE_BAD_L2A_QUEUE     3
+
+#define TXGBE_MAX_MACVLANS      32
+#define TXGBE_MAX_DCBMACVLANS   8
+
+struct txgbe_ring_feature {
+	u16 limit;      /* upper limit on feature indices */
+	u16 indices;    /* current value of indices */
+	u16 mask;       /* Mask used for feature to ring mapping */
+	u16 offset;     /* offset to start of feature */
+};
+
+#define TXGBE_VMDQ_8Q_MASK 0x78
+#define TXGBE_VMDQ_4Q_MASK 0x7C
+#define TXGBE_VMDQ_2Q_MASK 0x7E
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+/*
+ * FCoE requires that all Rx buffers be over 2200 bytes in length.  Since
+ * this is twice the size of a half page we need to double the page order
+ * for FCoE enabled Rx queues.
+ */
+static inline unsigned int txgbe_rx_bufsz(struct txgbe_ring __maybe_unused *ring)
+{
+#if MAX_SKB_FRAGS < 8
+	return ALIGN(TXGBE_MAX_RXBUFFER / MAX_SKB_FRAGS, 1024);
+#else
+#if IS_ENABLED(CONFIG_FCOE)
+	if (test_bit(__TXGBE_RX_FCOE, &ring->state))
+		return (PAGE_SIZE < 8192) ? TXGBE_RXBUFFER_4K :
+					    TXGBE_RXBUFFER_3K;
+#endif
+	return TXGBE_RXBUFFER_2K;
+#endif
+}
+
+static inline unsigned int txgbe_rx_pg_order(struct txgbe_ring __maybe_unused *ring)
+{
+#if IS_ENABLED(CONFIG_FCOE)
+	if (test_bit(__TXGBE_RX_FCOE, &ring->state))
+		return (PAGE_SIZE < 8192) ? 1 : 0;
+#endif
+	return 0;
+}
+#define txgbe_rx_pg_size(_ring) (PAGE_SIZE << txgbe_rx_pg_order(_ring))
+
+#endif
+struct txgbe_ring_container {
+	struct txgbe_ring *ring;        /* pointer to linked list of rings */
+	unsigned int total_bytes;       /* total bytes processed this int */
+	unsigned int total_packets;     /* total packets processed this int */
+	u16 work_limit;                 /* total work allowed per interrupt */
+	u8 count;                       /* total number of rings in vector */
+	u8 itr;                         /* current ITR setting for ring */
+};
+
+/* iterator for handling rings in ring container */
+#define txgbe_for_each_ring(pos, head) \
+	for (pos = (head).ring; pos != NULL; pos = pos->next)
+
+#define MAX_RX_PACKET_BUFFERS   ((adapter->flags & TXGBE_FLAG_DCB_ENABLED) \
+				 ? 8 : 1)
+#define MAX_TX_PACKET_BUFFERS   MAX_RX_PACKET_BUFFERS
+
+/* MAX_MSIX_Q_VECTORS of these are allocated,
+ * but we only use one per queue-specific vector.
+ */
+struct txgbe_q_vector {
+	struct txgbe_adapter *adapter;
+	int cpu;        /* CPU for DCA */
+	u16 v_idx;      /* index of q_vector within array, also used for
+			 * finding the bit in EICR and friends that
+			 * represents the vector for this ring */
+	u16 itr;        /* Interrupt throttle rate written to EITR */
+	struct txgbe_ring_container rx, tx;
+
+	struct napi_struct napi;
+#ifndef HAVE_NETDEV_NAPI_LIST
+	struct net_device poll_dev;
+#endif
+#ifdef HAVE_IRQ_AFFINITY_HINT
+	cpumask_t affinity_mask;
+#endif
+#ifndef TXGBE_NO_LRO
+	struct txgbe_lro_list lrolist;   /* LRO list for queue vector*/
+#endif
+	int numa_node;
+	struct rcu_head rcu;    /* to avoid race with update stats on free */
+	char name[IFNAMSIZ + 17];
+	bool netpoll_rx;
+
+#ifdef HAVE_NDO_BUSY_POLL
+	atomic_t state;
+#endif  /* HAVE_NDO_BUSY_POLL */
+
+	/* for dynamic allocation of rings associated with this q_vector */
+	struct txgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
+};
+
+#ifdef HAVE_NDO_BUSY_POLL
+enum txgbe_qv_state_t {
+	TXGBE_QV_STATE_IDLE = 0,
+	TXGBE_QV_STATE_NAPI,
+	TXGBE_QV_STATE_POLL,
+	TXGBE_QV_STATE_DISABLE
+};
+
+static inline void txgbe_qv_init_lock(struct txgbe_q_vector *q_vector)
+{
+	/* reset state to idle */
+	atomic_set(&q_vector->state, TXGBE_QV_STATE_IDLE);
+}
+
+/* called from the device poll routine to get ownership of a q_vector */
+static inline bool txgbe_qv_lock_napi(struct txgbe_q_vector *q_vector)
+{
+	int rc = atomic_cmpxchg(&q_vector->state, TXGBE_QV_STATE_IDLE,
+				TXGBE_QV_STATE_NAPI);
+#ifdef BP_EXTENDED_STATS
+	if (rc != TXGBE_QV_STATE_IDLE)
+		q_vector->tx.ring->stats.yields++;
+#endif
+
+	return rc == TXGBE_QV_STATE_IDLE;
+}
+
+/* returns true is someone tried to get the qv while napi had it */
+static inline void txgbe_qv_unlock_napi(struct txgbe_q_vector *q_vector)
+{
+	WARN_ON(atomic_read(&q_vector->state) != TXGBE_QV_STATE_NAPI);
+
+	/* flush any outstanding Rx frames */
+	if (q_vector->napi.gro_list)
+		napi_gro_flush(&q_vector->napi, false);
+
+	/* reset state to idle */
+	atomic_set(&q_vector->state, TXGBE_QV_STATE_IDLE);
+}
+
+/* called from txgbe_low_latency_poll() */
+static inline bool txgbe_qv_lock_poll(struct txgbe_q_vector *q_vector)
+{
+	int rc = atomic_cmpxchg(&q_vector->state, TXGBE_QV_STATE_IDLE,
+				TXGBE_QV_STATE_POLL);
+#ifdef BP_EXTENDED_STATS
+	if (rc != TXGBE_QV_STATE_IDLE)
+		q_vector->tx.ring->stats.yields++;
+#endif
+	return rc == TXGBE_QV_STATE_IDLE;
+}
+
+/* returns true if someone tried to get the qv while it was locked */
+static inline void txgbe_qv_unlock_poll(struct txgbe_q_vector *q_vector)
+{
+	WARN_ON(atomic_read(&q_vector->state) != TXGBE_QV_STATE_POLL);
+
+	/* reset state to idle */
+	atomic_set(&q_vector->state, TXGBE_QV_STATE_IDLE);
+}
+
+/* true if a socket is polling, even if it did not get the lock */
+static inline bool txgbe_qv_busy_polling(struct txgbe_q_vector *q_vector)
+{
+	return atomic_read(&q_vector->state) == TXGBE_QV_STATE_POLL;
+}
 
-#define TXGBE_MAX_RX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
-#define TXGBE_MAX_TX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
+/* false if QV is currently owned */
+static inline bool txgbe_qv_disable(struct txgbe_q_vector *q_vector)
+{
+	int rc = atomic_cmpxchg(&q_vector->state, TXGBE_QV_STATE_IDLE,
+				TXGBE_QV_STATE_DISABLE);
+
+	return rc == TXGBE_QV_STATE_IDLE;
+}
+
+#endif /* HAVE_NDO_BUSY_POLL */
+#ifdef TXGBE_HWMON
+
+#define TXGBE_HWMON_TYPE_TEMP           0
+#define TXGBE_HWMON_TYPE_ALARMTHRESH    1
+#define TXGBE_HWMON_TYPE_DALARMTHRESH   2
+
+struct hwmon_attr {
+	struct device_attribute dev_attr;
+	struct txgbe_hw *hw;
+	struct txgbe_thermal_diode_data *sensor;
+	char name[19];
+};
+
+struct hwmon_buff {
+	struct device *device;
+	struct hwmon_attr *hwmon_list;
+	unsigned int n_hwmon;
+};
+#endif /* TXGBE_HWMON */
+
+/*
+ * microsecond values for various ITR rates shifted by 2 to fit itr register
+ * with the first 3 bits reserved 0
+ */
+#define TXGBE_MIN_RSC_ITR       24
+#define TXGBE_100K_ITR          40
+#define TXGBE_20K_ITR           200
+#define TXGBE_16K_ITR           248
+#define TXGBE_12K_ITR           336
+
+/* txgbe_test_staterr - tests bits in Rx descriptor status and error fields */
+static inline __le32 txgbe_test_staterr(union txgbe_rx_desc *rx_desc,
+					const u32 stat_err_bits)
+{
+	return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
+}
+
+/* txgbe_desc_unused - calculate if we have unused descriptors */
+static inline u16 txgbe_desc_unused(struct txgbe_ring *ring)
+{
+	u16 ntc = ring->next_to_clean;
+	u16 ntu = ring->next_to_use;
+
+	return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
+}
+
+#define TXGBE_RX_DESC(R, i)     \
+	(&(((union txgbe_rx_desc *)((R)->desc))[i]))
+#define TXGBE_TX_DESC(R, i)     \
+	(&(((union txgbe_tx_desc *)((R)->desc))[i]))
+#define TXGBE_TX_CTXTDESC(R, i) \
+	(&(((struct txgbe_tx_context_desc *)((R)->desc))[i]))
+
+#define TXGBE_MAX_JUMBO_FRAME_SIZE      9432 /* max payload 9414 */
+#if IS_ENABLED(CONFIG_FCOE)
+/* use 3K as the baby jumbo frame size for FCoE */
+#define TXGBE_FCOE_JUMBO_FRAME_SIZE     3072
+#endif /* CONFIG_FCOE */
+
+#define TCP_TIMER_VECTOR        0
+#define OTHER_VECTOR    1
+#define NON_Q_VECTORS   (OTHER_VECTOR + TCP_TIMER_VECTOR)
+
+#define TXGBE_MAX_MSIX_Q_VECTORS_SAPPHIRE       64
+
+struct txgbe_mac_addr {
+	u8 addr[ETH_ALEN];
+	u16 state; /* bitmask */
+	u64 pools;
+};
+
+#define TXGBE_MAC_STATE_DEFAULT         0x1
+#define TXGBE_MAC_STATE_MODIFIED        0x2
+#define TXGBE_MAC_STATE_IN_USE          0x4
+
+#ifdef TXGBE_PROCFS
+struct txgbe_therm_proc_data {
+	struct txgbe_hw *hw;
+	struct txgbe_thermal_diode_data *sensor_data;
+};
+#endif
+
+/*
+ * Only for array allocations in our adapter struct.
+ * we can actually assign 64 queue vectors based on our extended-extended
+ * interrupt registers.
+ */
+#define MAX_MSIX_Q_VECTORS      TXGBE_MAX_MSIX_Q_VECTORS_SAPPHIRE
+#define MAX_MSIX_COUNT          TXGBE_MAX_MSIX_VECTORS_SAPPHIRE
+
+#define MIN_MSIX_Q_VECTORS      1
+#define MIN_MSIX_COUNT          (MIN_MSIX_Q_VECTORS + NON_Q_VECTORS)
+
+/* default to trying for four seconds */
+#define TXGBE_TRY_LINK_TIMEOUT  (4 * HZ)
+#define TXGBE_SFP_POLL_JIFFIES  (2 * HZ)        /* SFP poll every 2 seconds */
+
+/**
+ * txgbe_adapter.flag
+ **/
+#define TXGBE_FLAG_MSI_CAPABLE                  (u32)(1 << 0)
+#define TXGBE_FLAG_MSI_ENABLED                  (u32)(1 << 1)
+#define TXGBE_FLAG_MSIX_CAPABLE                 (u32)(1 << 2)
+#define TXGBE_FLAG_MSIX_ENABLED                 (u32)(1 << 3)
+#ifndef TXGBE_NO_LLI
+#define TXGBE_FLAG_LLI_PUSH                     (u32)(1 << 4)
+#endif
+
+#define TXGBE_FLAG_TPH_ENABLED                  (u32)(1 << 6)
+#define TXGBE_FLAG_TPH_CAPABLE                  (u32)(1 << 7)
+#define TXGBE_FLAG_TPH_ENABLED_DATA             (u32)(1 << 8)
+
+#define TXGBE_FLAG_MQ_CAPABLE                   (u32)(1 << 9)
+#define TXGBE_FLAG_DCB_ENABLED                  (u32)(1 << 10)
+#define TXGBE_FLAG_VMDQ_ENABLED                 (u32)(1 << 11)
+#define TXGBE_FLAG_FAN_FAIL_CAPABLE             (u32)(1 << 12)
+#define TXGBE_FLAG_NEED_LINK_UPDATE             (u32)(1 << 13)
+#define TXGBE_FLAG_NEED_LINK_CONFIG             (u32)(1 << 14)
+#define TXGBE_FLAG_FDIR_HASH_CAPABLE            (u32)(1 << 15)
+#define TXGBE_FLAG_FDIR_PERFECT_CAPABLE         (u32)(1 << 16)
+#if IS_ENABLED(CONFIG_FCOE)
+#define TXGBE_FLAG_FCOE_CAPABLE                 (u32)(1 << 17)
+#define TXGBE_FLAG_FCOE_ENABLED                 (u32)(1 << 18)
+#endif /* CONFIG_FCOE */
+#define TXGBE_FLAG_SRIOV_CAPABLE                (u32)(1 << 19)
+#define TXGBE_FLAG_SRIOV_ENABLED                (u32)(1 << 20)
+#define TXGBE_FLAG_SRIOV_REPLICATION_ENABLE     (u32)(1 << 21)
+#define TXGBE_FLAG_SRIOV_L2SWITCH_ENABLE        (u32)(1 << 22)
+#define TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE       (u32)(1 << 23)
+#define TXGBE_FLAG_RX_HWTSTAMP_ENABLED          (u32)(1 << 24)
+#define TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE        (u32)(1 << 25)
+#define TXGBE_FLAG_VXLAN_OFFLOAD_ENABLE         (u32)(1 << 26)
+#define TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER      (u32)(1 << 27)
+#define TXGBE_FLAG_NEED_ETH_PHY_RESET           (u32)(1 << 28)
+#define TXGBE_FLAG_RX_HS_ENABLED                (u32)(1 << 30)
+#define TXGBE_FLAG_LINKSEC_ENABLED              (u32)(1 << 31)
+#define TXGBE_FLAG_IPSEC_ENABLED                (u32)(1 << 5)
+
+/* preset defaults */
+#define TXGBE_FLAGS_SP_INIT (TXGBE_FLAG_MSI_CAPABLE \
+			   | TXGBE_FLAG_MSIX_CAPABLE \
+			   | TXGBE_FLAG_MQ_CAPABLE \
+			   | TXGBE_FLAG_SRIOV_CAPABLE)
+
+/**
+ * txgbe_adapter.flag2
+ **/
+#ifndef TXGBE_NO_HW_RSC
+#define TXGBE_FLAG2_RSC_CAPABLE                 (1U << 0)
+#define TXGBE_FLAG2_RSC_ENABLED                 (1U << 1)
+#else
+#define TXGBE_FLAG2_RSC_CAPABLE                 (0U)
+#define TXGBE_FLAG2_RSC_ENABLED                 (0U)
+#endif
+#define TXGBE_FLAG2_TEMP_SENSOR_CAPABLE         (1U << 3)
+#define TXGBE_FLAG2_TEMP_SENSOR_EVENT           (1U << 4)
+#define TXGBE_FLAG2_SEARCH_FOR_SFP              (1U << 5)
+#define TXGBE_FLAG2_SFP_NEEDS_RESET             (1U << 6)
+#define TXGBE_FLAG2_PF_RESET_REQUESTED          (1U << 7)
+#define TXGBE_FLAG2_FDIR_REQUIRES_REINIT        (1U << 8)
+#define TXGBE_FLAG2_RSS_FIELD_IPV4_UDP          (1U << 9)
+#define TXGBE_FLAG2_RSS_FIELD_IPV6_UDP          (1U << 10)
+#define TXGBE_FLAG2_RSS_ENABLED                 (1U << 12)
+#define TXGBE_FLAG2_PTP_PPS_ENABLED             (1U << 11)
+#define TXGBE_FLAG2_EEE_CAPABLE                 (1U << 14)
+#define TXGBE_FLAG2_EEE_ENABLED                 (1U << 15)
+#define TXGBE_FLAG2_VXLAN_REREG_NEEDED          (1U << 16)
+#define TXGBE_FLAG2_DEV_RESET_REQUESTED         (1U << 18)
+#define TXGBE_FLAG2_RESET_INTR_RECEIVED         (1U << 19)
+#define TXGBE_FLAG2_GLOBAL_RESET_REQUESTED      (1U << 20)
+#define TXGBE_FLAG2_CLOUD_SWITCH_ENABLED        (1U << 21)
+#define TXGBE_FLAG2_MNG_REG_ACCESS_DISABLED     (1U << 22)
+#define KR                                      (1U << 23)
+#define TXGBE_FLAG2_KR_TRAINING                 (1U << 24)
+#define TXGBE_FLAG2_KR_AUTO                     (1U << 25)
+#define TXGBE_FLAG2_LINK_DOWN                   (1U << 26)
+#define TXGBE_FLAG2_KR_PRO_DOWN                 (1U << 27)
+#define TXGBE_FLAG2_KR_PRO_REINIT               (1U << 28)
+#define TXGBE_FLAG2_PCIE_NEED_RECOVER           (1U << 31)
+
+
+#define TXGBE_SET_FLAG(_input, _flag, _result) \
+	((_flag <= _result) ? \
+	 ((u32)(_input & _flag) * (_result / _flag)) : \
+	 ((u32)(_input & _flag) / (_flag / _result)))
+
+enum txgbe_isb_idx {
+	TXGBE_ISB_HEADER,
+	TXGBE_ISB_MISC,
+	TXGBE_ISB_VEC0,
+	TXGBE_ISB_VEC1,
+	TXGBE_ISB_MAX
+};
 
 /* board specific private data structure */
 struct txgbe_adapter {
-	u8 __iomem *io_addr;    /* Mainly for iounmap use */
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) ||\
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+#ifdef HAVE_VLAN_RX_REGISTER
+	struct vlan_group *vlgrp; /* must be first, see txgbe_receive_skb */
+#else /* HAVE_VLAN_RX_REGISTER */
+	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+#endif /* HAVE_VLAN_RX_REGISTER */
+#endif
 	/* OS defined structs */
 	struct net_device *netdev;
 	struct pci_dev *pdev;
+
+	unsigned long state;
+
+	/* Some features need tri-state capability,
+	 * thus the additional *_CAPABLE flags.
+	 */
+	u32 flags;
+	u32 flags2;
+	u8  an73_mode;
+	u8  vf_mode;
+	u8  backplane_an;
+	u8  an73;
+	u8  an37;
+	u16 ffe_main;
+	u16 ffe_pre;
+	u16 ffe_post;
+	u8  ffe_set;
+	u8  backplane_mode;
+	u8  backplane_auto;
+
+	bool cloud_mode;
+
+	/* Tx fast path data */
+	int num_tx_queues;
+	u16 tx_itr_setting;
+	u16 tx_work_limit;
+
+	/* Rx fast path data */
+	int num_rx_queues;
+	u16 rx_itr_setting;
+	u16 rx_work_limit;
+
+	unsigned int num_vmdqs; /* does not include pools assigned to VFs */
+	unsigned int queues_per_pool;
+
+	/* XDP */
+	int num_xdp_queues;
+	struct txgbe_ring *xdp_ring[MAX_XDP_QUEUES];
+
+	/* TX */
+	struct txgbe_ring *tx_ring[MAX_TX_QUEUES] ____cacheline_aligned_in_smp;
+
+	u64 restart_queue;
+	u64 lsc_int;
+	u32 tx_timeout_count;
+
+	/* RX */
+	struct txgbe_ring *rx_ring[MAX_RX_QUEUES];
+	int num_rx_pools; /* does not include pools assigned to VFs */
+	int num_rx_queues_per_pool;
+	u64 hw_csum_rx_error;
+	u64 hw_csum_rx_good;
+	u64 hw_rx_no_dma_resources;
+	u64 rsc_total_count;
+	u64 rsc_total_flush;
+	u64 non_eop_descs;
+	u32 alloc_rx_page_failed;
+	u32 alloc_rx_buff_failed;
+
+	struct txgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+
+#ifdef HAVE_DCBNL_IEEE
+	struct ieee_pfc *txgbe_ieee_pfc;
+	struct ieee_ets *txgbe_ieee_ets;
+#endif
+	struct txgbe_dcb_config dcb_cfg;
+	struct txgbe_dcb_config temp_dcb_cfg;
+	u8 dcb_set_bitmap;
+	u8 dcbx_cap;
+#ifndef HAVE_MQPRIO
+	u8 dcb_tc;
+#endif
+	enum txgbe_fc_mode last_lfc_mode;
+
+	int num_q_vectors;      /* current number of q_vectors for device */
+	int max_q_vectors;      /* upper limit of q_vectors for device */
+	struct txgbe_ring_feature ring_feature[RING_F_ARRAY_SIZE];
+	struct msix_entry *msix_entries;
+
+#ifndef HAVE_NETDEV_STATS_IN_NETDEV
+	struct net_device_stats net_stats;
+#endif
+#ifndef TXGBE_NO_LRO
+	struct txgbe_lro_stats lro_stats;
+#endif
+
+#ifdef ETHTOOL_TEST
+	u64 test_icr;
+	struct txgbe_ring test_tx_ring;
+	struct txgbe_ring test_rx_ring;
+#endif
+
+	/* structs defined in txgbe_hw.h */
+	struct txgbe_hw hw;
+	u16 msg_enable;
+	struct txgbe_hw_stats stats;
+#ifndef TXGBE_NO_LLI
+	u32 lli_port;
+	u32 lli_size;
+	u32 lli_etype;
+	u32 lli_vlan_pri;
+#endif /* TXGBE_NO_LLI */
+
+	u32 *config_space;
+	u64 tx_busy;
+	unsigned int tx_ring_count;
+	unsigned int rx_ring_count;
+
+	u32 link_speed;
+	bool link_up;
+	unsigned long sfp_poll_time;
+	unsigned long link_check_timeout;
+
+	struct timer_list service_timer;
+	struct work_struct service_task;
+	struct work_struct sfp_sta_task;
+#ifdef POLL_LINK_STATUS
+	struct timer_list link_check_timer;
+#endif
+	struct hlist_head fdir_filter_list;
+	unsigned long fdir_overflow; /* number of times ATR was backed off */
+	union txgbe_atr_input fdir_mask;
+	int fdir_filter_count;
+	u32 fdir_pballoc;
+	u32 atr_sample_rate;
+	spinlock_t fdir_perfect_lock;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	struct txgbe_fcoe fcoe;
+#endif /* CONFIG_FCOE */
+	u8 __iomem *io_addr;    /* Mainly for iounmap use */
+	u32 wol;
+
+	u16 bd_number;
+
+#ifdef HAVE_BRIDGE_ATTRIBS
+	u16 bridge_mode;
+#endif
+
+	char eeprom_id[32];
+	u16 eeprom_cap;
+	bool netdev_registered;
+	u32 interrupt_event;
+#ifdef HAVE_ETHTOOL_SET_PHYS_ID
+	u32 led_reg;
+#endif
+
+#ifdef HAVE_PTP_1588_CLOCK
+	struct ptp_clock *ptp_clock;
+	struct ptp_clock_info ptp_caps;
+	struct work_struct ptp_tx_work;
+	struct sk_buff *ptp_tx_skb;
+	struct hwtstamp_config tstamp_config;
+	unsigned long ptp_tx_start;
+	unsigned long last_overflow_check;
+	unsigned long last_rx_ptp_check;
+	spinlock_t tmreg_lock;
+	struct cyclecounter hw_cc;
+	struct timecounter hw_tc;
+	u32 base_incval;
+	u32 tx_hwtstamp_timeouts;
+	u32 tx_hwtstamp_skipped;
+	u32 rx_hwtstamp_cleared;
+	void (*ptp_setup_sdp) (struct txgbe_adapter *);
+#endif /* HAVE_PTP_1588_CLOCK */
+
+	DECLARE_BITMAP(active_vfs, TXGBE_MAX_VF_FUNCTIONS);
+	unsigned int num_vfs;
+	struct vf_data_storage *vfinfo;
+	struct vf_macvlans vf_mvs;
+	struct vf_macvlans *mv_list;
+#ifdef CONFIG_PCI_IOV
+	u32 timer_event_accumulator;
+	u32 vferr_refcount;
+#endif
+	struct txgbe_mac_addr *mac_table;
+#if defined(HAVE_UDP_ENC_RX_OFFLOAD) || defined(HAVE_VXLAN_RX_OFFLOAD)
+	__le16 vxlan_port;
+#endif /* HAVE_UDP_ENC_RX_OFFLAD || HAVE_VXLAN_RX_OFFLOAD */
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+	__le16 geneve_port;
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD */
+#ifdef TXGBE_SYSFS
+#ifdef TXGBE_HWMON
+	struct hwmon_buff txgbe_hwmon_buff;
+#endif /* TXGBE_HWMON */
+#else /* TXGBE_SYSFS */
+#ifdef TXGBE_PROCFS
+	struct proc_dir_entry *eth_dir;
+	struct proc_dir_entry *info_dir;
+	u64 old_lsc;
+	struct proc_dir_entry *therm_dir;
+	struct txgbe_therm_proc_data therm_data;
+#endif /* TXGBE_PROCFS */
+#endif /* TXGBE_SYSFS */
+
+#ifdef HAVE_TXGBE_DEBUG_FS
+	struct dentry *txgbe_dbg_adapter;
+#endif /*HAVE_TXGBE_DEBUG_FS*/
+	u8 default_up;
+#ifdef HAVE_TX_MQ
+#ifndef HAVE_NETDEV_SELECT_QUEUE
+	unsigned int indices;
+#endif /* !HAVE_NETDEV_SELECT_QUEUE*/
+#endif /* HAVE_TX_MQ */
+	unsigned long fwd_bitmask; /* bitmask indicating in use pools */
+	unsigned long tx_timeout_last_recovery;
+	u32 tx_timeout_recovery_level;
+
+#define TXGBE_MAX_RETA_ENTRIES 128
+	u8 rss_indir_tbl[TXGBE_MAX_RETA_ENTRIES];
+#define TXGBE_RSS_KEY_SIZE     40
+	u32 rss_key[TXGBE_RSS_KEY_SIZE / sizeof(u32)];
+
+	void *ipsec;
+
+	/* misc interrupt status block */
+	dma_addr_t isb_dma;
+	u32 *isb_mem;
+	u32 isb_tag[TXGBE_ISB_MAX];
+
+	u64 eth_priv_flags;
+#define TXGBE_ETH_PRIV_FLAG_LLDP		BIT(0)
+};
+
+static inline u32 txgbe_misc_isb(struct txgbe_adapter *adapter,
+				 enum txgbe_isb_idx idx)
+{
+	u32 cur_tag = 0;
+	u32 cur_diff = 0;
+    
+    cur_tag = adapter->isb_mem[TXGBE_ISB_HEADER];
+    cur_diff = cur_tag - adapter->isb_tag[idx];
+
+	adapter->isb_tag[idx] = cur_tag;
+
+	return adapter->isb_mem[idx];
+}
+
+static inline u8 txgbe_max_rss_indices(struct txgbe_adapter *adapter)
+{
+	return TXGBE_MAX_RSS_INDICES;
+}
+
+struct txgbe_fdir_filter {
+	struct  hlist_node fdir_node;
+	union txgbe_atr_input filter;
+	u16 sw_idx;
+	u16 action;
+};
+
+enum txgbe_state_t {
+	__TXGBE_TESTING,
+	__TXGBE_RESETTING,
+	__TXGBE_DOWN,
+	__TXGBE_HANGING,
+	__TXGBE_DISABLED,
+	__TXGBE_REMOVING,
+	__TXGBE_SERVICE_SCHED,
+	__TXGBE_SERVICE_INITED,
+	__TXGBE_IN_SFP_INIT,
+#ifdef HAVE_PTP_1588_CLOCK
+	__TXGBE_PTP_RUNNING,
+	__TXGBE_PTP_TX_IN_PROGRESS,
+#endif
 };
 
+struct txgbe_cb {
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	union {                         /* Union defining head/tail partner */
+		struct sk_buff *head;
+		struct sk_buff *tail;
+	};
+#endif
+	dma_addr_t dma;
+#ifndef TXGBE_NO_LRO
+	__be32  tsecr;                  /* timestamp echo response */
+	u32     tsval;                  /* timestamp value in host order */
+	u32     next_seq;               /* next expected sequence number */
+	u16     free;                   /* 65521 minus total size */
+	u16     mss;                    /* size of data portion of packet */
+#endif /* TXGBE_NO_LRO */
+#ifdef HAVE_VLAN_RX_REGISTER
+	u16     vid;                    /* VLAN tag */
+#endif
+	u16     append_cnt;             /* number of skb's appended */
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	bool    page_released;
+	bool    dma_released;
+#endif
+};
+#define TXGBE_CB(skb) ((struct txgbe_cb *)(skb)->cb)
+
+/* ESX txgbe CIM IOCTL definition */
+
+#ifdef TXGBE_SYSFS
+void txgbe_sysfs_exit(struct txgbe_adapter *adapter);
+int txgbe_sysfs_init(struct txgbe_adapter *adapter);
+#endif /* TXGBE_SYSFS */
+#ifdef TXGBE_PROCFS
+void txgbe_procfs_exit(struct txgbe_adapter *adapter);
+int txgbe_procfs_init(struct txgbe_adapter *adapter);
+int txgbe_procfs_topdir_init(void);
+void txgbe_procfs_topdir_exit(void);
+#endif /* TXGBE_PROCFS */
+
+extern struct dcbnl_rtnl_ops dcbnl_ops;
+int txgbe_copy_dcb_cfg(struct txgbe_adapter *adapter, int tc_max);
+
+u8 txgbe_dcb_txq_to_tc(struct txgbe_adapter *adapter, u8 index);
+
+/* needed by txgbe_main.c */
+int txgbe_validate_mac_addr(u8 *mc_addr);
+void txgbe_check_options(struct txgbe_adapter *adapter);
+void txgbe_assign_netdev_ops(struct net_device *netdev);
+
+/* needed by txgbe_ethtool.c */
 extern char txgbe_driver_name[];
+extern const char txgbe_driver_version[];
+
+void txgbe_irq_disable(struct txgbe_adapter *adapter);
+void txgbe_irq_enable(struct txgbe_adapter *adapter, bool queues, bool flush);
+int txgbe_open(struct net_device *netdev);
+int txgbe_close(struct net_device *netdev);
+void txgbe_up(struct txgbe_adapter *adapter);
+void txgbe_down(struct txgbe_adapter *adapter);
+void txgbe_reinit_locked(struct txgbe_adapter *adapter);
+void txgbe_reset(struct txgbe_adapter *adapter);
+void txgbe_set_ethtool_ops(struct net_device *netdev);
+int txgbe_setup_rx_resources(struct txgbe_ring *);
+int txgbe_setup_tx_resources(struct txgbe_ring *);
+void txgbe_free_rx_resources(struct txgbe_ring *);
+void txgbe_free_tx_resources(struct txgbe_ring *);
+void txgbe_configure_rx_ring(struct txgbe_adapter *,
+				    struct txgbe_ring *);
+void txgbe_configure_tx_ring(struct txgbe_adapter *,
+				    struct txgbe_ring *);
+void txgbe_update_stats(struct txgbe_adapter *adapter);
+int txgbe_init_interrupt_scheme(struct txgbe_adapter *adapter);
+void txgbe_reset_interrupt_capability(struct txgbe_adapter *adapter);
+void txgbe_set_interrupt_capability(struct txgbe_adapter *adapter);
+void txgbe_clear_interrupt_scheme(struct txgbe_adapter *adapter);
+bool txgbe_is_txgbe(struct pci_dev *pcidev);
+netdev_tx_t txgbe_xmit_frame_ring(struct sk_buff *,
+					 struct txgbe_adapter *,
+					 struct txgbe_ring *);
+void txgbe_unmap_and_free_tx_resource(struct txgbe_ring *,
+					     struct txgbe_tx_buffer *);
+void txgbe_alloc_rx_buffers(struct txgbe_ring *, u16);
+void txgbe_configure_rscctl(struct txgbe_adapter *adapter,
+				   struct txgbe_ring *);
+void txgbe_clear_rscctl(struct txgbe_adapter *adapter,
+			       struct txgbe_ring *);
+void txgbe_clear_vxlan_port(struct txgbe_adapter *);
+void txgbe_set_rx_mode(struct net_device *netdev);
+int txgbe_write_mc_addr_list(struct net_device *netdev);
+int txgbe_setup_tc(struct net_device *dev, u8 tc);
+void txgbe_tx_ctxtdesc(struct txgbe_ring *, u32, u32, u32, u32);
+void txgbe_do_reset(struct net_device *netdev);
+void txgbe_write_eitr(struct txgbe_q_vector *q_vector);
+int txgbe_poll(struct napi_struct *napi, int budget);
+void txgbe_disable_rx_queue(struct txgbe_adapter *adapter,
+				   struct txgbe_ring *);
+void txgbe_vlan_strip_enable(struct txgbe_adapter *adapter);
+void txgbe_vlan_strip_disable(struct txgbe_adapter *adapter);
+#ifdef ETHTOOL_OPS_COMPAT
+int ethtool_ioctl(struct ifreq *ifr);
+#endif
+void txgbe_print_tx_hang_status(struct txgbe_adapter *adapter);
+
+#if IS_ENABLED(CONFIG_FCOE)
+void txgbe_configure_fcoe(struct txgbe_adapter *adapter);
+int txgbe_fso(struct txgbe_ring *tx_ring,
+		     struct txgbe_tx_buffer *first,
+		     u8 *hdr_len);
+int txgbe_fcoe_ddp(struct txgbe_adapter *adapter,
+			  union txgbe_rx_desc *rx_desc,
+			  struct sk_buff *skb);
+int txgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
+			      struct scatterlist *sgl, unsigned int sgc);
+#ifdef HAVE_NETDEV_OPS_FCOE_DDP_TARGET
+int txgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid,
+				 struct scatterlist *sgl, unsigned int sgc);
+#endif /* HAVE_NETDEV_OPS_FCOE_DDP_TARGET */
+int txgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid);
+int txgbe_setup_fcoe_ddp_resources(struct txgbe_adapter *adapter);
+void txgbe_free_fcoe_ddp_resources(struct txgbe_adapter *adapter);
+#ifdef HAVE_NETDEV_OPS_FCOE_ENABLE
+int txgbe_fcoe_enable(struct net_device *netdev);
+int txgbe_fcoe_disable(struct net_device *netdev);
+#else
+int txgbe_fcoe_ddp_enable(struct txgbe_adapter *adapter);
+void txgbe_fcoe_ddp_disable(struct txgbe_adapter *adapter);
+#endif /* HAVE_NETDEV_OPS_FCOE_ENABLE */
+#if IS_ENABLED(CONFIG_DCB)
+#ifdef HAVE_DCBNL_OPS_GETAPP
+u8 txgbe_fcoe_getapp(struct net_device *netdev);
+#endif /* HAVE_DCBNL_OPS_GETAPP */
+u8 txgbe_fcoe_setapp(struct txgbe_adapter *adapter, u8 up);
+#endif /* CONFIG_DCB */
+u8 txgbe_fcoe_get_tc(struct txgbe_adapter *adapter);
+#ifdef HAVE_NETDEV_OPS_FCOE_GETWWN
+int txgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type);
+#endif
+#endif /* CONFIG_FCOE */
+
+#ifdef HAVE_TXGBE_DEBUG_FS
+void txgbe_dbg_adapter_init(struct txgbe_adapter *adapter);
+void txgbe_dbg_adapter_exit(struct txgbe_adapter *adapter);
+void txgbe_dbg_init(void);
+void txgbe_dbg_exit(void);
+#endif /* HAVE_TXGBE_DEBUG_FS */
+void txgbe_dump(struct txgbe_adapter *adapter);
+
+static inline struct netdev_queue *txring_txq(const struct txgbe_ring *ring)
+{
+	return netdev_get_tx_queue(ring->netdev, ring->queue_index);
+}
+
+#if IS_ENABLED(CONFIG_DCB)
+#ifdef HAVE_DCBNL_IEEE
+s32 txgbe_dcb_hw_ets(struct txgbe_hw *hw, struct ieee_ets *ets, int max_frame);
+#endif /* HAVE_DCBNL_IEEE */
+#endif /* CONFIG_DCB */
+
+int txgbe_wol_supported(struct txgbe_adapter *adapter);
+int txgbe_get_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd);
+int txgbe_write_uc_addr_list(struct net_device *netdev, int pool);
+void txgbe_full_sync_mac_table(struct txgbe_adapter *adapter);
+int txgbe_add_mac_filter(struct txgbe_adapter *adapter,
+				u8 *addr, u16 pool);
+int txgbe_del_mac_filter(struct txgbe_adapter *adapter,
+				u8 *addr, u16 pool);
+int txgbe_available_rars(struct txgbe_adapter *adapter);
+#ifndef HAVE_VLAN_RX_REGISTER
+void txgbe_vlan_mode(struct net_device *, u32);
+#endif
+
+#ifdef HAVE_PTP_1588_CLOCK
+void txgbe_ptp_init(struct txgbe_adapter *adapter);
+void txgbe_ptp_stop(struct txgbe_adapter *adapter);
+void txgbe_ptp_suspend(struct txgbe_adapter *adapter);
+void txgbe_ptp_overflow_check(struct txgbe_adapter *adapter);
+void txgbe_ptp_rx_hang(struct txgbe_adapter *adapter);
+void txgbe_ptp_rx_hwtstamp(struct txgbe_adapter *adapter, struct sk_buff *skb);
+int txgbe_ptp_set_ts_config(struct txgbe_adapter *adapter, struct ifreq *ifr);
+int txgbe_ptp_get_ts_config(struct txgbe_adapter *adapter, struct ifreq *ifr);
+void txgbe_ptp_start_cyclecounter(struct txgbe_adapter *adapter);
+void txgbe_ptp_reset(struct txgbe_adapter *adapter);
+void txgbe_ptp_check_pps_event(struct txgbe_adapter *adapter);
+#endif /* HAVE_PTP_1588_CLOCK */
+#ifdef CONFIG_PCI_IOV
+void txgbe_sriov_reinit(struct txgbe_adapter *adapter);
+#endif
+
+void txgbe_set_rx_drop_en(struct txgbe_adapter *adapter);
+
+u32 txgbe_rss_indir_tbl_entries(struct txgbe_adapter *adapter);
+void txgbe_store_reta(struct txgbe_adapter *adapter);
+
+int txgbe_setup_isb_resources(struct txgbe_adapter *adapter);
+void txgbe_free_isb_resources(struct txgbe_adapter *adapter);
+void txgbe_configure_isb(struct txgbe_adapter *adapter);
+
+/**
+ * interrupt masking operations. each bit in PX_ICn correspond to a interrupt.
+ * disable a interrupt by writing to PX_IMS with the corresponding bit=1
+ * enable a interrupt by writing to PX_IMC with the corresponding bit=1
+ * trigger a interrupt by writing to PX_ICS with the corresponding bit=1
+ **/
+#define TXGBE_INTR_ALL (~0ULL)
+#define TXGBE_INTR_MISC(A) (1ULL << (A)->num_q_vectors)
+#define TXGBE_INTR_QALL(A) (TXGBE_INTR_MISC(A) - 1)
+#define TXGBE_INTR_Q(i) (1ULL << (i))
+static inline void txgbe_intr_enable(struct txgbe_hw *hw, u64 qmask)
+{
+	u32 mask;
+
+	mask = (qmask & 0xFFFFFFFF);
+	if (mask)
+		wr32(hw, TXGBE_PX_IMC(0), mask);
+	mask = (qmask >> 32);
+	if (mask)
+		wr32(hw, TXGBE_PX_IMC(1), mask);
+
+	/* skip the flush */
+}
+
+static inline void txgbe_intr_disable(struct txgbe_hw *hw, u64 qmask)
+{
+	u32 mask;
+
+	mask = (qmask & 0xFFFFFFFF);
+	if (mask)
+		wr32(hw, TXGBE_PX_IMS(0), mask);
+	mask = (qmask >> 32);
+	if (mask)
+		wr32(hw, TXGBE_PX_IMS(1), mask);
+
+	/* skip the flush */
+}
+
+static inline void txgbe_intr_trigger(struct txgbe_hw *hw, u64 qmask)
+{
+	u32 mask;
+
+	mask = (qmask & 0xFFFFFFFF);
+	if (mask)
+		wr32(hw, TXGBE_PX_ICS(0), mask);
+	mask = (qmask >> 32);
+	if (mask)
+		wr32(hw, TXGBE_PX_ICS(1), mask);
+
+	/* skip the flush */
+}
+
+#define TXGBE_RING_SIZE(R) ((R)->count < TXGBE_MAX_TXD ? (R)->count / 128 : 0)
 
 #endif /* _TXGBE_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.c
new file mode 100644
index 000000000000..a25fdebe1201
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.c
@@ -0,0 +1,696 @@
+#include "txgbe_bp.h"
+
+int handle_bkp_an73_flow(unsigned char bp_link_mode, struct txgbe_adapter *adapter);
+int wait_bkp_an73_xnp_done(struct txgbe_adapter *adapter);
+int get_bkp_an73_ability(bkpan73ability *pt_bkp_an73_ability, unsigned char byLinkPartner , 
+								struct txgbe_adapter *adapter);
+int clr_bkp_an73_int(unsigned int intIndex, unsigned int intIndexHi, struct txgbe_adapter * adapter);
+int chk_bkp_an73_Int(unsigned int intIndex, struct txgbe_adapter *adapter);
+int chk_bkp_an73_ability(bkpan73ability tBkpAn73Ability, bkpan73ability tLpBkpAn73Ability,
+								struct txgbe_adapter *adapter);
+
+void txgbe_bp_close_protect(struct txgbe_adapter *adapter)
+{
+	adapter->flags2 |= TXGBE_FLAG2_KR_PRO_DOWN;
+	while (adapter->flags2 & TXGBE_FLAG2_KR_PRO_REINIT){
+		msleep(100);
+		printk("wait to reinited ok..%x\n",adapter->flags2);
+	}
+}
+
+int txgbe_bp_mode_setting(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	/*default to open an73*/
+
+	adapter->backplane_an = AUTO?1:0;
+	adapter->an37 = AUTO?1:0;
+	
+	if (adapter->backplane_mode == TXGBE_BP_M_KR) {
+		hw->subsystem_device_id = TXGBE_ID_WX1820_KR_KX_KX4;
+	} else if (adapter->backplane_mode == TXGBE_BP_M_KX4) {
+		hw->subsystem_device_id = TXGBE_ID_WX1820_MAC_XAUI;
+	} else if (adapter->backplane_mode == TXGBE_BP_M_KX) {
+		hw->subsystem_device_id = TXGBE_ID_WX1820_MAC_SGMII;
+	} else if (adapter->backplane_mode == TXGBE_BP_M_SFI) {
+		hw->subsystem_device_id = TXGBE_ID_WX1820_SFP;
+	} 
+
+	if (adapter->backplane_auto == TXGBE_BP_M_AUTO) {
+		adapter->backplane_an = 1;
+		adapter->an37 = 1;
+	} else if (adapter->backplane_auto == TXGBE_BP_M_NAUTO) {
+		adapter->backplane_an = 0;
+		adapter->an37 = 0;
+	}
+
+	if (adapter->ffe_set == TXGBE_BP_M_KR ||
+		adapter->ffe_set == TXGBE_BP_M_KX4 ||
+		adapter->ffe_set == TXGBE_BP_M_KX ||
+		adapter->ffe_set == TXGBE_BP_M_SFI ) {
+		goto out;
+	}
+
+	if (KR_SET == 1) {
+		adapter->ffe_main = KR_MAIN;
+		adapter->ffe_pre = KR_PRE;
+		adapter->ffe_post = KR_POST;
+	} else if (KX4_SET == 1) {
+		adapter->ffe_main = KX4_MAIN;
+		adapter->ffe_pre = KX4_PRE;
+		adapter->ffe_post = KX4_POST;
+	} else if (KX_SET == 1) {
+		adapter->ffe_main = KX_MAIN;
+		adapter->ffe_pre = KX_PRE;
+		adapter->ffe_post = KX_POST;
+	} else if (SFI_SET == 1) {
+		adapter->ffe_main = SFI_MAIN;
+		adapter->ffe_pre = SFI_PRE;
+		adapter->ffe_post = SFI_POST;
+	}
+out:
+	return 0;
+}
+
+static int txgbe_kr_subtask(struct txgbe_adapter *adapter)
+{
+	handle_bkp_an73_flow(0, adapter);
+	return 0;
+}
+
+void txgbe_bp_watchdog_event(struct txgbe_adapter *adapter)
+{
+	u32 value = 0;
+	struct txgbe_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	
+	/* only continue if link is down */
+	if (netif_carrier_ok(netdev))
+		return;
+
+	if (KR_POLLING == 1) {
+		value = txgbe_rd32_epcs(hw, 0x78002);
+		value = value & 0x4;
+		if (value == 0x4) {
+			e_dev_info("Enter training\n");
+			txgbe_kr_subtask(adapter);
+		}
+	} else {
+		if(adapter->flags2 & TXGBE_FLAG2_KR_TRAINING){
+			e_dev_info("Enter training\n");
+			txgbe_kr_subtask(adapter);
+			adapter->flags2 &= ~TXGBE_FLAG2_KR_TRAINING;
+		}
+	}
+}
+
+void txgbe_bp_down_event(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if(adapter->backplane_an == 1){
+		if (KR_NORESET == 1){
+			txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0000);
+			txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0000);
+			txgbe_wr32_epcs(hw, 0x78001, 0x0000);
+			msleep(1000);
+			txgbe_set_link_to_kr(hw, 1);
+		} else if (KR_NOREINITED == 1){
+			txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0000);
+			txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0000);
+			txgbe_wr32_epcs(hw, 0x78001, 0x0000);
+			msleep(1050);
+			txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0001);
+			txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x3200);
+			txgbe_wr32_epcs(hw, 0x78001, 0x0007);
+		} else {
+			msleep(200);
+			if (!(adapter->flags2&TXGBE_FLAG2_KR_PRO_DOWN))
+				txgbe_reinit_locked(adapter);
+		}
+	}
+}
+
+int txgbe_kr_intr_handle(struct txgbe_adapter *adapter)
+{ 
+	bkpan73ability tBkpAn73Ability, tLpBkpAn73Ability;
+	tBkpAn73Ability.currentLinkMode = 0;
+
+	if (KR_MODE) e_dev_info("HandleBkpAn73Flow() \n");
+	if (KR_MODE) e_dev_info("---------------------------------\n");
+	
+	/*1. Get the local AN73 Base Page Ability*/
+	if (KR_MODE) e_dev_info("<1>. Get the local AN73 Base Page Ability ...\n");
+	get_bkp_an73_ability(&tBkpAn73Ability, 0, adapter);
+	/*2. Check the AN73 Interrupt Status*/
+	if (KR_MODE) e_dev_info("<2>. Check the AN73 Interrupt Status ...\n");
+	/*3.Clear the AN_PG_RCV interrupt*/
+	clr_bkp_an73_int(2, 0x0, adapter);
+
+	/*3.1. Get the link partner AN73 Base Page Ability*/
+	if (KR_MODE) e_dev_info("<3.1>. Get the link partner AN73 Base Page Ability ...\n");
+	get_bkp_an73_ability(&tLpBkpAn73Ability, 1, adapter);
+
+	/*3.2. Check the AN73 Link Ability with Link Partner*/
+	if (KR_MODE) e_dev_info("<3.2>. Check the AN73 Link Ability with Link Partner ...\n");
+	if (KR_MODE) e_dev_info("		  Local Link Ability: 0x%x\n", tBkpAn73Ability.linkAbility);
+	if (KR_MODE) e_dev_info("  Link Partner Link Ability: 0x%x\n", tLpBkpAn73Ability.linkAbility);
+
+	chk_bkp_an73_ability(tBkpAn73Ability, tLpBkpAn73Ability, adapter);
+	return 0;
+
+}
+
+/*Check Ethernet Backplane AN73 Base Page Ability
+**return value:
+**  -1 : none link mode matched, exit
+**   0 : current link mode matched, wait AN73 to be completed
+**   1 : current link mode not matched, set to matched link mode, re-start AN73 external
+*/
+int chk_bkp_an73_ability(bkpan73ability tBkpAn73Ability, bkpan73ability tLpBkpAn73Ability,
+								struct txgbe_adapter *adapter)
+{
+	unsigned int comLinkAbility;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (KR_MODE) e_dev_info("CheckBkpAn73Ability():\n");
+	if (KR_MODE) e_dev_info("------------------------\n");
+
+	/*-- Check the common link ability and take action based on the result*/
+	comLinkAbility = tBkpAn73Ability.linkAbility & tLpBkpAn73Ability.linkAbility;
+	if (KR_MODE) e_dev_info("comLinkAbility= 0x%x, linkAbility= 0x%x, lpLinkAbility= 0x%x\n", comLinkAbility, tBkpAn73Ability.linkAbility, tLpBkpAn73Ability.linkAbility);
+
+	/*only support kr*/
+	if (comLinkAbility == 0){
+		if (KR_MODE) e_dev_info("WARNING: The Link Partner does not support any compatible speed mode!!!\n\n");
+		return -1;
+	} else if (comLinkAbility & 0x80) {
+		if (tBkpAn73Ability.currentLinkMode == 0){
+			if (KR_MODE) e_dev_info("Link mode is matched with Link Partner: [LINK_KR].\n");
+			return 0;
+		} else {
+			if (KR_MODE) e_dev_info("Link mode is not matched with Link Partner: [LINK_KR].\n");
+			if (KR_MODE) e_dev_info("Set the local link mode to [LINK_KR] ...\n");
+			txgbe_set_link_to_kr(hw, 1);
+			return 1;
+		}
+	}
+
+#if 0
+	if (comLinkAbility == 0){
+		if (KR_MODE) e_dev_info("WARNING: The Link Partner does not support any compatible speed mode!!!\n\n");
+		return -1;
+	} else if (comLinkAbility & 0x80) {
+		if (tBkpAn73Ability.currentLinkMode == 0){
+			if (KR_MODE) e_dev_info("Link mode is matched with Link Partner: [LINK_KR].\n");
+			return 0;
+		}else{
+			if (KR_MODE) e_dev_info("Link mode is not matched with Link Partner: [LINK_KR].\n");
+			if (KR_MODE) e_dev_info("Set the local link mode to [LINK_KR] ...\n");
+			txgbe_set_link_to_kr(hw, 1);
+			return 1;
+		}
+	} else if (comLinkAbility & 0x40) {
+		if (tBkpAn73Ability.currentLinkMode == 0x10){
+			if (KR_MODE) e_dev_info("Link mode is matched with Link Partner: [LINK_KX4].\n");
+			return 0;
+		} else {
+			if (KR_MODE) e_dev_info("Link mode is not matched with Link Partner: [LINK_KX4].\n");
+			if (KR_MODE) e_dev_info("Set the local link mode to [LINK_KX4] ...\n");
+			txgbe_set_link_to_kx4(hw, 1);
+			return 1;
+		}
+	} else if (comLinkAbility & 0x20) {
+		if (tBkpAn73Ability.currentLinkMode == 0x1){
+			if (KR_MODE) e_dev_info("Link mode is matched with Link Partner: [LINK_KX].\n");
+			return 0;
+		} else {
+			if (KR_MODE) e_dev_info("Link mode is not matched with Link Partner: [LINK_KX].\n");
+			if (KR_MODE) e_dev_info("Set the local link mode to [LINK_KX] ...\n");
+			txgbe_set_link_to_kx(hw, 1, 1);
+			return 1;
+		}
+	}
+#endif
+	return 0;
+}
+
+
+/*Get Ethernet Backplane AN73 Base Page Ability
+**byLinkPartner:
+**- 1: Get Link Partner Base Page
+**- 2: Get Link Partner Next Page (only get NXP Ability Register 1 at the moment)
+**- 0: Get Local Device Base Page
+*/
+int get_bkp_an73_ability(bkpan73ability *pt_bkp_an73_ability, unsigned char byLinkPartner , 
+								struct txgbe_adapter *adapter)
+{
+	int status = 0;
+	unsigned int rdata;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (KR_MODE) e_dev_info("get_bkp_an73_ability(): byLinkPartner = %d\n", byLinkPartner);
+	if (KR_MODE) e_dev_info("----------------------------------------\n");
+
+	if (byLinkPartner == 1) /*Link Partner Base Page*/
+	{
+		/*Read the link partner AN73 Base Page Ability Registers*/
+		if (KR_MODE) e_dev_info("Read the link partner AN73 Base Page Ability Registers...\n");
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_LP_ABL1);
+		if (KR_MODE) e_dev_info("SR AN MMD LP Base Page Ability Register 1: 0x%x\n", rdata);
+		pt_bkp_an73_ability->nextPage = (rdata >> 15) & 0x01;
+		if (KR_MODE) e_dev_info("  Next Page (bit15): %d\n", pt_bkp_an73_ability->nextPage);
+
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, 0x70014);
+		if (KR_MODE) e_dev_info("SR AN MMD LP Base Page Ability Register 2: 0x%x\n", rdata);
+		pt_bkp_an73_ability->linkAbility = rdata & 0xE0;
+		if (KR_MODE) e_dev_info("  Link Ability (bit[15:0]): 0x%x\n", pt_bkp_an73_ability->linkAbility);
+		if (KR_MODE) e_dev_info("  (0x20- KX_ONLY, 0x40- KX4_ONLY, 0x60- KX4_KX\n");
+		if (KR_MODE) e_dev_info("   0x80- KR_ONLY, 0xA0- KR_KX, 0xC0- KR_KX4, 0xE0- KR_KX4_KX)\n");
+
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, 0x70015);
+		if (KR_MODE) e_dev_info("SR AN MMD LP Base Page Ability Register 3: 0x%x\n", rdata);
+		if (KR_MODE) e_dev_info("  FEC Request (bit15): %d\n", ((rdata >> 15) & 0x01));
+		if (KR_MODE) e_dev_info("  FEC Enable  (bit14): %d\n", ((rdata >> 14) & 0x01));
+		pt_bkp_an73_ability->fecAbility = (rdata >> 14) & 0x03;
+	} else if (byLinkPartner == 2) {/*Link Partner Next Page*/
+		/*Read the link partner AN73 Next Page Ability Registers*/
+		if (KR_MODE) e_dev_info("\nRead the link partner AN73 Next Page Ability Registers...\n");
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, 0x70019);
+		if (KR_MODE) e_dev_info(" SR AN MMD LP XNP Ability Register 1: 0x%x\n", rdata);
+		pt_bkp_an73_ability->nextPage = (rdata >> 15) & 0x01;
+		if (KR_MODE)e_dev_info("  Next Page (bit15): %d\n", pt_bkp_an73_ability->nextPage);
+	} else {
+		/*Read the local AN73 Base Page Ability Registers*/
+		if (KR_MODE) e_dev_info("\nRead the local AN73 Base Page Ability Registers...\n");
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG1);
+		if (KR_MODE) e_dev_info("SR AN MMD Advertisement Register 1: 0x%x\n", rdata);
+		pt_bkp_an73_ability->nextPage = (rdata >> 15) & 0x01;
+		if (KR_MODE) e_dev_info("  Next Page (bit15): %d\n", pt_bkp_an73_ability->nextPage);
+
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG2);
+		if (KR_MODE) e_dev_info("SR AN MMD Advertisement Register 2: 0x%x\n", rdata);
+		pt_bkp_an73_ability->linkAbility = rdata & 0xE0;
+		if (KR_MODE) e_dev_info("  Link Ability (bit[15:0]): 0x%x\n", pt_bkp_an73_ability->linkAbility);
+		if (KR_MODE) e_dev_info("  (0x20- KX_ONLY, 0x40- KX4_ONLY, 0x60- KX4_KX\n");
+		if (KR_MODE) e_dev_info("   0x80- KR_ONLY, 0xA0- KR_KX, 0xC0- KR_KX4, 0xE0- KR_KX4_KX)\n");
+
+		rdata = 0;
+		rdata = txgbe_rd32_epcs(hw, 0x70012);
+		if (KR_MODE) e_dev_info("SR AN MMD Advertisement Register 3: 0x%x\n", rdata);
+		if (KR_MODE) e_dev_info("  FEC Request (bit15): %d\n", ((rdata >> 15) & 0x01));
+		if (KR_MODE) e_dev_info("  FEC Enable  (bit14): %d\n", ((rdata >> 14) & 0x01));
+		pt_bkp_an73_ability->fecAbility = (rdata >> 14) & 0x03;
+	} /*if (byLinkPartner == 1) Link Partner Base Page*/
+
+	if (KR_MODE) e_dev_info("get_bkp_an73_ability() done.\n");
+
+	return status;
+}
+
+/* DESCRIPTION: Set the source data fields[bitHigh:bitLow] with setValue
+** INPUTS:      *src_data: Source data pointer
+**              bitHigh: High bit position of the fields
+**              bitLow : Low bit position of the fields
+**              setValue: Set value of the fields
+** OUTPUTS:     return the updated source data
+*/
+static void set_fields(
+    unsigned int *src_data,
+    unsigned int bitHigh,
+    unsigned int bitLow,
+    unsigned int setValue) 
+{
+	int i;
+
+	if (bitHigh == bitLow) {
+		if (setValue == 0) { 
+			*src_data &= ~(1 << bitLow);
+		}
+		else { 
+			*src_data |= (1 << bitLow);
+		}
+	}else {
+		for (i = bitLow; i <= bitHigh; i++) {
+			*src_data &= ~(1 << i); 
+		}
+		*src_data |= (setValue << bitLow);
+	}
+}
+
+/*Check Ethernet Backplane AN73 Interrupt status
+**- return the value of select interrupt index
+*/
+int chk_bkp_an73_Int(unsigned int intIndex, struct txgbe_adapter *adapter)
+{
+	unsigned int rdata;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (KR_MODE) e_dev_info("chk_bkp_an73_Int(): intIndex = %d\n", intIndex);
+	if (KR_MODE) e_dev_info("----------------------------------------\n");
+
+	rdata = 0x0000;
+	rdata = txgbe_rd32_epcs(hw, 0x78002);
+	if (KR_MODE) e_dev_info("Read VR AN MMD Interrupt Register: 0x%x\n", rdata);
+	if (KR_MODE) e_dev_info("Interrupt: 0- AN_INT_CMPLT, 1-  AN_INC_LINK, 2- AN_PG_RCV\n\n"); 
+
+	return ((rdata >> intIndex) & 0x01);
+}
+
+/*Clear Ethernet Backplane AN73 Interrupt status
+**- intIndexHi  =0, only intIndex bit will be cleared
+**- intIndexHi !=0, the [intIndexHi, intIndex] range will be cleared
+*/
+int clr_bkp_an73_int(unsigned int intIndex, unsigned int intIndexHi, struct txgbe_adapter * adapter)
+{
+	int status = 0;
+	unsigned int rdata, wdata;
+	struct txgbe_hw *hw = &adapter->hw;
+
+
+	if (KR_MODE) e_dev_info("clr_bkp_an73_int(): intIndex = %d\n", intIndex);
+	if (KR_MODE) e_dev_info("----------------------------------------\n");
+
+	rdata = 0x0000;
+	rdata = txgbe_rd32_epcs(hw, 0x78002);
+	if (KR_MODE) e_dev_info("[Before clear] Read VR AN MMD Interrupt Register: 0x%x\n", rdata);
+
+	wdata = rdata;
+	if (intIndexHi) {
+        	set_fields(&wdata, intIndexHi, intIndex, 0);
+	} else {
+		set_fields(&wdata, intIndex, intIndex, 0);
+	} 
+	txgbe_wr32_epcs(hw, 0x78002, wdata);
+
+	rdata = 0x0000;
+	rdata = txgbe_rd32_epcs(hw, 0x78002);
+	if (KR_MODE) e_dev_info("[After clear] Read VR AN MMD Interrupt Register: 0x%x\n", rdata);
+	if (KR_MODE) e_dev_info("\n");
+
+	return status;
+}
+
+int wait_bkp_an73_xnp_done(struct txgbe_adapter *adapter)
+{
+	int status = 0;
+	unsigned int timer = 0;
+	bkpan73ability tLpBkpAn73Ability;
+
+	/*while(timer++ < BKPAN73_TIMEOUT)*/
+	while(timer++ < 20) { 
+		if (chk_bkp_an73_Int(2, adapter))
+		{
+			/*Clear the AN_PG_RCV interrupt*/
+			clr_bkp_an73_int(2, 0, adapter);
+
+			/*Get the link partner AN73 Next Page Ability*/
+			get_bkp_an73_ability(&tLpBkpAn73Ability, 2, adapter);
+
+			/*Return when AN_LP_XNP_NP == 0, (bit[15]: Next Page)*/
+			if (tLpBkpAn73Ability.nextPage == 0)
+			{
+				return status;
+			}
+		}
+		msleep(200);
+	}  /*while(timer++ < BKPAN73_TIMEOUT)*/
+	if (KR_MODE) e_dev_info("ERROR: Wait all the AN73 next pages to be exchanged Timeout!!!\n");
+
+	return -1;
+}
+
+
+int read_phy_lane_txeq(unsigned short lane, struct txgbe_adapter *adapter, int post_t, int mode)
+{
+	int status = 0;
+	unsigned int addr, rdata;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 pre;
+	u32 post;
+	u32 lmain;
+
+	/*LANEN_DIG_ASIC_TX_ASIC_IN_1[11:6]: TX_MAIN_CURSOR*/
+	rdata = 0;
+	addr  = 0x100E | (lane << 8);
+	rdata = rd32_ephy(hw, addr);
+	if (KR_MODE) e_dev_info("PHY LANE%0d TX EQ Read Value:\n", lane);
+	if (KR_MODE) e_dev_info("  TX_MAIN_CURSOR: %d\n", ((rdata >> 6) & 0x3F));
+
+	/*LANEN_DIG_ASIC_TX_ASIC_IN_2[5 :0]: TX_PRE_CURSOR*/
+	/*LANEN_DIG_ASIC_TX_ASIC_IN_2[11:6]: TX_POST_CURSOR*/
+	rdata = 0;
+	addr  = 0x100F | (lane << 8);
+	rdata = rd32_ephy(hw, addr);
+	if (KR_MODE) e_dev_info("  TX_PRE_CURSOR : %d\n", (rdata & 0x3F));
+	if (KR_MODE) e_dev_info("  TX_POST_CURSOR: %d\n", ((rdata >> 6) & 0x3F));
+	if (KR_MODE) e_dev_info("**********************************************\n");
+
+	if(mode == 1){
+		pre = (rdata & 0x3F);
+		post = ((rdata >> 6) & 0x3F);
+		if((160 - pre -post ) < 88)
+			lmain = 88;
+		else	
+			lmain = 160 - pre - post;
+		if (post_t != 0)
+			post = post_t;
+		txgbe_wr32_epcs( hw, 0x1803b , post );
+		txgbe_wr32_epcs( hw, 0x1803a , pre | (lmain << 8));
+		txgbe_wr32_epcs( hw, 0x18037 , txgbe_rd32_epcs(hw, 0x18037) & 0xff7f);
+	}
+	if (KR_MODE) e_dev_info("**********************************************\n");
+
+	return status;
+}
+
+
+/*Enable Clause 72 KR training
+**
+**Note:
+**<1>. The Clause 72 start-up protocol should be initiated when all pages are exchanged during Clause 73 auto-
+**negotiation and when the auto-negotiation process is waiting for link status to be UP for 500 ms after 
+**exchanging all the pages.
+**
+**<2>. The local device and link partner should be enabled the CL72 KR training
+**with in 500ms
+**
+**enable:
+**- bits[1:0] =2'b11: Enable the CL72 KR training
+**- bits[1:0] =2'b01: Disable the CL72 KR training
+*/
+int en_cl72_krtr(unsigned int enable, struct txgbe_adapter *adapter)
+{
+	int status = 0;
+	unsigned int wdata=0;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (enable == 1) {
+		if (KR_MODE) e_dev_info("\nDisable Clause 72 KR Training ...\n");
+		status |= read_phy_lane_txeq(0, adapter, 0, 0);
+	} else if (enable == 4) {
+		status |= read_phy_lane_txeq(0, adapter, 20, 1);
+	} else if (enable == 8) {
+		status |= read_phy_lane_txeq(0, adapter, 16, 1);
+	} else if (enable == 12) {
+		status |= read_phy_lane_txeq(0, adapter, 24, 1);
+	} else if (enable == 5) {
+		status |= read_phy_lane_txeq(0, adapter, 0, 1);
+	} else if (enable == 3) {
+	if (KR_MODE) e_dev_info("\nEnable Clause 72 KR Training ...\n");
+
+		if (CL72_KRTR_PRBS_MODE_EN != 0xffff) {
+			/*Set PRBS Timer Duration Control to maximum 6.7ms in VR_PMA_KRTR_PRBS_CTRL1 Register*/
+			wdata = CL72_KRTR_PRBS_MODE_EN;
+			txgbe_wr32_epcs(hw, 0x18005, wdata);
+			/*Set PRBS Timer Duration Control to maximum 6.7ms in VR_PMA_KRTR_PRBS_CTRL1 Register*/
+			wdata = 0xFFFF;
+			txgbe_wr32_epcs(hw, 0x18004, wdata);
+
+			/*Enable PRBS Mode to determine KR Training Status by setting Bit 0 of VR_PMA_KRTR_PRBS_CTRL0 Register*/
+			wdata = 0;
+			set_fields(&wdata, 0, 0, 1);
+		}
+
+#ifdef CL72_KRTR_PRBS31_EN
+		/*Enable PRBS31 as the KR Training Pattern by setting Bit 1 of VR_PMA_KRTR_PRBS_CTRL0 Register*/
+		set_fields(&wdata, 1, 1, 1);
+#endif /*#ifdef CL72_KRTR_PRBS31_EN*/
+		txgbe_wr32_epcs(hw, 0x18003, wdata);
+		status |= read_phy_lane_txeq(0, adapter, 0, 0);
+	} else {
+		if (KR_MODE) e_dev_info("\nInvalid setting for Clause 72 KR Training!!!\n");
+		return -1;
+	}
+
+	/*Enable the Clause 72 start-up protocol by setting Bit 1 of SR_PMA_KR_PMD_CTRL Register.
+	**Restart the Clause 72 start-up protocol by setting Bit 0 of SR_PMA_KR_PMD_CTRL Register*/
+	wdata = enable;
+	txgbe_wr32_epcs(hw, 0x10096, wdata);
+	return status;
+}
+
+int chk_cl72_krtr_status(struct txgbe_adapter *adapter)
+{
+	int status = 0;
+	unsigned int addr, rdata, rdata1;
+	unsigned int timer = 0, times = 0;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	times = KR_POLLING?35:20;
+
+	/*While loop to check clause 72 KR training status*/
+	while(timer++ < times) { 
+		//Get the latest received coefficient update or status
+		rdata = 0;
+		addr  = 0x010098;
+		rdata = txgbe_rd32_epcs(hw, addr);
+		if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR LP Coefficient Update Register: 0x%x\n", rdata);
+
+		rdata = 0;
+		addr  = 0x010099;
+		rdata = txgbe_rd32_epcs(hw, addr);
+		if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR LP Coefficient Status Register: 0x%x\n", rdata);
+
+		rdata = 0;
+		addr  = 0x01009a;
+		rdata = txgbe_rd32_epcs(hw, addr);
+		if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR LD Coefficient Update: 0x%x\n", rdata);
+
+		rdata = 0;
+		addr  = 0x01009b;
+		rdata = txgbe_rd32_epcs(hw, addr);
+		if (KR_MODE) e_dev_info(" SR PMA MMD 10GBASE-KR LD Coefficient Status: 0x%x\n", rdata);
+
+		rdata = 0;
+		addr  = 0x010097; 
+		rdata = txgbe_rd32_epcs(hw, addr);
+		if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR Status Register: 0x%x\n", rdata);
+		if (KR_MODE) e_dev_info("  Training Failure         (bit3): %d\n", ((rdata >> 3) & 0x01));
+		if (KR_MODE) e_dev_info("  Start-Up Protocol Status (bit2): %d\n", ((rdata >> 2) & 0x01));
+		if (KR_MODE) e_dev_info("  Frame Lock               (bit1): %d\n", ((rdata >> 1) & 0x01));
+		if (KR_MODE) e_dev_info("  Receiver Status          (bit0): %d\n", ((rdata >> 0) & 0x01));
+
+		rdata1 = txgbe_rd32_epcs(hw, 0x10099) & 0x8000;
+		if (rdata1 == 0x8000) {
+			adapter->flags2 |= KR;
+			if (KR_MODE) e_dev_info("TEST Coefficient Status Register: 0x%x\n", rdata);
+		}
+		/*If bit3 is set, Training is completed with failure*/
+		if ((rdata >> 3) & 0x01) {
+			if (KR_MODE) e_dev_info("Training is completed with failure!!!\n");
+			status |= read_phy_lane_txeq(0, adapter, 0, 0);
+			return status;
+		}
+
+		/*If bit0 is set, Receiver trained and ready to receive data*/
+		if ((rdata >> 0) & 0x01) {
+			if (KR_MODE) e_dev_info("Receiver trained and ready to receive data ^_^\n");
+			status |= read_phy_lane_txeq(0, adapter, 0, 0);
+			return status;
+		}
+
+		msleep(20);
+	} 
+
+	if (KR_MODE) e_dev_info("ERROR: Check Clause 72 KR Training Complete Timeout!!!\n");
+
+	return status;
+}
+
+int handle_bkp_an73_flow(unsigned char bp_link_mode, struct txgbe_adapter *adapter)
+{
+	int status = 0;
+	unsigned int timer = 0;
+	unsigned int addr, data;
+	bkpan73ability tBkpAn73Ability , tLpBkpAn73Ability ;
+	u32 i = 0;
+	u32 rdata = 0;
+	u32 rdata1 = 0;
+	struct txgbe_hw *hw = &adapter->hw;
+	tBkpAn73Ability.currentLinkMode = bp_link_mode;
+
+	if (KR_MODE) e_dev_info("HandleBkpAn73Flow() \n");
+	if (KR_MODE) e_dev_info("---------------------------------\n");
+
+	if (adapter->an73_mode == 0) {
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0);
+		txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0);
+	}
+	
+	/*Check the FEC and KR Training for KR mode*/
+	if ( 1 )
+	{
+		//FEC handling
+		if (KR_MODE) e_dev_info("<3.3>. Check the FEC for KR mode ...\n");
+		tBkpAn73Ability.fecAbility = 0x03;
+		tLpBkpAn73Ability.fecAbility = 0x03;
+		if (((tBkpAn73Ability.fecAbility & tLpBkpAn73Ability.fecAbility) == 0x03)
+			&& (KR_FEC == 1)) {
+			if (KR_MODE) e_dev_info("Enable the Backplane KR FEC ...\n");
+			//Write 1 to SR_PMA_KR_FEC_CTRL bit0 to enable the FEC
+			data = 1;
+			addr = 0x100ab; //SR_PMA_KR_FEC_CTRL 
+			txgbe_wr32_epcs(hw, addr, data);
+		} else {
+			if (KR_MODE) e_dev_info("Backplane KR FEC is disabled.\n");
+		}
+#ifdef CL72_KR_TRAINING_ON
+		for (i = 0; i < 2; i++) {
+			if (KR_MODE) e_dev_info("\n<3.4>. Check the CL72 KR Training for KR mode ...\n");
+			if  (KR_MODE)printk("===================%d=======================\n", i);
+			status |= en_cl72_krtr(3, adapter);
+
+			if (KR_MODE) e_dev_info("\nCheck the Clause 72 KR Training status ...\n");
+			status |= chk_cl72_krtr_status(adapter);
+			
+			rdata = txgbe_rd32_epcs(hw, 0x10099) & 0x8000;
+			if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR LP Coefficient Status Register: 0x%x\n", rdata);
+			rdata1 = txgbe_rd32_epcs(hw, 0x1009b) & 0x8000;
+			if (KR_MODE) e_dev_info("SR PMA MMD 10GBASE-KR LP Coefficient Status Register: 0x%x\n", rdata1);
+			if (KR_POLLING == 0) {
+				if(adapter->flags2 & KR){
+					rdata = 0x8000;
+					adapter->flags2 &= ~KR;
+				}
+			}
+			if( (rdata == 0x8000) & (rdata1 == 0x8000)){
+				if (KR_MODE) e_dev_info("====================out===========================\n");
+				status |= en_cl72_krtr(1, adapter);
+				clr_bkp_an73_int(2, 0, adapter);
+				clr_bkp_an73_int(1, 0, adapter);
+				clr_bkp_an73_int(0, 0, adapter);
+				while(timer++ < 10) { 
+					rdata = txgbe_rd32_epcs(hw, 0x30020);
+					rdata = rdata & 0x1000;
+					if (rdata  == 0x1000)
+					{
+						if (KR_MODE) e_dev_info("\nINT_AN_INT_CMPLT =1, AN73 Done Success.\n");
+						e_dev_info("AN73 Done Success.\n");
+						txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0000);
+						txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0);
+						return 0;
+					}
+					msleep(10);
+				} 
+
+				return 0;
+			}	
+
+			status |= en_cl72_krtr(1, adapter);
+		}
+#endif 
+	}
+	clr_bkp_an73_int(0, 0, adapter);
+	clr_bkp_an73_int(1, 0, adapter);
+	clr_bkp_an73_int(2, 0, adapter);
+
+	return status;
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.h
new file mode 100644
index 000000000000..cc19ac69207b
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_bp.h
@@ -0,0 +1,26 @@
+#ifndef _TXGBE_BP_H_
+#define _TXGBE_BP_H_
+
+#include "txgbe.h"
+#include "txgbe_type.h"
+#include "txgbe_hw.h"
+
+#define CL72_KR_TRAINING_ON
+
+/* Backplane AN73 Base Page Ability struct*/
+typedef struct TBKPAN73ABILITY
+{
+    unsigned int nextPage;    //Next Page (bit0)
+    unsigned int linkAbility; //Link Ability (bit[7:0])
+    unsigned int fecAbility;  //FEC Request (bit1), FEC Enable  (bit0)
+    unsigned int currentLinkMode; //current link mode for local device
+}bkpan73ability;
+
+int txgbe_kr_intr_handle(struct txgbe_adapter *adapter);
+void txgbe_bp_down_event(struct txgbe_adapter *adapter);
+void txgbe_bp_watchdog_event(struct txgbe_adapter *adapter);
+int txgbe_bp_mode_setting(struct txgbe_adapter *adapter);
+void txgbe_bp_close_protect(struct txgbe_adapter *adapter);
+
+#endif
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.c
new file mode 100644
index 000000000000..b7351e5f0d66
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.c
@@ -0,0 +1,653 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_dcb.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#include "txgbe_type.h"
+#include "txgbe_dcb.h"
+#include "txgbe.h"
+
+/*
+ * txgbe_dcb_calculate_tc_credits - This calculates the ieee traffic class
+ * credits from the configured bandwidth percentages. Credits
+ * are the smallest unit programmable into the underlying
+ * hardware. The IEEE 802.1Qaz specification do not use bandwidth
+ * groups so this is much simplified from the CEE case.
+ */
+s32 txgbe_dcb_calculate_tc_credits(u8 *bw, u16 *refill, u16 *max,
+				   int max_frame_size)
+{
+	int min_percent = 100;
+	int min_credit, multiplier;
+	int i;
+
+	min_credit = ((max_frame_size / 2) + TXGBE_DCB_CREDIT_QUANTUM - 1) /
+			TXGBE_DCB_CREDIT_QUANTUM;
+
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		if (bw[i] < min_percent && bw[i])
+			min_percent = bw[i];
+	}
+
+	multiplier = (min_credit / min_percent) + 1;
+
+	/* Find out the hw credits for each TC */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		int val = min(bw[i] * multiplier, TXGBE_DCB_MAX_CREDIT_REFILL);
+
+		if (val < min_credit)
+			val = min_credit;
+		refill[i] = (u16)val;
+
+		max[i] = (u16)(bw[i] ? (bw[i]*TXGBE_DCB_MAX_CREDIT)/100 : min_credit);
+	}
+
+	return 0;
+}
+
+/**
+ * txgbe_dcb_calculate_tc_credits_cee - Calculates traffic class credits
+ * @txgbe_dcb_config: Struct containing DCB settings.
+ * @direction: Configuring either Tx or Rx.
+ *
+ * This function calculates the credits allocated to each traffic class.
+ * It should be called only after the rules are checked by
+ * txgbe_dcb_check_config_cee().
+ */
+s32 txgbe_dcb_calculate_tc_credits_cee(struct txgbe_hw *hw,
+				   struct txgbe_dcb_config *dcb_config,
+				   u32 max_frame_size, u8 direction)
+{
+	struct txgbe_dcb_tc_path *p;
+	u32 min_multiplier      = 0;
+	u16 min_percent         = 100;
+	s32 ret_val =           0;
+	/* Initialization values default for Tx settings */
+	u32 min_credit          = 0;
+	u32 credit_refill       = 0;
+	u32 credit_max          = 0;
+	u16 link_percentage     = 0;
+	u8  bw_percent          = 0;
+	u8  i;
+
+	UNREFERENCED_PARAMETER(hw);
+
+	if (dcb_config == NULL) {
+		ret_val = TXGBE_ERR_CONFIG;
+		goto out;
+	}
+
+	min_credit = ((max_frame_size / 2) + TXGBE_DCB_CREDIT_QUANTUM - 1) /
+		     TXGBE_DCB_CREDIT_QUANTUM;
+
+	/* Find smallest link percentage */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[direction];
+		bw_percent = dcb_config->bw_percentage[direction][p->bwg_id];
+		link_percentage = p->bwg_percent;
+
+		link_percentage = (link_percentage * bw_percent) / 100;
+
+		if (link_percentage && link_percentage < min_percent)
+			min_percent = link_percentage;
+	}
+
+	/*
+	 * The ratio between traffic classes will control the bandwidth
+	 * percentages seen on the wire. To calculate this ratio we use
+	 * a multiplier. It is required that the refill credits must be
+	 * larger than the max frame size so here we find the smallest
+	 * multiplier that will allow all bandwidth percentages to be
+	 * greater than the max frame size.
+	 */
+	min_multiplier = (min_credit / min_percent) + 1;
+
+	/* Find out the link percentage for each TC first */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		p = &dcb_config->tc_config[i].path[direction];
+		bw_percent = dcb_config->bw_percentage[direction][p->bwg_id];
+
+		link_percentage = p->bwg_percent;
+		/* Must be careful of integer division for very small nums */
+		link_percentage = (link_percentage * bw_percent) / 100;
+		if (p->bwg_percent > 0 && link_percentage == 0)
+			link_percentage = 1;
+
+		/* Save link_percentage for reference */
+		p->link_percent = (u8)link_percentage;
+
+		/* Calculate credit refill ratio using multiplier */
+		credit_refill = min(link_percentage * min_multiplier,
+				    (u32)TXGBE_DCB_MAX_CREDIT_REFILL);
+
+		/* Refill at least minimum credit */
+		if (credit_refill < min_credit)
+			credit_refill = min_credit;
+
+		p->data_credits_refill = (u16)credit_refill;
+
+		/* Calculate maximum credit for the TC */
+		credit_max = (link_percentage * TXGBE_DCB_MAX_CREDIT) / 100;
+
+		/*
+		 * Adjustment based on rule checking, if the percentage
+		 * of a TC is too small, the maximum credit may not be
+		 * enough to send out a jumbo frame in data plane arbitration.
+		 */
+		if (credit_max < min_credit)
+			credit_max = min_credit;
+
+		if (direction == TXGBE_DCB_TX_CONFIG) {
+			/*
+			 * Adjustment based on rule checking, if the
+			 * percentage of a TC is too small, the maximum
+			 * credit may not be enough to send out a TSO
+			 * packet in descriptor plane arbitration.
+			 */
+
+			dcb_config->tc_config[i].desc_credits_max =
+								(u16)credit_max;
+		}
+
+		p->data_credits_max = (u16)credit_max;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ * txgbe_dcb_unpack_pfc_cee - Unpack dcb_config PFC info
+ * @cfg: dcb configuration to unpack into hardware consumable fields
+ * @map: user priority to traffic class map
+ * @pfc_up: u8 to store user priority PFC bitmask
+ *
+ * This unpacks the dcb configuration PFC info which is stored per
+ * traffic class into a 8bit user priority bitmask that can be
+ * consumed by hardware routines. The priority to tc map must be
+ * updated before calling this routine to use current up-to maps.
+ */
+void txgbe_dcb_unpack_pfc_cee(struct txgbe_dcb_config *cfg, u8 *map, u8 *pfc_up)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	int up;
+
+	/*
+	 * If the TC for this user priority has PFC enabled then set the
+	 * matching bit in 'pfc_up' to reflect that PFC is enabled.
+	 */
+	for (*pfc_up = 0, up = 0; up < TXGBE_DCB_MAX_USER_PRIORITY; up++) {
+		if (tc_config[map[up]].pfc != txgbe_dcb_pfc_disabled)
+			*pfc_up |= 1 << up;
+	}
+}
+
+void txgbe_dcb_unpack_refill_cee(struct txgbe_dcb_config *cfg, int direction,
+			     u16 *refill)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	int tc;
+
+	for (tc = 0; tc < TXGBE_DCB_MAX_TRAFFIC_CLASS; tc++)
+		refill[tc] = tc_config[tc].path[direction].data_credits_refill;
+}
+
+void txgbe_dcb_unpack_max_cee(struct txgbe_dcb_config *cfg, u16 *max)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	int tc;
+
+	for (tc = 0; tc < TXGBE_DCB_MAX_TRAFFIC_CLASS; tc++)
+		max[tc] = tc_config[tc].desc_credits_max;
+}
+
+void txgbe_dcb_unpack_bwgid_cee(struct txgbe_dcb_config *cfg, int direction,
+			    u8 *bwgid)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	int tc;
+
+	for (tc = 0; tc < TXGBE_DCB_MAX_TRAFFIC_CLASS; tc++)
+		bwgid[tc] = tc_config[tc].path[direction].bwg_id;
+}
+
+void txgbe_dcb_unpack_tsa_cee(struct txgbe_dcb_config *cfg, int direction,
+			   u8 *tsa)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	int tc;
+
+	for (tc = 0; tc < TXGBE_DCB_MAX_TRAFFIC_CLASS; tc++)
+		tsa[tc] = tc_config[tc].path[direction].tsa;
+}
+
+u8 txgbe_dcb_get_tc_from_up(struct txgbe_dcb_config *cfg, int direction, u8 up)
+{
+	struct txgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
+	u8 prio_mask = 1 << up;
+	u8 tc = cfg->num_tcs.pg_tcs;
+
+	/* If tc is 0 then DCB is likely not enabled or supported */
+	if (!tc)
+		goto out;
+
+	/*
+	 * Test from maximum TC to 1 and report the first match we find.  If
+	 * we find no match we can assume that the TC is 0 since the TC must
+	 * be set for all user priorities
+	 */
+	for (tc--; tc; tc--) {
+		if (prio_mask & tc_config[tc].path[direction].up_to_tc_bitmap)
+			break;
+	}
+out:
+	return tc;
+}
+
+void txgbe_dcb_unpack_map_cee(struct txgbe_dcb_config *cfg, int direction,
+			      u8 *map)
+{
+	u8 up;
+
+	for (up = 0; up < TXGBE_DCB_MAX_USER_PRIORITY; up++)
+		map[up] = txgbe_dcb_get_tc_from_up(cfg, direction, up);
+}
+
+
+
+
+
+
+
+
+
+
+/**
+ * txgbe_dcb_config_tc_stats - Config traffic class statistics
+ * @hw: pointer to hardware structure
+ *
+ * Configure queue statistics registers, all queues belonging to same traffic
+ * class uses a single set of queue statistics counters.
+ */
+s32 txgbe_dcb_config_tc_stats(struct txgbe_hw *hw,
+			      struct txgbe_dcb_config *dcb_config)
+{
+	UNREFERENCED_PARAMETER(hw);
+	UNREFERENCED_PARAMETER(dcb_config);
+	return 0;
+}
+
+/**
+ * txgbe_dcb_hw_config_cee - Config and enable DCB
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to txgbe_dcb_config structure
+ *
+ * Configure dcb settings and enable dcb mode.
+ */
+s32 txgbe_dcb_hw_config_cee(struct txgbe_hw *hw,
+			struct txgbe_dcb_config *dcb_config)
+{
+	s32 ret = TXGBE_NOT_IMPLEMENTED;
+	u8 pfc_en;
+	u8 tsa[TXGBE_DCB_MAX_TRAFFIC_CLASS];
+	u8 bwgid[TXGBE_DCB_MAX_TRAFFIC_CLASS];
+	u8 map[TXGBE_DCB_MAX_USER_PRIORITY] = { 0 };
+	u16 refill[TXGBE_DCB_MAX_TRAFFIC_CLASS];
+	u16 max[TXGBE_DCB_MAX_TRAFFIC_CLASS];
+
+	/* Unpack CEE standard containers */
+	txgbe_dcb_unpack_refill_cee(dcb_config, TXGBE_DCB_TX_CONFIG, refill);
+	txgbe_dcb_unpack_max_cee(dcb_config, max);
+	txgbe_dcb_unpack_bwgid_cee(dcb_config, TXGBE_DCB_TX_CONFIG, bwgid);
+	txgbe_dcb_unpack_tsa_cee(dcb_config, TXGBE_DCB_TX_CONFIG, tsa);
+	txgbe_dcb_unpack_map_cee(dcb_config, TXGBE_DCB_TX_CONFIG, map);
+
+
+	txgbe_dcb_config(hw, dcb_config);
+	ret = txgbe_dcb_hw_config(hw,
+					refill, max, bwgid,
+					tsa, map);
+
+	txgbe_dcb_config_tc_stats(hw, dcb_config);
+
+
+	if (!ret && dcb_config->pfc_mode_enable) {
+		txgbe_dcb_unpack_pfc_cee(dcb_config, map, &pfc_en);
+		ret = txgbe_dcb_config_pfc(hw, pfc_en, map);
+	}
+
+	return ret;
+}
+
+/* Helper routines to abstract HW specifics from DCB netlink ops */
+s32 txgbe_dcb_config_pfc(struct txgbe_hw *hw, u8 pfc_en, u8 *map)
+{
+	int ret = TXGBE_ERR_PARAM;
+
+	u32 i, j, fcrtl, reg;
+	u8 max_tc = 0;
+
+	/* Enable Transmit Priority Flow Control */
+	wr32(hw, TXGBE_RDB_RFCC, TXGBE_RDB_RFCC_RFCE_PRIORITY);
+
+	/* Enable Receive Priority Flow Control */
+	reg = 0;
+
+	if (pfc_en)
+		reg |= (TXGBE_MAC_RX_FLOW_CTRL_PFCE | 0x1);
+
+	wr32(hw, TXGBE_MAC_RX_FLOW_CTRL, reg);
+
+	for (i = 0; i < TXGBE_DCB_MAX_USER_PRIORITY; i++) {
+		if (map[i] > max_tc)
+			max_tc = map[i];
+	}
+
+
+	/* Configure PFC Tx thresholds per TC */
+	for (i = 0; i <= max_tc; i++) {
+		int enabled = 0;
+
+		for (j = 0; j < TXGBE_DCB_MAX_USER_PRIORITY; j++) {
+			if ((map[j] == i) && (pfc_en & (1 << j))) {
+				enabled = 1;
+				break;
+			}
+		}
+
+		if (enabled) {
+			reg = (hw->fc.high_water[i] << 10) |
+			      TXGBE_RDB_RFCH_XOFFE;
+			fcrtl = (hw->fc.low_water[i] << 10) |
+				TXGBE_RDB_RFCL_XONE;
+			wr32(hw, TXGBE_RDB_RFCH(i), fcrtl);
+		} else {
+			/*
+			 * In order to prevent Tx hangs when the internal Tx
+			 * switch is enabled we must set the high water mark
+			 * to the Rx packet buffer size - 24KB.  This allows
+			 * the Tx switch to function even under heavy Rx
+			 * workloads.
+			 */
+			reg = rd32(hw, TXGBE_RDB_PB_SZ(i));
+			wr32(hw, TXGBE_RDB_RFCL(i), 0);
+		}
+
+		wr32(hw, TXGBE_RDB_RFCH(i), reg);
+	}
+
+	for (; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		wr32(hw, TXGBE_RDB_RFCL(i), 0);
+		wr32(hw, TXGBE_RDB_RFCH(i), 0);
+	}
+
+	/* Configure pause time (2 TCs per register) */
+	reg = hw->fc.pause_time | (hw->fc.pause_time << 16);
+	for (i = 0; i < (TXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++)
+		wr32(hw, TXGBE_RDB_RFCV(i), reg);
+
+	/* Configure flow control refresh threshold value */
+	wr32(hw, TXGBE_RDB_RFCRT, hw->fc.pause_time / 2);
+
+	return ret;
+}
+
+s32 txgbe_dcb_hw_config(struct txgbe_hw *hw, u16 *refill, u16 *max,
+			    u8 *bwg_id, u8 *tsa, u8 *map)
+{
+	txgbe_dcb_config_rx_arbiter(hw, refill, max, bwg_id,
+					  tsa, map);
+	txgbe_dcb_config_tx_desc_arbiter(hw, refill, max,
+					      bwg_id, tsa);
+	txgbe_dcb_config_tx_data_arbiter(hw, refill, max,
+					      bwg_id, tsa, map);
+
+	return 0;
+}
+
+/**
+ * txgbe_dcb_config_rx_arbiter - Config Rx Data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to txgbe_dcb_config structure
+ *
+ * Configure Rx Packet Arbiter and credits for each traffic class.
+ */
+s32 txgbe_dcb_config_rx_arbiter(struct txgbe_hw *hw, u16 *refill,
+				      u16 *max, u8 *bwg_id, u8 *tsa,
+				      u8 *map)
+{
+	u32 reg = 0;
+	u32 credit_refill = 0;
+	u32 credit_max = 0;
+	u8  i = 0;
+
+	/*
+	 * Disable the arbiter before changing parameters
+	 * (always enable recycle mode; WSP)
+	 */
+	reg = TXGBE_RDM_ARB_CTL_RRM | TXGBE_RDM_ARB_CTL_RAC |
+	      TXGBE_RDM_ARB_CTL_ARBDIS;
+	wr32(hw, TXGBE_RDM_ARB_CTL, reg);
+
+	/*
+	 * map all UPs to TCs. up_to_tc_bitmap for each TC has corresponding
+	 * bits sets for the UPs that needs to be mappped to that TC.
+	 * e.g if priorities 6 and 7 are to be mapped to a TC then the
+	 * up_to_tc_bitmap value for that TC will be 11000000 in binary.
+	 */
+	reg = 0;
+	for (i = 0; i < TXGBE_DCB_MAX_USER_PRIORITY; i++)
+		reg |= (map[i] << (i * TXGBE_RDB_UP2TC_UP_SHIFT));
+
+	wr32(hw, TXGBE_RDB_UP2TC, reg);
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		credit_refill = refill[i];
+		credit_max = max[i];
+		reg = credit_refill |
+		      (credit_max << TXGBE_RDM_ARB_CFG_MCL_SHIFT);
+
+		reg |= (u32)(bwg_id[i]) << TXGBE_RDM_ARB_CFG_BWG_SHIFT;
+
+		if (tsa[i] == txgbe_dcb_tsa_strict)
+			reg |= TXGBE_RDM_ARB_CFG_LSP;
+
+		wr32(hw, TXGBE_RDM_ARB_CFG(i), reg);
+	}
+
+	/*
+	 * Configure Rx packet plane (recycle mode; WSP) and
+	 * enable arbiter
+	 */
+	reg = TXGBE_RDM_ARB_CTL_RRM | TXGBE_RDM_ARB_CTL_RAC;
+	wr32(hw, TXGBE_RDM_ARB_CTL, reg);
+
+	return 0;
+}
+
+/**
+ * txgbe_dcb_config_tx_desc_arbiter - Config Tx Desc. arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to txgbe_dcb_config structure
+ *
+ * Configure Tx Descriptor Arbiter and credits for each traffic class.
+ */
+s32 txgbe_dcb_config_tx_desc_arbiter(struct txgbe_hw *hw, u16 *refill,
+					      u16 *max, u8 *bwg_id, u8 *tsa)
+{
+	u32 reg, max_credits;
+	u8  i;
+
+	/* Clear the per-Tx queue credits; we use per-TC instead */
+	for (i = 0; i < 128; i++) {
+		wr32(hw, TXGBE_TDM_VM_CREDIT(i), 0);
+	}
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		max_credits = max[i];
+		reg = max_credits << TXGBE_TDM_PBWARB_CFG_MCL_SHIFT;
+		reg |= refill[i];
+		reg |= (u32)(bwg_id[i]) << TXGBE_TDM_PBWARB_CFG_BWG_SHIFT;
+
+		if (tsa[i] == txgbe_dcb_tsa_group_strict_cee)
+			reg |= TXGBE_TDM_PBWARB_CFG_GSP;
+
+		if (tsa[i] == txgbe_dcb_tsa_strict)
+			reg |= TXGBE_TDM_PBWARB_CFG_LSP;
+
+		wr32(hw, TXGBE_TDM_PBWARB_CFG(i), reg);
+	}
+
+	/*
+	 * Configure Tx descriptor plane (recycle mode; WSP) and
+	 * enable arbiter
+	 */
+	reg = TXGBE_TDM_PBWARB_CTL_TDPAC | TXGBE_TDM_PBWARB_CTL_TDRM;
+	wr32(hw, TXGBE_TDM_PBWARB_CTL, reg);
+
+	return 0;
+}
+
+/**
+ * txgbe_dcb_config_tx_data_arbiter - Config Tx Data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to txgbe_dcb_config structure
+ *
+ * Configure Tx Packet Arbiter and credits for each traffic class.
+ */
+s32 txgbe_dcb_config_tx_data_arbiter(struct txgbe_hw *hw, u16 *refill,
+					      u16 *max, u8 *bwg_id, u8 *tsa,
+					      u8 *map)
+{
+	u32 reg;
+	u8 i;
+
+	/*
+	 * Disable the arbiter before changing parameters
+	 * (always enable recycle mode; SP; arb delay)
+	 */
+	reg = TXGBE_TDB_PBRARB_CTL_TPPAC | TXGBE_TDB_PBRARB_CTL_TPRM |
+	      TXGBE_RTTPCS_ARBDIS;
+	wr32(hw, TXGBE_TDB_PBRARB_CTL, reg);
+
+	/*
+	 * map all UPs to TCs. up_to_tc_bitmap for each TC has corresponding
+	 * bits sets for the UPs that needs to be mappped to that TC.
+	 * e.g if priorities 6 and 7 are to be mapped to a TC then the
+	 * up_to_tc_bitmap value for that TC will be 11000000 in binary.
+	 */
+	reg = 0;
+	for (i = 0; i < TXGBE_DCB_MAX_USER_PRIORITY; i++)
+		reg |= (map[i] << (i * TXGBE_TDB_UP2TC_UP_SHIFT));
+
+	wr32(hw, TXGBE_TDB_UP2TC, reg);
+
+	/* Configure traffic class credits and priority */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		reg = refill[i];
+		reg |= (u32)(max[i]) << TXGBE_TDB_PBRARB_CFG_MCL_SHIFT;
+		reg |= (u32)(bwg_id[i]) << TXGBE_TDB_PBRARB_CFG_BWG_SHIFT;
+
+		if (tsa[i] == txgbe_dcb_tsa_group_strict_cee)
+			reg |= TXGBE_TDB_PBRARB_CFG_GSP;
+
+		if (tsa[i] == txgbe_dcb_tsa_strict)
+			reg |= TXGBE_TDB_PBRARB_CFG_LSP;
+
+		wr32(hw, TXGBE_TDB_PBRARB_CFG(i), reg);
+	}
+
+	/*
+	 * Configure Tx packet plane (recycle mode; SP; arb delay) and
+	 * enable arbiter
+	 */
+	reg = TXGBE_TDB_PBRARB_CTL_TPPAC | TXGBE_TDB_PBRARB_CTL_TPRM;
+	wr32(hw, TXGBE_TDB_PBRARB_CTL, reg);
+
+	return 0;
+}
+
+/**
+ * txgbe_dcb_config - Configure general DCB parameters
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to txgbe_dcb_config structure
+ *
+ * Configure general DCB parameters.
+ */
+s32 txgbe_dcb_config(struct txgbe_hw *hw,
+			   struct txgbe_dcb_config *dcb_config)
+{
+	u32 n, value;
+
+	struct txgbe_adapter *adapter = hw->back;
+
+	if (dcb_config->vt_mode)
+		adapter->flags |= TXGBE_FLAG_VMDQ_ENABLED;
+	else
+		adapter->flags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+
+	if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED) {
+		if (dcb_config->num_tcs.pg_tcs == 8)
+			/* 8 TCs */
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_8 |
+			      TXGBE_CFG_PORT_CTL_NUM_VT_16 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (dcb_config->num_tcs.pg_tcs == 4)
+			/* 4 TCs */
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_4 |
+			      TXGBE_CFG_PORT_CTL_NUM_VT_32 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (adapter->ring_feature[RING_F_RSS].indices == 4)
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_32;
+		else /* adapter->ring_feature[RING_F_RSS].indices <= 2 */
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_64;
+	} else {
+		if (dcb_config->num_tcs.pg_tcs == 8)
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_8 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (dcb_config->num_tcs.pg_tcs == 4)
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_4 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else
+			value = 0;
+	}
+
+	value |= TXGBE_CFG_PORT_CTL_D_VLAN | TXGBE_CFG_PORT_CTL_QINQ;
+	wr32m(hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_NUM_TC_MASK |
+		TXGBE_CFG_PORT_CTL_NUM_VT_MASK |
+		TXGBE_CFG_PORT_CTL_DCB_EN |
+		TXGBE_CFG_PORT_CTL_D_VLAN |
+		TXGBE_CFG_PORT_CTL_QINQ,
+		value);
+
+	/* Disable drop for all queues */
+	for (n = 0; n < 4; n++) {
+		wr32(hw, TXGBE_RDM_PF_QDE(n), 0x0);
+	}
+
+	return 0;
+}
+
+
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.h
new file mode 100644
index 000000000000..e912c076521d
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb.h
@@ -0,0 +1,208 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_dcb.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#ifndef _TXGBE_DCB_H_
+#define _TXGBE_DCB_H_
+
+#include "txgbe_type.h"
+
+/* DCB defines */
+/* DCB credit calculation defines */
+#define TXGBE_DCB_CREDIT_QUANTUM        64
+#define TXGBE_DCB_MAX_CREDIT_REFILL     200   /* 200 * 64B = 12800B */
+#define TXGBE_DCB_MAX_TSO_SIZE          (32 * 1024) /* Max TSO pkt size in DCB*/
+#define TXGBE_DCB_MAX_CREDIT            (2 * TXGBE_DCB_MAX_CREDIT_REFILL)
+
+/* 513 for 32KB TSO packet */
+#define TXGBE_DCB_MIN_TSO_CREDIT        \
+	((TXGBE_DCB_MAX_TSO_SIZE / TXGBE_DCB_CREDIT_QUANTUM) + 1)
+
+/* DCB configuration defines */
+#define TXGBE_DCB_MAX_USER_PRIORITY     8
+#define TXGBE_DCB_MAX_BW_GROUP          8
+#define TXGBE_DCB_BW_PERCENT            100
+
+#define TXGBE_DCB_TX_CONFIG             0
+#define TXGBE_DCB_RX_CONFIG             1
+
+/* DCB capability defines */
+#define TXGBE_DCB_PG_SUPPORT    0x00000001
+#define TXGBE_DCB_PFC_SUPPORT   0x00000002
+#define TXGBE_DCB_BCN_SUPPORT   0x00000004
+#define TXGBE_DCB_UP2TC_SUPPORT 0x00000008
+#define TXGBE_DCB_GSP_SUPPORT   0x00000010
+
+/* DCB register definitions */
+#define TXGBE_TDM_PBWARB_CTL_TDPAC      0x00000001 /* 0 Round Robin,
+					    * 1 WSP - Weighted Strict Priority
+					    */
+#define TXGBE_TDM_PBWARB_CTL_TDRM       0x00000010 /* Transmit Recycle Mode */
+#define TXGBE_TDM_PBWARB_CTL_ARBDIS     0x00000040 /* DCB arbiter disable */
+
+
+/* Receive UP2TC mapping */
+#define TXGBE_RDB_UP2TC_UP_SHIFT        4
+#define TXGBE_RDB_UP2TC_UP_MASK         7
+/* Transmit UP2TC mapping */
+#define TXGBE_TDB_UP2TC_UP_SHIFT        4
+
+#define TXGBE_RDM_ARB_CFG_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */
+#define TXGBE_RDM_ARB_CFG_BWG_SHIFT 9  /* Offset to BWG index */
+#define TXGBE_RDM_ARB_CFG_GSP   0x40000000 /* GSP enable bit */
+#define TXGBE_RDM_ARB_CFG_LSP   0x80000000 /* LSP enable bit */
+
+/* RTRPCS Bit Masks */
+#define TXGBE_RDM_ARB_CTL_RRM   0x00000002 /* Receive Recycle Mode enable */
+/* Receive Arbitration Control: 0 Round Robin, 1 DFP */
+#define TXGBE_RDM_ARB_CTL_RAC   0x00000004
+#define TXGBE_RDM_ARB_CTL_ARBDIS        0x00000040 /* Arbitration disable bit */
+
+/* RTTDT2C Bit Masks */
+#define TXGBE_TDM_PBWARB_CFG_MCL_SHIFT  12
+#define TXGBE_TDM_PBWARB_CFG_BWG_SHIFT  9
+#define TXGBE_TDM_PBWARB_CFG_GSP        0x40000000
+#define TXGBE_TDM_PBWARB_CFG_LSP        0x80000000
+
+#define TXGBE_TDB_PBRARB_CFG_MCL_SHIFT  12
+#define TXGBE_TDB_PBRARB_CFG_BWG_SHIFT  9
+#define TXGBE_TDB_PBRARB_CFG_GSP        0x40000000
+#define TXGBE_TDB_PBRARB_CFG_LSP        0x80000000
+
+/* RTTPCS Bit Masks */
+#define TXGBE_TDB_PBRARB_CTL_TPPAC      0x00000020 /* 0 Round Robin,
+						    * 1 SP - Strict Priority
+							*/
+#define TXGBE_RTTPCS_ARBDIS     	0x00000040 /* Arbiter disable */
+#define TXGBE_TDB_PBRARB_CTL_TPRM   0x00000100 /* Transmit Recycle Mode enable*/
+
+#define TXGBE_TDM_PB_THRE_DCB   0xA /* THRESH value for DCB mode */
+
+
+struct txgbe_dcb_support {
+	u32 capabilities; /* DCB capabilities */
+
+	/* Each bit represents a number of TCs configurable in the hw.
+	 * If 8 traffic classes can be configured, the value is 0x80. */
+	u8 traffic_classes;
+	u8 pfc_traffic_classes;
+};
+
+enum txgbe_dcb_tsa {
+	txgbe_dcb_tsa_ets = 0,
+	txgbe_dcb_tsa_group_strict_cee,
+	txgbe_dcb_tsa_strict
+};
+
+/* Traffic class bandwidth allocation per direction */
+struct txgbe_dcb_tc_path {
+	u8 bwg_id; /* Bandwidth Group (BWG) ID */
+	u8 bwg_percent; /* % of BWG's bandwidth */
+	u8 link_percent; /* % of link bandwidth */
+	u8 up_to_tc_bitmap; /* User Priority to Traffic Class mapping */
+	u16 data_credits_refill; /* Credit refill amount in 64B granularity */
+	u16 data_credits_max; /* Max credits for a configured packet buffer
+			       * in 64B granularity.*/
+	enum txgbe_dcb_tsa tsa; /* Link or Group Strict Priority */
+};
+
+enum txgbe_dcb_pfc {
+	txgbe_dcb_pfc_disabled = 0,
+	txgbe_dcb_pfc_enabled,
+	txgbe_dcb_pfc_enabled_txonly,
+	txgbe_dcb_pfc_enabled_rxonly
+};
+
+/* Traffic class configuration */
+struct txgbe_dcb_tc_config {
+	struct txgbe_dcb_tc_path path[2]; /* One each for Tx/Rx */
+	enum txgbe_dcb_pfc pfc; /* Class based flow control setting */
+
+	u16 desc_credits_max; /* For Tx Descriptor arbitration */
+	u8 tc; /* Traffic class (TC) */
+};
+
+enum txgbe_dcb_pba {
+	/* PBA[0-7] each use 64KB FIFO */
+	txgbe_dcb_pba_equal = PBA_STRATEGY_EQUAL,
+	/* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */
+	txgbe_dcb_pba_80_48 = PBA_STRATEGY_WEIGHTED
+};
+
+struct txgbe_dcb_num_tcs {
+	u8 pg_tcs;
+	u8 pfc_tcs;
+};
+
+struct txgbe_dcb_config {
+	struct txgbe_dcb_tc_config tc_config[TXGBE_DCB_MAX_TRAFFIC_CLASS];
+	struct txgbe_dcb_support support;
+	struct txgbe_dcb_num_tcs num_tcs;
+	u8 bw_percentage[2][TXGBE_DCB_MAX_BW_GROUP]; /* One each for Tx/Rx */
+	bool pfc_mode_enable;
+	bool round_robin_enable;
+
+	enum txgbe_dcb_pba rx_pba_cfg;
+
+	u32 dcb_cfg_version; /* Not used...OS-specific? */
+	u32 link_speed; /* For bandwidth allocation validation purpose */
+	bool vt_mode;
+};
+
+/* DCB driver APIs */
+
+/* DCB credits calculation */
+s32 txgbe_dcb_calculate_tc_credits(u8 *, u16 *, u16 *, int);
+s32 txgbe_dcb_calculate_tc_credits_cee(struct txgbe_hw *,
+				       struct txgbe_dcb_config *, u32, u8);
+
+/* DCB PFC */
+s32 txgbe_dcb_config_pfc(struct txgbe_hw *, u8, u8 *);
+
+/* DCB stats */
+s32 txgbe_dcb_config_tc_stats(struct txgbe_hw *,
+								struct txgbe_dcb_config *);
+
+/* DCB config arbiters */
+s32 txgbe_dcb_config_tx_desc_arbiter(struct txgbe_hw *, u16 *, u16 *,
+					   u8 *, u8 *);
+s32 txgbe_dcb_config_tx_data_arbiter(struct txgbe_hw *, u16 *, u16 *,
+					   u8 *, u8 *, u8 *);
+s32 txgbe_dcb_config_rx_arbiter(struct txgbe_hw *, u16 *, u16 *, u8 *,
+				      u8 *, u8 *);
+
+/* DCB unpack routines */
+void txgbe_dcb_unpack_pfc_cee(struct txgbe_dcb_config *, u8 *, u8 *);
+void txgbe_dcb_unpack_refill_cee(struct txgbe_dcb_config *, int, u16 *);
+void txgbe_dcb_unpack_max_cee(struct txgbe_dcb_config *, u16 *);
+void txgbe_dcb_unpack_bwgid_cee(struct txgbe_dcb_config *, int, u8 *);
+void txgbe_dcb_unpack_tsa_cee(struct txgbe_dcb_config *, int, u8 *);
+void txgbe_dcb_unpack_map_cee(struct txgbe_dcb_config *, int, u8 *);
+u8 txgbe_dcb_get_tc_from_up(struct txgbe_dcb_config *, int, u8);
+
+/* DCB initialization */
+s32 txgbe_dcb_config(struct txgbe_hw *,
+			   struct txgbe_dcb_config *);
+s32 txgbe_dcb_hw_config(struct txgbe_hw *, u16 *, u16 *, u8 *, u8 *, u8 *);
+s32 txgbe_dcb_hw_config_cee(struct txgbe_hw *, struct txgbe_dcb_config *);
+#endif /* _TXGBE_DCB_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb_nl.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb_nl.c
new file mode 100644
index 000000000000..0efb05b9977c
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_dcb_nl.c
@@ -0,0 +1,869 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_dcb_nl.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+
+#if IS_ENABLED(CONFIG_DCB)
+#include <linux/dcbnl.h>
+#include "txgbe_dcb.h"
+
+/* Callbacks for DCB netlink in the kernel */
+#define BIT_DCB_MODE    0x01
+#define BIT_PFC         0x02
+#define BIT_PG_RX       0x04
+#define BIT_PG_TX       0x08
+#define BIT_APP_UPCHG   0x10
+#define BIT_RESETLINK   0x40
+#define BIT_LINKSPEED   0x80
+
+/* Responses for the DCB_C_SET_ALL command */
+#define DCB_HW_CHG_RST  0  /* DCB configuration changed with reset */
+#define DCB_NO_HW_CHG   1  /* DCB configuration did not change */
+#define DCB_HW_CHG      2  /* DCB configuration changed, no reset */
+
+int txgbe_copy_dcb_cfg(struct txgbe_adapter *adapter, int tc_max)
+{
+	struct txgbe_dcb_config *scfg = &adapter->temp_dcb_cfg;
+	struct txgbe_dcb_config *dcfg = &adapter->dcb_cfg;
+	struct txgbe_dcb_tc_config *src = NULL;
+	struct txgbe_dcb_tc_config *dst = NULL;
+	int i, j;
+	int tx = TXGBE_DCB_TX_CONFIG;
+	int rx = TXGBE_DCB_RX_CONFIG;
+	int changes = 0;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (adapter->fcoe.up_set != adapter->fcoe.up)
+		changes |= BIT_APP_UPCHG;
+#endif /* CONFIG_FCOE */
+
+	for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) {
+		src = &scfg->tc_config[i - DCB_PG_ATTR_TC_0];
+		dst = &dcfg->tc_config[i - DCB_PG_ATTR_TC_0];
+
+		if (dst->path[tx].tsa != src->path[tx].tsa) {
+			dst->path[tx].tsa = src->path[tx].tsa;
+			changes |= BIT_PG_TX;
+		}
+
+		if (dst->path[tx].bwg_id != src->path[tx].bwg_id) {
+			dst->path[tx].bwg_id = src->path[tx].bwg_id;
+			changes |= BIT_PG_TX;
+		}
+
+		if (dst->path[tx].bwg_percent != src->path[tx].bwg_percent) {
+			dst->path[tx].bwg_percent = src->path[tx].bwg_percent;
+			changes |= BIT_PG_TX;
+		}
+
+		if (dst->path[tx].up_to_tc_bitmap !=
+		    src->path[tx].up_to_tc_bitmap) {
+			dst->path[tx].up_to_tc_bitmap =
+				src->path[tx].up_to_tc_bitmap;
+			changes |= (BIT_PG_TX | BIT_PFC | BIT_APP_UPCHG);
+		}
+
+		if (dst->path[rx].tsa != src->path[rx].tsa) {
+			dst->path[rx].tsa = src->path[rx].tsa;
+			changes |= BIT_PG_RX;
+		}
+
+		if (dst->path[rx].bwg_id != src->path[rx].bwg_id) {
+			dst->path[rx].bwg_id = src->path[rx].bwg_id;
+			changes |= BIT_PG_RX;
+		}
+
+		if (dst->path[rx].bwg_percent != src->path[rx].bwg_percent) {
+			dst->path[rx].bwg_percent = src->path[rx].bwg_percent;
+			changes |= BIT_PG_RX;
+		}
+
+		if (dst->path[rx].up_to_tc_bitmap !=
+		    src->path[rx].up_to_tc_bitmap) {
+			dst->path[rx].up_to_tc_bitmap =
+				src->path[rx].up_to_tc_bitmap;
+			changes |= (BIT_PG_RX | BIT_PFC | BIT_APP_UPCHG);
+		}
+	}
+
+	for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) {
+		j = i - DCB_PG_ATTR_BW_ID_0;
+
+		if (dcfg->bw_percentage[tx][j] != scfg->bw_percentage[tx][j]) {
+			dcfg->bw_percentage[tx][j] = scfg->bw_percentage[tx][j];
+			changes |= BIT_PG_TX;
+		}
+		if (dcfg->bw_percentage[rx][j] != scfg->bw_percentage[rx][j]) {
+			dcfg->bw_percentage[rx][j] = scfg->bw_percentage[rx][j];
+			changes |= BIT_PG_RX;
+		}
+	}
+
+	for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) {
+		j = i - DCB_PFC_UP_ATTR_0;
+		if (dcfg->tc_config[j].pfc != scfg->tc_config[j].pfc) {
+			dcfg->tc_config[j].pfc = scfg->tc_config[j].pfc;
+			changes |= BIT_PFC;
+		}
+	}
+
+	if (dcfg->pfc_mode_enable != scfg->pfc_mode_enable) {
+		dcfg->pfc_mode_enable = scfg->pfc_mode_enable;
+		changes |= BIT_PFC;
+	}
+
+	return changes;
+}
+
+static u8 txgbe_dcbnl_get_state(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	return !!(adapter->flags & TXGBE_FLAG_DCB_ENABLED);
+}
+
+static u8 txgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int err = 0;
+
+	/* Fail command if not in CEE mode */
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
+		return 1;
+
+	/* verify there is something to do, if not then exit */
+	if (!state == !(adapter->flags & TXGBE_FLAG_DCB_ENABLED))
+		goto out;
+
+	err = txgbe_setup_tc(netdev,
+			     state ? adapter->dcb_cfg.num_tcs.pg_tcs : 0);
+out:
+	return !!err;
+}
+
+static void txgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev,
+					 u8 *perm_addr)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int i, j;
+
+	memset(perm_addr, 0xff, MAX_ADDR_LEN);
+
+	for (i = 0; i < netdev->addr_len; i++)
+		perm_addr[i] = adapter->hw.mac.perm_addr[i];
+
+	for (j = 0; j < netdev->addr_len; j++, i++)
+		perm_addr[i] = adapter->hw.mac.san_addr[j];
+
+}
+
+static void txgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
+					 u8 prio, u8 bwg_id, u8 bw_pct,
+					 u8 up_map)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (prio != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].tsa = prio;
+	if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id;
+	if (bw_pct != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent =
+			bw_pct;
+	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap =
+			up_map;
+}
+
+static void txgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
+					  u8 bw_pct)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct;
+}
+
+static void txgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
+					 u8 prio, u8 bwg_id, u8 bw_pct,
+					 u8 up_map)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (prio != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].tsa = prio;
+	if (bwg_id != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id;
+	if (bw_pct != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent =
+			bw_pct;
+	if (up_map != DCB_ATTR_VALUE_UNDEFINED)
+		adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap =
+			up_map;
+}
+
+static void txgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
+					  u8 bw_pct)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct;
+}
+
+static void txgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc,
+					 u8 *prio, u8 *bwg_id, u8 *bw_pct,
+					 u8 *up_map)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	*prio = adapter->dcb_cfg.tc_config[tc].path[0].tsa;
+	*bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id;
+	*bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent;
+	*up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap;
+}
+
+static void txgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
+					  u8 *bw_pct)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	*bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id];
+}
+
+static void txgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc,
+					 u8 *prio, u8 *bwg_id, u8 *bw_pct,
+					 u8 *up_map)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	*prio = adapter->dcb_cfg.tc_config[tc].path[1].tsa;
+	*bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id;
+	*bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent;
+	*up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap;
+}
+
+static void txgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
+					  u8 *bw_pct)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	*bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id];
+}
+
+static void txgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int up, u8 pfc)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u8 tc = txgbe_dcb_get_tc_from_up(&adapter->temp_dcb_cfg, 0, up);
+
+	adapter->temp_dcb_cfg.tc_config[tc].pfc = pfc;
+	if (adapter->temp_dcb_cfg.tc_config[tc].pfc !=
+	    adapter->dcb_cfg.tc_config[tc].pfc)
+		adapter->temp_dcb_cfg.pfc_mode_enable = true;
+}
+
+static void txgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int up, u8 *pfc)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u8 tc = txgbe_dcb_get_tc_from_up(&adapter->dcb_cfg, 0, up);
+	*pfc = adapter->dcb_cfg.tc_config[tc].pfc;
+}
+
+static void txgbe_dcbnl_devreset(struct net_device *dev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+
+	while (test_and_set_bit(__TXGBE_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
+
+	if (netif_running(dev))
+#ifdef HAVE_NET_DEVICE_OPS
+		dev->netdev_ops->ndo_stop(dev);
+#else
+		dev->stop(dev);
+#endif
+
+	txgbe_clear_interrupt_scheme(adapter);
+	txgbe_init_interrupt_scheme(adapter);
+
+	if (netif_running(dev))
+#ifdef HAVE_NET_DEVICE_OPS
+		dev->netdev_ops->ndo_open(dev);
+#else
+		dev->open(dev);
+#endif
+
+	clear_bit(__TXGBE_RESETTING, &adapter->state);
+}
+
+static u8 txgbe_dcbnl_set_all(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_dcb_config *dcb_cfg = &adapter->dcb_cfg;
+	struct txgbe_hw *hw = &adapter->hw;
+	int ret = DCB_NO_HW_CHG;
+	u8 prio_tc[TXGBE_DCB_MAX_USER_PRIORITY] = { 0 };
+
+	/* Fail command if not in CEE mode */
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
+		return ret;
+
+	adapter->dcb_set_bitmap |= txgbe_copy_dcb_cfg(adapter,
+						TXGBE_DCB_MAX_TRAFFIC_CLASS);
+	if (!adapter->dcb_set_bitmap)
+		return ret;
+
+	txgbe_dcb_unpack_map_cee(dcb_cfg, TXGBE_DCB_TX_CONFIG, prio_tc);
+
+	if (adapter->dcb_set_bitmap & (BIT_PG_TX | BIT_PG_RX)) {
+		/* Priority to TC mapping in CEE case default to 1:1 */
+		int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+#ifdef HAVE_MQPRIO
+		int i;
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+		if (adapter->netdev->features & NETIF_F_FCOE_MTU)
+			max_frame = max(max_frame, TXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif
+
+		txgbe_dcb_calculate_tc_credits_cee(hw, dcb_cfg, max_frame,
+						   TXGBE_DCB_TX_CONFIG);
+
+		txgbe_dcb_calculate_tc_credits_cee(hw, dcb_cfg, max_frame,
+						   TXGBE_DCB_RX_CONFIG);
+
+		txgbe_dcb_hw_config_cee(hw, dcb_cfg);
+
+#ifdef HAVE_MQPRIO
+		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+			netdev_set_prio_tc_map(netdev, i, prio_tc[i]);
+#endif /* HAVE_MQPRIO */
+		ret = DCB_HW_CHG_RST;
+	}
+
+	if (adapter->dcb_set_bitmap & BIT_PFC) {
+		if (dcb_cfg->pfc_mode_enable) {
+			u8 pfc_en;
+			txgbe_dcb_unpack_pfc_cee(dcb_cfg, prio_tc, &pfc_en);
+			txgbe_dcb_config_pfc(hw, pfc_en, prio_tc);
+		} else {
+			TCALL(hw, mac.ops.fc_enable);
+		}
+		txgbe_set_rx_drop_en(adapter);
+		if (ret != DCB_HW_CHG_RST)
+			ret = DCB_HW_CHG;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* Reprogam FCoE hardware offloads when the traffic class
+	 * FCoE is using changes. This happens if the APP info
+	 * changes or the up2tc mapping is updated.
+	 */
+	if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
+		adapter->fcoe.up_set = adapter->fcoe.up;
+		txgbe_dcbnl_devreset(netdev);
+		ret = DCB_HW_CHG_RST;
+	}
+#endif /* CONFIG_FCOE */
+
+	adapter->dcb_set_bitmap = 0x00;
+	return ret;
+}
+
+static u8 txgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap)
+{
+#ifdef HAVE_DCBNL_IEEE
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#endif
+
+	switch (capid) {
+	case DCB_CAP_ATTR_PG:
+		*cap = true;
+		break;
+	case DCB_CAP_ATTR_PFC:
+		*cap = true;
+		break;
+	case DCB_CAP_ATTR_UP2TC:
+		*cap = false;
+		break;
+	case DCB_CAP_ATTR_PG_TCS:
+		*cap = 0x80;
+		break;
+	case DCB_CAP_ATTR_PFC_TCS:
+		*cap = 0x80;
+		break;
+	case DCB_CAP_ATTR_GSP:
+		*cap = true;
+		break;
+	case DCB_CAP_ATTR_BCN:
+		*cap = false;
+		break;
+#ifdef HAVE_DCBNL_IEEE
+	case DCB_CAP_ATTR_DCBX:
+		*cap = adapter->dcbx_cap;
+		break;
+#endif
+	default:
+		*cap = false;
+		break;
+	}
+
+	return 0;
+}
+
+#ifdef NUMTCS_RETURNS_U8
+static u8 txgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
+#else
+static int txgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u8 rval = 0;
+
+	if (adapter->flags & TXGBE_FLAG_DCB_ENABLED) {
+		switch (tcid) {
+		case DCB_NUMTCS_ATTR_PG:
+			*num = adapter->dcb_cfg.num_tcs.pg_tcs;
+			break;
+		case DCB_NUMTCS_ATTR_PFC:
+			*num = adapter->dcb_cfg.num_tcs.pfc_tcs;
+			break;
+		default:
+			rval = -EINVAL;
+			break;
+		}
+	} else {
+		rval = -EINVAL;
+	}
+
+	return rval;
+}
+
+#ifdef NUMTCS_RETURNS_U8
+static u8 txgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
+#else
+static int txgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u8 rval = 0;
+
+	if (adapter->flags & TXGBE_FLAG_DCB_ENABLED) {
+		switch (tcid) {
+		case DCB_NUMTCS_ATTR_PG:
+			adapter->dcb_cfg.num_tcs.pg_tcs = num;
+			break;
+		case DCB_NUMTCS_ATTR_PFC:
+			adapter->dcb_cfg.num_tcs.pfc_tcs = num;
+			break;
+		default:
+			rval = -EINVAL;
+			break;
+		}
+	} else {
+		rval = -EINVAL;
+	}
+
+	return rval;
+}
+
+static u8 txgbe_dcbnl_getpfcstate(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	return adapter->dcb_cfg.pfc_mode_enable;
+}
+
+static void txgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	adapter->temp_dcb_cfg.pfc_mode_enable = state;
+	return;
+}
+
+#ifdef HAVE_DCBNL_OPS_GETAPP
+/**
+ * txgbe_dcbnl_getapp - retrieve the DCBX application user priority
+ * @netdev : the corresponding netdev
+ * @idtype : identifies the id as ether type or TCP/UDP port number
+ * @id: id is either ether type or TCP/UDP port number
+ *
+ * Returns : on success, returns a non-zero 802.1p user priority bitmap
+ * otherwise returns 0 as the invalid user priority bitmap to indicate an
+ * error.
+ */
+#ifdef HAVE_DCBNL_OPS_SETAPP_RETURN_INT
+static int txgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
+#else
+static u8 txgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
+#endif
+{
+	u8 rval = 0;
+#ifdef HAVE_DCBNL_IEEE
+	struct dcb_app app = {
+		.selector = idtype,
+		.protocol = id,
+	};
+
+	rval = dcb_getapp(netdev, &app);
+#endif
+
+	switch (idtype) {
+	case DCB_APP_IDTYPE_ETHTYPE:
+#if IS_ENABLED(CONFIG_FCOE)
+		if (id == ETH_P_FCOE)
+			rval = txgbe_fcoe_getapp(netdev);
+#endif
+		break;
+	case DCB_APP_IDTYPE_PORTNUM:
+		break;
+	default:
+		break;
+	}
+
+	return rval;
+}
+
+/**
+ * txgbe_dcbnl_setapp - set the DCBX application user priority
+ * @netdev : the corresponding netdev
+ * @idtype : identifies the id as ether type or TCP/UDP port number
+ * @id: id is either ether type or TCP/UDP port number
+ * @up: the 802.1p user priority bitmap
+ *
+ * Returns : 0 on success or 1 on error
+ */
+#ifdef HAVE_DCBNL_OPS_SETAPP_RETURN_INT
+static int txgbe_dcbnl_setapp(struct net_device *netdev,
+#else
+static u8 txgbe_dcbnl_setapp(struct net_device *netdev,
+#endif
+			     u8 idtype, u16 id, u8 up)
+{
+	int err = 0;
+#ifdef HAVE_DCBNL_IEEE
+	struct dcb_app app;
+
+	app.selector = idtype;
+	app.protocol = id;
+	app.priority = up;
+	err = dcb_setapp(netdev, &app);
+#endif
+
+	switch (idtype) {
+	case DCB_APP_IDTYPE_ETHTYPE:
+#if IS_ENABLED(CONFIG_FCOE)
+		if (id == ETH_P_FCOE) {
+			struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+			adapter->fcoe.up = up ? ffs(up) - 1 : TXGBE_FCOE_DEFUP;
+		}
+#endif
+		break;
+	case DCB_APP_IDTYPE_PORTNUM:
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+#endif /* HAVE_DCBNL_OPS_GETAPP */
+
+#ifdef HAVE_DCBNL_IEEE
+static int txgbe_dcbnl_ieee_getets(struct net_device *dev,
+				   struct ieee_ets *ets)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct ieee_ets *my_ets = adapter->txgbe_ieee_ets;
+
+	/* No IEEE PFC settings available */
+	if (!my_ets)
+		return -EINVAL;
+
+	ets->ets_cap = adapter->dcb_cfg.num_tcs.pg_tcs;
+	ets->cbs = my_ets->cbs;
+	memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
+	memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
+	memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
+	memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
+	return 0;
+}
+
+static int txgbe_dcbnl_ieee_setets(struct net_device *dev,
+				   struct ieee_ets *ets)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	int i, err = 0;
+	__u8 max_tc = 0;
+	__u8 map_chg = 0;
+
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+		return -EINVAL;
+
+	if (!adapter->txgbe_ieee_ets) {
+		adapter->txgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets),
+						  GFP_KERNEL);
+		if (!adapter->txgbe_ieee_ets)
+			return -ENOMEM;
+		/* initialize UP2TC mappings to invalid value */
+		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+			adapter->txgbe_ieee_ets->prio_tc[i] =
+				IEEE_8021QAZ_MAX_TCS;
+		/* if possible update UP2TC mappings from HW */
+		TCALL(&adapter->hw, mac.ops.get_rtrup2tc,
+					adapter->txgbe_ieee_ets->prio_tc);
+	}
+
+	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+		if (ets->prio_tc[i] > max_tc)
+			max_tc = ets->prio_tc[i];
+		if (ets->prio_tc[i] != adapter->txgbe_ieee_ets->prio_tc[i])
+			map_chg = 1;
+	}
+
+	memcpy(adapter->txgbe_ieee_ets, ets, sizeof(*adapter->txgbe_ieee_ets));
+
+	if (max_tc)
+		max_tc++;
+
+	if (max_tc > adapter->dcb_cfg.num_tcs.pg_tcs)
+		return -EINVAL;
+
+	if (max_tc != netdev_get_num_tc(dev))
+		err = txgbe_setup_tc(dev, max_tc);
+	else if (map_chg)
+		txgbe_dcbnl_devreset(dev);
+
+	if (err)
+		goto err_out;
+
+	err = txgbe_dcb_hw_ets(&adapter->hw, ets, max_frame);
+err_out:
+	return err;
+}
+
+static int txgbe_dcbnl_ieee_getpfc(struct net_device *dev,
+				   struct ieee_pfc *pfc)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct ieee_pfc *my_pfc = adapter->txgbe_ieee_pfc;
+	int i;
+
+	/* No IEEE PFC settings available */
+	if (!my_pfc)
+		return -EINVAL;
+
+	pfc->pfc_cap = adapter->dcb_cfg.num_tcs.pfc_tcs;
+	pfc->pfc_en = my_pfc->pfc_en;
+	pfc->mbc = my_pfc->mbc;
+	pfc->delay = my_pfc->delay;
+
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		pfc->requests[i] = adapter->stats.pxoffrxc[i];
+		pfc->indications[i] = adapter->stats.pxofftxc[i];
+	}
+
+	return 0;
+}
+
+static int txgbe_dcbnl_ieee_setpfc(struct net_device *dev,
+				   struct ieee_pfc *pfc)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u8 *prio_tc;
+	int err;
+
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+		return -EINVAL;
+
+	if (!adapter->txgbe_ieee_pfc) {
+		adapter->txgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc),
+						  GFP_KERNEL);
+		if (!adapter->txgbe_ieee_pfc)
+			return -ENOMEM;
+	}
+
+	prio_tc = adapter->txgbe_ieee_ets->prio_tc;
+	memcpy(adapter->txgbe_ieee_pfc, pfc, sizeof(*adapter->txgbe_ieee_pfc));
+
+
+	/* Enable link flow control parameters if PFC is disabled */
+	if (pfc->pfc_en)
+		err = txgbe_dcb_config_pfc(hw, pfc->pfc_en, prio_tc);
+	else
+		err = TCALL(hw, mac.ops.fc_enable);
+
+	txgbe_set_rx_drop_en(adapter);
+
+	return err;
+}
+
+static int txgbe_dcbnl_ieee_setapp(struct net_device *dev,
+				   struct dcb_app *app)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	int err = -EINVAL;
+
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+		return err;
+
+	err = dcb_ieee_setapp(dev, app);
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+	    app->protocol == ETH_P_FCOE) {
+		u8 app_mask = dcb_ieee_getapp_mask(dev, app);
+
+		if (app_mask & (1 << adapter->fcoe.up))
+			return err;
+
+		adapter->fcoe.up = app->priority;
+		adapter->fcoe.up_set = adapter->fcoe.up;
+		txgbe_dcbnl_devreset(dev);
+	}
+#endif
+	return 0;
+}
+
+#ifdef HAVE_DCBNL_IEEE_DELAPP
+static int txgbe_dcbnl_ieee_delapp(struct net_device *dev,
+				   struct dcb_app *app)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	int err;
+
+	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+		return -EINVAL;
+
+	err = dcb_ieee_delapp(dev, app);
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+	    app->protocol == ETH_P_FCOE) {
+		u8 app_mask = dcb_ieee_getapp_mask(dev, app);
+
+		if (app_mask & (1 << adapter->fcoe.up))
+			return err;
+
+		adapter->fcoe.up = app_mask ?
+				   ffs(app_mask) - 1 : TXGBE_FCOE_DEFUP;
+		txgbe_dcbnl_devreset(dev);
+	}
+#endif
+	return err;
+}
+#endif /* HAVE_DCBNL_IEEE_DELAPP */
+
+static u8 txgbe_dcbnl_getdcbx(struct net_device *dev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	return adapter->dcbx_cap;
+}
+
+static u8 txgbe_dcbnl_setdcbx(struct net_device *dev, u8 mode)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct ieee_ets ets = { .ets_cap = 0 };
+	struct ieee_pfc pfc = { .pfc_en = 0 };
+
+	/* no support for LLD_MANAGED modes or CEE+IEEE */
+	if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
+	    ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) ||
+	    !(mode & DCB_CAP_DCBX_HOST))
+		return 1;
+
+	if (mode == adapter->dcbx_cap)
+		return 0;
+
+	adapter->dcbx_cap = mode;
+
+	/* ETS and PFC defaults */
+	ets.ets_cap = 8;
+	pfc.pfc_cap = 8;
+
+	if (mode & DCB_CAP_DCBX_VER_IEEE) {
+		txgbe_dcbnl_ieee_setets(dev, &ets);
+		txgbe_dcbnl_ieee_setpfc(dev, &pfc);
+	} else if (mode & DCB_CAP_DCBX_VER_CEE) {
+		u8 mask = (BIT_PFC | BIT_PG_TX | BIT_PG_RX | BIT_APP_UPCHG);
+
+		adapter->dcb_set_bitmap |= mask;
+		txgbe_dcbnl_set_all(dev);
+	} else {
+		/* Drop into single TC mode strict priority as this
+		 * indicates CEE and IEEE versions are disabled
+		 */
+		txgbe_dcbnl_ieee_setets(dev, &ets);
+		txgbe_dcbnl_ieee_setpfc(dev, &pfc);
+		txgbe_setup_tc(dev, 0);
+	}
+
+	return 0;
+}
+#endif
+
+struct dcbnl_rtnl_ops dcbnl_ops = {
+#ifdef HAVE_DCBNL_IEEE
+	.ieee_getets    = txgbe_dcbnl_ieee_getets,
+	.ieee_setets    = txgbe_dcbnl_ieee_setets,
+	.ieee_getpfc    = txgbe_dcbnl_ieee_getpfc,
+	.ieee_setpfc    = txgbe_dcbnl_ieee_setpfc,
+	.ieee_setapp    = txgbe_dcbnl_ieee_setapp,
+#ifdef HAVE_DCBNL_IEEE_DELAPP
+	.ieee_delapp    = txgbe_dcbnl_ieee_delapp,
+#endif
+#endif
+	.getstate       = txgbe_dcbnl_get_state,
+	.setstate       = txgbe_dcbnl_set_state,
+	.getpermhwaddr  = txgbe_dcbnl_get_perm_hw_addr,
+	.setpgtccfgtx   = txgbe_dcbnl_set_pg_tc_cfg_tx,
+	.setpgbwgcfgtx  = txgbe_dcbnl_set_pg_bwg_cfg_tx,
+	.setpgtccfgrx   = txgbe_dcbnl_set_pg_tc_cfg_rx,
+	.setpgbwgcfgrx  = txgbe_dcbnl_set_pg_bwg_cfg_rx,
+	.getpgtccfgtx   = txgbe_dcbnl_get_pg_tc_cfg_tx,
+	.getpgbwgcfgtx  = txgbe_dcbnl_get_pg_bwg_cfg_tx,
+	.getpgtccfgrx   = txgbe_dcbnl_get_pg_tc_cfg_rx,
+	.getpgbwgcfgrx  = txgbe_dcbnl_get_pg_bwg_cfg_rx,
+	.setpfccfg      = txgbe_dcbnl_set_pfc_cfg,
+	.getpfccfg      = txgbe_dcbnl_get_pfc_cfg,
+	.setall         = txgbe_dcbnl_set_all,
+	.getcap         = txgbe_dcbnl_getcap,
+	.getnumtcs      = txgbe_dcbnl_getnumtcs,
+	.setnumtcs      = txgbe_dcbnl_setnumtcs,
+	.getpfcstate    = txgbe_dcbnl_getpfcstate,
+	.setpfcstate    = txgbe_dcbnl_setpfcstate,
+#ifdef HAVE_DCBNL_OPS_GETAPP
+	.getapp         = txgbe_dcbnl_getapp,
+	.setapp         = txgbe_dcbnl_setapp,
+#endif
+#ifdef HAVE_DCBNL_IEEE
+	.getdcbx        = txgbe_dcbnl_getdcbx,
+	.setdcbx        = txgbe_dcbnl_setdcbx,
+#endif
+};
+
+#endif /* CONFIG_DCB */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_debugfs.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_debugfs.c
new file mode 100644
index 000000000000..7489006f607e
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_debugfs.c
@@ -0,0 +1,804 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_debugfs.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+
+#ifdef HAVE_TXGBE_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+static struct dentry *txgbe_dbg_root;
+static int txgbe_data_mode;
+
+#define TXGBE_DATA_FUNC(dm)  ((dm) & ~0xFFFF)
+#define TXGBE_DATA_ARGS(dm)  ((dm) & 0xFFFF)
+enum txgbe_data_func {
+	TXGBE_FUNC_NONE        = (0 << 16),
+	TXGBE_FUNC_DUMP_BAR    = (1 << 16),
+	TXGBE_FUNC_DUMP_RDESC  = (2 << 16),
+	TXGBE_FUNC_DUMP_TDESC  = (3 << 16),
+	TXGBE_FUNC_FLASH_READ  = (4 << 16),
+	TXGBE_FUNC_FLASH_WRITE = (5 << 16),
+};
+
+/**
+ * data operation
+ **/
+ssize_t
+txgbe_simple_read_from_pcibar(struct txgbe_adapter *adapter, int res,
+		void __user *buf, size_t size, loff_t *ppos)
+{
+	loff_t pos = *ppos;
+	u32 miss, len, limit = pci_resource_len(adapter->pdev, res);
+
+	if (pos < 0)
+		return 0;
+
+	limit = (pos + size <= limit ? pos + size : limit);
+	for (miss = 0; pos < limit && !miss; buf += len, pos += len) {
+		u32 val = 0, reg = round_down(pos, 4);
+		u32 off = pos - reg;
+
+		len = (reg + 4 <= limit ? 4 - off : 4 - off - (limit - reg - 4));
+		val = txgbe_rd32(adapter->io_addr + reg);
+		miss = copy_to_user(buf, &val + off, len);
+	}
+
+	size = pos - *ppos - miss;
+	*ppos += size;
+
+	return size;
+}
+
+ssize_t
+txgbe_simple_read_from_flash(struct txgbe_adapter *adapter,
+		void __user *buf, size_t size, loff_t *ppos)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	loff_t pos = *ppos;
+	size_t ret = 0;
+	loff_t rpos, rtail;
+	void __user *to = buf;
+	size_t available = adapter->hw.flash.dword_size << 2;
+
+	if (pos < 0)
+		return -EINVAL;
+	if (pos >= available || !size)
+		return 0;
+	if (size > available - pos)
+		size = available - pos;
+
+	rpos = round_up(pos, 4);
+	rtail = round_down(pos + size, 4);
+	if (rtail < rpos)
+		return 0;
+
+	to += rpos - pos;
+	while (rpos <= rtail) {
+		u32 value = txgbe_rd32(adapter->io_addr + rpos);
+		if (TCALL(hw, flash.ops.write_buffer, rpos>>2, 1, &value)) {
+			ret = size;
+			break;
+		}
+		if (4 == copy_to_user(to, &value, 4)) {
+			ret = size;
+			break;
+		}
+		to += 4;
+		rpos += 4;
+	}
+
+	if (ret == size)
+		return -EFAULT;
+	size -= ret;
+	*ppos = pos + size;
+	return size;
+}
+
+ssize_t
+txgbe_simple_write_to_flash(struct txgbe_adapter *adapter,
+	const void __user *from, size_t size, loff_t *ppos, size_t available)
+{
+	return size;
+}
+
+static ssize_t
+txgbe_dbg_data_ops_read(struct file *filp, char __user *buffer,
+				    size_t size, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	u32 func = TXGBE_DATA_FUNC(txgbe_data_mode);
+
+	rmb();
+
+	switch (func) {
+	case TXGBE_FUNC_DUMP_BAR: {
+		u32 bar = TXGBE_DATA_ARGS(txgbe_data_mode);
+
+		return txgbe_simple_read_from_pcibar(adapter, bar, buffer, size,
+					       ppos);
+		break;
+	}
+	case TXGBE_FUNC_FLASH_READ: {
+		return txgbe_simple_read_from_flash(adapter, buffer, size, ppos);
+		break;
+	}
+	case TXGBE_FUNC_DUMP_RDESC: {
+		struct txgbe_ring *ring;
+		u32 queue = TXGBE_DATA_ARGS(txgbe_data_mode);
+
+		if (queue >= adapter->num_rx_queues)
+			return 0;
+		queue += VMDQ_P(0) * adapter->queues_per_pool;
+		ring = adapter->rx_ring[queue];
+
+		return simple_read_from_buffer(buffer, size, ppos,
+			ring->desc, ring->size);
+		break;
+	}
+	case TXGBE_FUNC_DUMP_TDESC: {
+		struct txgbe_ring *ring;
+		u32 queue = TXGBE_DATA_ARGS(txgbe_data_mode);
+
+		if (queue >= adapter->num_tx_queues)
+			return 0;
+		queue += VMDQ_P(0) * adapter->queues_per_pool;
+		ring = adapter->tx_ring[queue];
+
+		return simple_read_from_buffer(buffer, size, ppos,
+			ring->desc, ring->size);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t
+txgbe_dbg_data_ops_write(struct file *filp,
+				     const char __user *buffer,
+				     size_t size, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	u32 func = TXGBE_DATA_FUNC(txgbe_data_mode);
+
+	rmb();
+
+	switch (func) {
+	case TXGBE_FUNC_FLASH_WRITE: {
+		u32 size = TXGBE_DATA_ARGS(txgbe_data_mode);
+
+		if (size > adapter->hw.flash.dword_size << 2)
+			size = adapter->hw.flash.dword_size << 2;
+
+		return txgbe_simple_write_to_flash(adapter, buffer, size, ppos, size);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return size;
+}
+static struct file_operations txgbe_dbg_data_ops_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = txgbe_dbg_data_ops_read,
+	.write = txgbe_dbg_data_ops_write,
+};
+
+/**
+ * reg_ops operation
+ **/
+static char txgbe_dbg_reg_ops_buf[256] = "";
+static ssize_t
+txgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer,
+				    size_t count, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	char *buf;
+	int len;
+
+	/* don't allow partial reads */
+	if (*ppos != 0)
+		return 0;
+
+	buf = kasprintf(GFP_KERNEL, "%s: mode=0x%08x\n%s\n",
+			adapter->netdev->name, txgbe_data_mode,
+			txgbe_dbg_reg_ops_buf);
+	if (!buf)
+		return -ENOMEM;
+
+	if (count < strlen(buf)) {
+		kfree(buf);
+		return -ENOSPC;
+	}
+
+	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+
+	kfree(buf);
+	return len;
+}
+
+static ssize_t
+txgbe_dbg_reg_ops_write(struct file *filp,
+				     const char __user *buffer,
+				     size_t count, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	char *pc = txgbe_dbg_reg_ops_buf;
+	int len;
+
+	/* don't allow partial writes */
+	if (*ppos != 0)
+		return 0;
+	if (count >= sizeof(txgbe_dbg_reg_ops_buf))
+		return -ENOSPC;
+
+	len = simple_write_to_buffer(txgbe_dbg_reg_ops_buf,
+				     sizeof(txgbe_dbg_reg_ops_buf)-1,
+				     ppos,
+				     buffer,
+				     count);
+	if (len < 0)
+		return len;
+
+	pc[len] = '\0';
+
+	if (strncmp(pc, "dump", 4) == 0) {
+		u32 mode = 0;
+		u16 args;
+
+		pc += 4;
+		pc += strspn(pc, " \t");
+
+		if (!strncmp(pc, "bar", 3)) {
+			pc += 3;
+			mode = TXGBE_FUNC_DUMP_BAR;
+		} else if (!strncmp(pc, "rdesc", 5)) {
+			pc += 5;
+			mode = TXGBE_FUNC_DUMP_RDESC;
+		} else if (!strncmp(pc, "tdesc", 5)) {
+			pc += 5;
+			mode = TXGBE_FUNC_DUMP_TDESC;
+		} else {
+			txgbe_dump(adapter);
+		}
+
+		if (mode && 1 == sscanf(pc, "%hu", &args)) {
+			mode |= args;
+		}
+
+		txgbe_data_mode = mode;
+	} else if (strncmp(pc, "flash", 4) == 0) {
+		u32 mode = 0;
+		u16 args;
+
+		pc += 5;
+		pc += strspn(pc, " \t");
+		if (!strncmp(pc, "read", 3)) {
+			pc += 4;
+			mode = TXGBE_FUNC_FLASH_READ;
+		} else if (!strncmp(pc, "write", 5)) {
+			pc += 5;
+			mode = TXGBE_FUNC_FLASH_WRITE;
+		}
+
+		if (mode && 1 == sscanf(pc, "%hu", &args)) {
+			mode |= args;
+		}
+
+		txgbe_data_mode = mode;
+	} else if (strncmp(txgbe_dbg_reg_ops_buf, "write", 5) == 0) {
+		u32 reg, value;
+		int cnt;
+		cnt = sscanf(&txgbe_dbg_reg_ops_buf[5], "%x %x", &reg, &value);
+		if (cnt == 2) {
+			wr32(&adapter->hw, reg, value);
+			e_dev_info("write: 0x%08x = 0x%08x\n", reg, value);
+		} else {
+			e_dev_info("write <reg> <value>\n");
+		}
+	} else if (strncmp(txgbe_dbg_reg_ops_buf, "read", 4) == 0) {
+		u32 reg, value;
+		int cnt;
+		cnt = sscanf(&txgbe_dbg_reg_ops_buf[4], "%x", &reg);
+		if (cnt == 1) {
+			value = rd32(&adapter->hw, reg);
+			e_dev_info("read 0x%08x = 0x%08x\n", reg, value);
+		} else {
+			e_dev_info("read <reg>\n");
+		}
+	} else {
+		e_dev_info("Unknown command %s\n", txgbe_dbg_reg_ops_buf);
+		e_dev_info("Available commands:\n");
+		e_dev_info("   read <reg>\n");
+		e_dev_info("   write <reg> <value>\n");
+	}
+	return count;
+}
+
+static const struct file_operations txgbe_dbg_reg_ops_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read =  txgbe_dbg_reg_ops_read,
+	.write = txgbe_dbg_reg_ops_write,
+};
+
+/**
+ * netdev_ops operation
+ **/
+static char txgbe_dbg_netdev_ops_buf[256] = "";
+static ssize_t
+txgbe_dbg_netdev_ops_read(struct file *filp,
+					 char __user *buffer,
+					 size_t count, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	char *buf;
+	int len;
+
+	/* don't allow partial reads */
+	if (*ppos != 0)
+		return 0;
+
+	buf = kasprintf(GFP_KERNEL, "%s: mode=0x%08x\n%s\n",
+			adapter->netdev->name, txgbe_data_mode,
+			txgbe_dbg_netdev_ops_buf);
+	if (!buf)
+		return -ENOMEM;
+
+	if (count < strlen(buf)) {
+		kfree(buf);
+		return -ENOSPC;
+	}
+
+	len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+
+	kfree(buf);
+	return len;
+}
+
+static ssize_t
+txgbe_dbg_netdev_ops_write(struct file *filp,
+					  const char __user *buffer,
+					  size_t count, loff_t *ppos)
+{
+	struct txgbe_adapter *adapter = filp->private_data;
+	int len;
+
+	/* don't allow partial writes */
+	if (*ppos != 0)
+		return 0;
+	if (count >= sizeof(txgbe_dbg_netdev_ops_buf))
+		return -ENOSPC;
+
+	len = simple_write_to_buffer(txgbe_dbg_netdev_ops_buf,
+				     sizeof(txgbe_dbg_netdev_ops_buf)-1,
+				     ppos,
+				     buffer,
+				     count);
+	if (len < 0)
+		return len;
+
+	txgbe_dbg_netdev_ops_buf[len] = '\0';
+
+	if (strncmp(txgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
+#if defined(HAVE_TX_TIMEOUT_TXQUEUE)
+		adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev, 0);
+#elif defined(HAVE_NET_DEVICE_OPS) 
+		adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev);
+#else
+		adapter->netdev->tx_timeout(adapter->netdev);
+#endif /* HAVE_NET_DEVICE_OPS */
+		e_dev_info("tx_timeout called\n");
+	} else {
+		e_dev_info("Unknown command: %s\n", txgbe_dbg_netdev_ops_buf);
+		e_dev_info("Available commands:\n");
+		e_dev_info("    tx_timeout\n");
+	}
+	return count;
+}
+
+static struct file_operations txgbe_dbg_netdev_ops_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = txgbe_dbg_netdev_ops_read,
+	.write = txgbe_dbg_netdev_ops_write,
+};
+
+/**
+ * txgbe_dbg_adapter_init - setup the debugfs directory for the adapter
+ * @adapter: the adapter that is starting up
+ **/
+void txgbe_dbg_adapter_init(struct txgbe_adapter *adapter)
+{
+	const char *name = pci_name(adapter->pdev);
+	struct dentry *pfile;
+
+	adapter->txgbe_dbg_adapter = debugfs_create_dir(name, txgbe_dbg_root);
+	if (!adapter->txgbe_dbg_adapter) {
+		e_dev_err("debugfs entry for %s failed\n", name);
+		return;
+	}
+
+	pfile = debugfs_create_file("data", 0600,
+				    adapter->txgbe_dbg_adapter, adapter,
+				    &txgbe_dbg_data_ops_fops);
+	if (!pfile)
+		e_dev_err("debugfs netdev_ops for %s failed\n", name);
+
+	pfile = debugfs_create_file("reg_ops", 0600,
+				    adapter->txgbe_dbg_adapter, adapter,
+				    &txgbe_dbg_reg_ops_fops);
+	if (!pfile)
+		e_dev_err("debugfs reg_ops for %s failed\n", name);
+
+	pfile = debugfs_create_file("netdev_ops", 0600,
+				    adapter->txgbe_dbg_adapter, adapter,
+				    &txgbe_dbg_netdev_ops_fops);
+	if (!pfile)
+		e_dev_err("debugfs netdev_ops for %s failed\n", name);
+}
+
+/**
+ * txgbe_dbg_adapter_exit - clear out the adapter's debugfs entries
+ * @pf: the pf that is stopping
+ **/
+void txgbe_dbg_adapter_exit(struct txgbe_adapter *adapter)
+{
+	if (adapter->txgbe_dbg_adapter)
+		debugfs_remove_recursive(adapter->txgbe_dbg_adapter);
+	adapter->txgbe_dbg_adapter = NULL;
+}
+
+/**
+ * txgbe_dbg_init - start up debugfs for the driver
+ **/
+void txgbe_dbg_init(void)
+{
+	txgbe_dbg_root = debugfs_create_dir(txgbe_driver_name, NULL);
+	if (txgbe_dbg_root == NULL)
+		pr_err("init of debugfs failed\n");
+}
+
+/**
+ * txgbe_dbg_exit - clean out the driver's debugfs entries
+ **/
+void txgbe_dbg_exit(void)
+{
+	debugfs_remove_recursive(txgbe_dbg_root);
+}
+
+#endif /* HAVE_TXGBE_DEBUG_FS */
+
+struct txgbe_reg_info {
+	u32 offset;
+	u32 length;
+	char *name;
+};
+
+static struct txgbe_reg_info txgbe_reg_info_tbl[] = {
+
+	/* General Registers */
+	{TXGBE_CFG_PORT_CTL, 1, "CTRL"},
+	{TXGBE_CFG_PORT_ST, 1, "STATUS"},
+
+	/* RX Registers */
+	{TXGBE_PX_RR_CFG(0), 1, "SRRCTL"},
+	{TXGBE_PX_RR_RP(0), 1, "RDH"},
+	{TXGBE_PX_RR_WP(0), 1, "RDT"},
+	{TXGBE_PX_RR_CFG(0), 1, "RXDCTL"},
+	{TXGBE_PX_RR_BAL(0), 1, "RDBAL"},
+	{TXGBE_PX_RR_BAH(0), 1, "RDBAH"},
+
+	/* TX Registers */
+	{TXGBE_PX_TR_BAL(0), 1, "TDBAL"},
+	{TXGBE_PX_TR_BAH(0), 1, "TDBAH"},
+	{TXGBE_PX_TR_RP(0), 1, "TDH"},
+	{TXGBE_PX_TR_WP(0), 1, "TDT"},
+	{TXGBE_PX_TR_CFG(0), 1, "TXDCTL"},
+
+	/* MACVLAN */
+	{TXGBE_PSR_MAC_SWC_VM_H, 128, "PSR_MAC_SWC_VM"},
+	{TXGBE_PSR_MAC_SWC_AD_L, 128, "PSR_MAC_SWC_AD"},
+	{TXGBE_PSR_VLAN_TBL(0),  128, "PSR_VLAN_TBL"},
+
+	/* QoS */
+	{TXGBE_TDM_RP_RATE, 128, "TDM_RP_RATE"},
+
+	/* List Terminator */
+	{ .name = NULL }
+};
+
+/**
+ * txgbe_regdump - register printout routine
+ **/
+static void
+txgbe_regdump(struct txgbe_hw *hw, struct txgbe_reg_info *reg_info)
+{
+	int i, n = 0;
+	u32 buffer[32*8];
+
+	switch (reg_info->offset) {
+	case TXGBE_PSR_MAC_SWC_VM_H:
+		for (i = 0; i < reg_info->length; i++) {
+			wr32(hw, TXGBE_PSR_MAC_SWC_IDX, i);
+			buffer[n++] =
+				rd32(hw, TXGBE_PSR_MAC_SWC_VM_H);
+			buffer[n++] =
+				rd32(hw, TXGBE_PSR_MAC_SWC_VM_L);
+		}
+		break;
+	case TXGBE_PSR_MAC_SWC_AD_L:
+		for (i = 0; i < reg_info->length; i++) {
+			wr32(hw, TXGBE_PSR_MAC_SWC_IDX, i);
+			buffer[n++] =
+				rd32(hw, TXGBE_PSR_MAC_SWC_AD_H);
+			buffer[n++] =
+				rd32(hw, TXGBE_PSR_MAC_SWC_AD_L);
+		}
+		break;
+	case TXGBE_TDM_RP_RATE:
+		for (i = 0; i < reg_info->length; i++) {
+			wr32(hw, TXGBE_TDM_RP_IDX, i);
+			buffer[n++] = rd32(hw, TXGBE_TDM_RP_RATE);
+		}
+		break;
+	default:
+		for (i = 0; i < reg_info->length; i++) {
+			buffer[n++] = rd32(hw,
+				reg_info->offset + 4*i);
+		}
+		break;
+	}
+#if 0
+	for (i = 0; n && i < 32; i++) {
+		pr_info("%-20s[%02x-%02x]", reg_info->name, i*8, i*8 + 7);
+		for (j = 0; n && j < 8; j++, n--)
+			pr_cont(" %08x", buffer[i*8 + j]);
+		pr_cont("\n");
+	}
+#endif
+	BUG_ON(n);
+}
+
+/**
+ * txgbe_dump - Print registers, tx-rings and rx-rings
+ **/
+void txgbe_dump(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_reg_info *reg_info;
+	int n = 0;
+	struct txgbe_ring *tx_ring;
+	struct txgbe_tx_buffer *tx_buffer;
+	union txgbe_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct txgbe_ring *rx_ring;
+	union txgbe_rx_desc *rx_desc;
+	struct txgbe_rx_buffer *rx_buffer_info;
+	u32 staterr;
+	int i = 0;
+
+	if (!netif_msg_hw(adapter))
+		return;
+
+	/* Print Registers */
+	dev_info(&adapter->pdev->dev, "Register Dump\n");
+	pr_info(" Register Name   Value\n");
+	for (reg_info = txgbe_reg_info_tbl; reg_info->name; reg_info++) {
+		txgbe_regdump(hw, reg_info);
+	}
+
+	/* Print TX Ring Summary */
+	if (!netdev || !netif_running(netdev))
+		return;
+
+	dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+	pr_info(" %s     %s              %s        %s\n",
+		"Queue [NTU] [NTC] [bi(ntc)->dma  ]",
+		"leng", "ntw", "timestamp");
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = adapter->tx_ring[n];
+		tx_buffer = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
+		pr_info(" %5d %5X %5X %016llX %08X %p %016llX\n",
+			   n, tx_ring->next_to_use, tx_ring->next_to_clean,
+			   (u64)dma_unmap_addr(tx_buffer, dma),
+			   dma_unmap_len(tx_buffer, len),
+			   tx_buffer->next_to_watch,
+			   (u64)tx_buffer->time_stamp);
+	}
+
+	/* Print TX Rings */
+	if (!netif_msg_tx_done(adapter))
+		goto rx_ring_summary;
+
+	dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats
+	 *
+	 * Transmit Descriptor (Read)
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0]                                |
+	 *   +--------------------------------------------------------------+
+	 * 8 |PAYLEN  |POPTS|CC|IDX  |STA  |DCMD  |DTYP |MAC  |RSV  |DTALEN |
+	 *   +--------------------------------------------------------------+
+	 *   63     46 45 40 39 38 36 35 32 31  24 23 20 19 18 17 16 15     0
+	 *
+	 * Transmit Descriptor (Write-Back)
+	 *   +--------------------------------------------------------------+
+	 * 0 |                          RSV [63:0]                          |
+	 *   +--------------------------------------------------------------+
+	 * 8 |            RSV           |  STA  |           RSV             |
+	 *   +--------------------------------------------------------------+
+	 *   63                       36 35   32 31                         0
+	 */
+
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = adapter->tx_ring[n];
+		pr_info("------------------------------------\n");
+		pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+		pr_info("------------------------------------\n");
+		pr_info("%s%s    %s              %s        %s          %s\n",
+			"T [desc]     [address 63:0  ] ",
+			"[PlPOIdStDDt Ln] [bi->dma       ] ",
+			"leng", "ntw", "timestamp", "bi->skb");
+
+		for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+			tx_desc = TXGBE_TX_DESC(tx_ring, i);
+			tx_buffer = &tx_ring->tx_buffer_info[i];
+			u0 = (struct my_u0 *)tx_desc;
+			if (dma_unmap_len(tx_buffer, len) > 0) {
+				pr_info("T [0x%03X]    %016llX %016llX %016llX "
+					"%08X %p %016llX %p",
+					i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)dma_unmap_addr(tx_buffer, dma),
+					dma_unmap_len(tx_buffer, len),
+					tx_buffer->next_to_watch,
+					(u64)tx_buffer->time_stamp,
+					tx_buffer->skb);
+				if (i == tx_ring->next_to_use &&
+					i == tx_ring->next_to_clean)
+					pr_cont(" NTC/U\n");
+				else if (i == tx_ring->next_to_use)
+					pr_cont(" NTU\n");
+				else if (i == tx_ring->next_to_clean)
+					pr_cont(" NTC\n");
+				else
+					pr_cont("\n");
+
+				if (netif_msg_pktdata(adapter) &&
+				    tx_buffer->skb)
+					print_hex_dump(KERN_INFO, "",
+						DUMP_PREFIX_ADDRESS, 16, 1,
+						tx_buffer->skb->data,
+						dma_unmap_len(tx_buffer, len),
+						true);
+			}
+		}
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+	pr_info("Queue [NTU] [NTC]\n");
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		pr_info("%5d %5X %5X\n",
+			n, rx_ring->next_to_use, rx_ring->next_to_clean);
+	}
+
+	/* Print RX Rings */
+	if (!netif_msg_rx_status(adapter))
+		return;
+
+	dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+
+	/* Receive Descriptor Formats
+	 *
+	 * Receive Descriptor (Read)
+	 *    63                                           1        0
+	 *    +-----------------------------------------------------+
+	 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+	 *    +----------------------------------------------+------+
+	 *  8 |       Header Buffer Address [63:1]           |  DD  |
+	 *    +-----------------------------------------------------+
+	 *
+	 *
+	 * Receive Descriptor (Write-Back)
+	 *
+	 *   63       48 47    32 31  30      21 20 17 16   4 3     0
+	 *   +------------------------------------------------------+
+	 * 0 |RSS / Frag Checksum|SPH| HDR_LEN  |RSC- |Packet|  RSS |
+	 *   |/ RTT / PCoE_PARAM |   |          | CNT | Type | Type |
+	 *   |/ Flow Dir Flt ID  |   |          |     |      |      |
+	 *   +------------------------------------------------------+
+	 * 8 | VLAN Tag | Length |Extended Error| Xtnd Status/NEXTP |
+	 *   +------------------------------------------------------+
+	 *   63       48 47    32 31          20 19                 0
+	 */
+
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		pr_info("------------------------------------\n");
+		pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+		pr_info("------------------------------------\n");
+		pr_info("%s%s%s",
+			"R  [desc]      [ PktBuf     A0] ",
+			"[  HeadBuf   DD] [bi->dma       ] [bi->skb       ] ",
+			"<-- Adv Rx Read format\n");
+		pr_info("%s%s%s",
+			"RWB[desc]      [PcsmIpSHl PtRs] ",
+			"[vl er S cks ln] ---------------- [bi->skb       ] ",
+			"<-- Adv Rx Write-Back format\n");
+
+		for (i = 0; i < rx_ring->count; i++) {
+			rx_buffer_info = &rx_ring->rx_buffer_info[i];
+			rx_desc = TXGBE_RX_DESC(rx_ring, i);
+			u0 = (struct my_u0 *)rx_desc;
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			if (staterr & TXGBE_RXD_STAT_DD) {
+				/* Descriptor Done */
+				pr_info("RWB[0x%03X]     %016llX "
+					"%016llX ---------------- %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					rx_buffer_info->skb);
+			} else {
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+				pr_info("R  [0x%03X]     %016llX "
+					"%016llX %016llX %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)rx_buffer_info->page_dma,
+					rx_buffer_info->skb);
+
+				if (netif_msg_pktdata(adapter) &&
+				    rx_buffer_info->page_dma) {
+					print_hex_dump(KERN_INFO, "",
+					   DUMP_PREFIX_ADDRESS, 16, 1,
+					   page_address(rx_buffer_info->page) +
+						    rx_buffer_info->page_offset,
+					   txgbe_rx_bufsz(rx_ring), true);
+				}
+#endif
+			}
+
+			if (i == rx_ring->next_to_use)
+				pr_cont(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				pr_cont(" NTC\n");
+			else
+				pr_cont("\n");
+
+		}
+	}
+}
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
new file mode 100644
index 000000000000..c0724a124f76
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -0,0 +1,4817 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_ethtool.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+/* ethtool support for txgbe */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/firmware.h>
+#ifdef SIOCETHTOOL
+#include <asm/uaccess.h>
+
+#include "txgbe.h"
+#include "txgbe_hw.h"
+#if defined(ETHTOOL_GMODULEINFO)||defined(HAVE_ETHTOOL_SET_PHYS_ID)
+#include "txgbe_phy.h"
+#endif
+#ifdef HAVE_ETHTOOL_GET_TS_INFO
+#include <linux/net_tstamp.h>
+#endif
+
+#ifndef ETH_GSTRING_LEN
+#define ETH_GSTRING_LEN 32
+#endif
+
+#define TXGBE_ALL_RAR_ENTRIES 16
+
+#ifdef ETHTOOL_OPS_COMPAT
+#include "kcompat_ethtool.c"
+#endif
+
+#define ETHTOOL_LINK_MODE_SPEED_MASK	0xfffe903f
+
+#ifdef ETHTOOL_GSTATS
+struct txgbe_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define TXGBE_NETDEV_STAT(_net_stat) { \
+	.stat_string = #_net_stat, \
+	.sizeof_stat = sizeof_field(struct net_device_stats, _net_stat), \
+	.stat_offset = offsetof(struct net_device_stats, _net_stat) \
+}
+static const struct txgbe_stats txgbe_gstrings_net_stats[] = {
+	TXGBE_NETDEV_STAT(rx_packets),
+	TXGBE_NETDEV_STAT(tx_packets),
+	TXGBE_NETDEV_STAT(rx_bytes),
+	TXGBE_NETDEV_STAT(tx_bytes),
+	TXGBE_NETDEV_STAT(rx_errors),
+	TXGBE_NETDEV_STAT(tx_errors),
+	TXGBE_NETDEV_STAT(rx_dropped),
+	TXGBE_NETDEV_STAT(tx_dropped),
+	TXGBE_NETDEV_STAT(collisions),
+	TXGBE_NETDEV_STAT(rx_over_errors),
+	TXGBE_NETDEV_STAT(rx_crc_errors),
+	TXGBE_NETDEV_STAT(rx_frame_errors),
+	TXGBE_NETDEV_STAT(rx_fifo_errors),
+	TXGBE_NETDEV_STAT(rx_missed_errors),
+	TXGBE_NETDEV_STAT(tx_aborted_errors),
+	TXGBE_NETDEV_STAT(tx_carrier_errors),
+	TXGBE_NETDEV_STAT(tx_fifo_errors),
+	TXGBE_NETDEV_STAT(tx_heartbeat_errors),
+};
+
+#define TXGBE_STAT(_name, _stat) { \
+	.stat_string = _name, \
+	.sizeof_stat = sizeof_field(struct txgbe_adapter, _stat), \
+	.stat_offset = offsetof(struct txgbe_adapter, _stat) \
+}
+static struct txgbe_stats txgbe_gstrings_stats[] = {
+	TXGBE_STAT("rx_pkts_nic", stats.gprc),
+	TXGBE_STAT("tx_pkts_nic", stats.gptc),
+	TXGBE_STAT("rx_bytes_nic", stats.gorc),
+	TXGBE_STAT("tx_bytes_nic", stats.gotc),
+	TXGBE_STAT("lsc_int", lsc_int),
+	TXGBE_STAT("tx_busy", tx_busy),
+	TXGBE_STAT("non_eop_descs", non_eop_descs),
+	TXGBE_STAT("rx_broadcast", stats.bprc),
+	TXGBE_STAT("tx_broadcast", stats.bptc),
+	TXGBE_STAT("rx_multicast", stats.mprc),
+	TXGBE_STAT("tx_multicast", stats.mptc),
+	TXGBE_STAT("rx_no_buffer_count", stats.rnbc[0]),
+	TXGBE_STAT("tx_timeout_count", tx_timeout_count),
+	TXGBE_STAT("tx_restart_queue", restart_queue),
+	TXGBE_STAT("rx_long_length_count", stats.roc),
+	TXGBE_STAT("rx_short_length_count", stats.ruc),
+	TXGBE_STAT("tx_flow_control_xon", stats.lxontxc),
+	TXGBE_STAT("rx_flow_control_xon", stats.lxonrxc),
+	TXGBE_STAT("tx_flow_control_xoff", stats.lxofftxc),
+	TXGBE_STAT("rx_flow_control_xoff", stats.lxoffrxc),
+	TXGBE_STAT("rx_csum_offload_good_count", hw_csum_rx_good),
+	TXGBE_STAT("rx_csum_offload_errors", hw_csum_rx_error),
+	TXGBE_STAT("alloc_rx_page_failed", alloc_rx_page_failed),
+	TXGBE_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
+#ifndef TXGBE_NO_LRO
+	TXGBE_STAT("lro_aggregated", lro_stats.coal),
+	TXGBE_STAT("lro_flushed", lro_stats.flushed),
+#endif /* TXGBE_NO_LRO */
+	TXGBE_STAT("rx_no_dma_resources", hw_rx_no_dma_resources),
+	TXGBE_STAT("hw_rsc_aggregated", rsc_total_count),
+	TXGBE_STAT("hw_rsc_flushed", rsc_total_flush),
+#ifdef HAVE_TX_MQ
+	TXGBE_STAT("fdir_match", stats.fdirmatch),
+	TXGBE_STAT("fdir_miss", stats.fdirmiss),
+	TXGBE_STAT("fdir_overflow", fdir_overflow),
+#endif /* HAVE_TX_MQ */
+#if IS_ENABLED(CONFIG_FCOE)
+	TXGBE_STAT("fcoe_bad_fccrc", stats.fccrc),
+	TXGBE_STAT("fcoe_last_errors", stats.fclast),
+	TXGBE_STAT("rx_fcoe_dropped", stats.fcoerpdc),
+	TXGBE_STAT("rx_fcoe_packets", stats.fcoeprc),
+	TXGBE_STAT("rx_fcoe_dwords", stats.fcoedwrc),
+	TXGBE_STAT("fcoe_noddp", stats.fcoe_noddp),
+	TXGBE_STAT("fcoe_noddp_ext_buff", stats.fcoe_noddp_ext_buff),
+	TXGBE_STAT("tx_fcoe_packets", stats.fcoeptc),
+	TXGBE_STAT("tx_fcoe_dwords", stats.fcoedwtc),
+#endif /* CONFIG_FCOE */
+	TXGBE_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
+	TXGBE_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
+	TXGBE_STAT("os2bmc_tx_by_host", stats.o2bspc),
+	TXGBE_STAT("os2bmc_rx_by_host", stats.b2ogprc),
+#ifdef HAVE_PTP_1588_CLOCK
+	TXGBE_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+	TXGBE_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+#endif /* HAVE_PTP_1588_CLOCK */
+};
+
+/* txgbe allocates num_tx_queues and num_rx_queues symmetrically so
+ * we set the num_rx_queues to evaluate to num_tx_queues. This is
+ * used because we do not have a good way to get the max number of
+ * rx queues with CONFIG_RPS disabled.
+ */
+#ifdef HAVE_TX_MQ
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#define TXGBE_NUM_RX_QUEUES netdev->num_tx_queues
+#define TXGBE_NUM_TX_QUEUES netdev->num_tx_queues
+#else
+#define TXGBE_NUM_RX_QUEUES adapter->indices
+#define TXGBE_NUM_TX_QUEUES adapter->indices
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+#else /* HAVE_TX_MQ */
+#define TXGBE_NUM_RX_QUEUES 1
+#define TXGBE_NUM_TX_QUEUES ( \
+		((struct txgbe_adapter *)netdev_priv(netdev))->num_tx_queues)
+#endif /* HAVE_TX_MQ */
+
+#define TXGBE_QUEUE_STATS_LEN ( \
+		(TXGBE_NUM_TX_QUEUES + TXGBE_NUM_RX_QUEUES) * \
+		(sizeof(struct txgbe_queue_stats) / sizeof(u64)))
+#define TXGBE_GLOBAL_STATS_LEN  ARRAY_SIZE(txgbe_gstrings_stats)
+#define TXGBE_NETDEV_STATS_LEN  ARRAY_SIZE(txgbe_gstrings_net_stats)
+#define TXGBE_PB_STATS_LEN ( \
+		(sizeof(((struct txgbe_adapter *)0)->stats.pxonrxc) + \
+		 sizeof(((struct txgbe_adapter *)0)->stats.pxontxc) + \
+		 sizeof(((struct txgbe_adapter *)0)->stats.pxoffrxc) + \
+		 sizeof(((struct txgbe_adapter *)0)->stats.pxofftxc)) \
+		/ sizeof(u64))
+#define TXGBE_STATS_LEN (TXGBE_GLOBAL_STATS_LEN + \
+			 TXGBE_NETDEV_STATS_LEN + \
+			 TXGBE_PB_STATS_LEN + \
+			 TXGBE_QUEUE_STATS_LEN)
+
+#endif /* ETHTOOL_GSTATS */
+#ifdef ETHTOOL_TEST
+static const char txgbe_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Register test  (offline)", "Eeprom test    (offline)",
+	"Interrupt test (offline)", "Loopback test  (offline)",
+	"Link test   (on/offline)"
+};
+#define TXGBE_TEST_LEN  (sizeof(txgbe_gstrings_test) / ETH_GSTRING_LEN)
+#endif /* ETHTOOL_TEST */
+
+
+#ifdef HAVE_ETHTOOL_GET_SSET_COUNT
+struct txgbe_priv_flags {
+	char flag_string[ETH_GSTRING_LEN];
+	u64 flag;
+	bool read_only;
+};
+
+#define TXGBE_PRIV_FLAG(_name, _flag, _read_only) { \
+	.flag_string = _name, \
+	.flag = _flag, \
+	.read_only = _read_only, \
+}
+
+static const struct txgbe_priv_flags txgbe_gstrings_priv_flags[] = {
+	TXGBE_PRIV_FLAG("lldp", TXGBE_ETH_PRIV_FLAG_LLDP, 0),
+};
+
+#define TXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(txgbe_gstrings_priv_flags)
+
+#endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+
+/* currently supported speeds for 10G */
+#define ADVERTISED_MASK_10G (SUPPORTED_10000baseT_Full | \
+		SUPPORTED_10000baseKX4_Full | SUPPORTED_10000baseKR_Full)
+
+#define txgbe_isbackplane(type)  \
+			((type == txgbe_media_type_backplane) ? true : false)
+
+#ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
+static int txgbe_set_advertising_1g_10gtypes(struct txgbe_hw *hw,
+			struct ethtool_link_ksettings *cmd, u32 advertised_speed)
+{
+	switch (hw->phy.sfp_type) {
+	case txgbe_sfp_type_da_cu:
+	case txgbe_sfp_type_da_act_lmt_core0:
+	case txgbe_sfp_type_da_act_lmt_core1:
+	case txgbe_sfp_type_da_cu_core0:
+	case txgbe_sfp_type_da_cu_core1:
+	case txgbe_sfp_type_srlr_core0:
+	case txgbe_sfp_type_srlr_core1:
+		if (advertised_speed & TXGBE_LINK_SPEED_10GB_FULL) {
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseSR_Full);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising,
+						     10000baseLR_Full);
+		}
+		if (advertised_speed & TXGBE_LINK_SPEED_1GB_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+										 1000baseX_Full);
+		}
+		break;
+	case txgbe_sfp_type_sr:
+		if (advertised_speed & TXGBE_LINK_SPEED_10GB_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+								 10000baseSR_Full);
+		}
+		if (advertised_speed & TXGBE_LINK_SPEED_1GB_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+										 1000baseX_Full);
+		}
+		break;
+	case txgbe_sfp_type_lr:
+		if (advertised_speed & TXGBE_LINK_SPEED_10GB_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+								 10000baseLR_Full);
+		}
+		if (advertised_speed & TXGBE_LINK_SPEED_1GB_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+										 1000baseX_Full);
+		}
+		break;
+	case txgbe_sfp_type_1g_cu_core0:
+	case txgbe_sfp_type_1g_cu_core1:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 1000baseT_Full);
+		break;
+	case txgbe_sfp_type_1g_sx_core0:
+	case txgbe_sfp_type_1g_sx_core1:
+	case txgbe_sfp_type_1g_lx_core0:
+	case txgbe_sfp_type_1g_lx_core1:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 1000baseX_Full);
+		break;
+	default:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseT_Full);
+		break;
+	}
+
+	return 0;
+}
+			
+static int txgbe_set_supported_1g_10gtypes(struct txgbe_hw *hw,
+			struct ethtool_link_ksettings *cmd)
+{	
+	switch (hw->phy.sfp_type) {
+	case txgbe_sfp_type_da_cu:
+	case txgbe_sfp_type_da_act_lmt_core0:
+	case txgbe_sfp_type_da_act_lmt_core1:
+	case txgbe_sfp_type_da_cu_core0:
+	case txgbe_sfp_type_da_cu_core1:
+	case txgbe_sfp_type_srlr_core0:
+	case txgbe_sfp_type_srlr_core1:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 10000baseSR_Full);
+		ethtool_link_ksettings_add_link_mode(cmd, supported,
+						     10000baseLR_Full);
+		break;
+	case txgbe_sfp_type_sr:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 10000baseSR_Full);
+		break;
+	case txgbe_sfp_type_lr:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 10000baseLR_Full);
+		break;
+	case txgbe_sfp_type_1g_cu_core0:
+	case txgbe_sfp_type_1g_cu_core1:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 1000baseT_Full);
+		break;
+	case txgbe_sfp_type_1g_sx_core0:
+	case txgbe_sfp_type_1g_sx_core1:
+	case txgbe_sfp_type_1g_lx_core0:
+	case txgbe_sfp_type_1g_lx_core1:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 1000baseX_Full);
+		break;
+	default:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 10000baseT_Full);
+		break;
+	}
+
+	return 0;
+}
+
+int txgbe_get_link_ksettings(struct net_device *netdev,
+		    struct ethtool_link_ksettings *cmd)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 supported_link;
+	u32 link_speed = 0;
+	bool autoneg = false;
+	bool link_up;
+
+	ethtool_link_ksettings_zero_link_mode(cmd, supported);
+	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
+
+	TCALL(hw, mac.ops.get_link_capabilities, &supported_link, &autoneg);
+
+	if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4)
+		autoneg = adapter->backplane_an ? 1:0;
+	else if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII)
+		autoneg = adapter->an37?1:0;
+
+	
+	/* set the supported link speeds */
+	if (hw->phy.media_type == txgbe_media_type_copper) {
+		if (supported_link & TXGBE_LINK_SPEED_10GB_FULL) 
+			ethtool_link_ksettings_add_link_mode(cmd, supported, 
+								 10000baseT_Full);
+		if (supported_link & TXGBE_LINK_SPEED_1GB_FULL) 
+			ethtool_link_ksettings_add_link_mode(cmd, supported, 
+								1000baseT_Full);
+		if (supported_link & TXGBE_LINK_SPEED_100_FULL) 
+			ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 100baseT_Full);
+
+		if (supported_link & TXGBE_LINK_SPEED_10_FULL) 
+			ethtool_link_ksettings_add_link_mode(cmd, supported, 
+								 10baseT_Full);
+	}else if (hw->phy.media_type == txgbe_media_type_fiber) {
+		if ((supported_link & TXGBE_LINK_SPEED_10GB_FULL) ||
+			(supported_link & TXGBE_LINK_SPEED_1GB_FULL)) 
+			txgbe_set_supported_1g_10gtypes(hw, cmd);
+		if (hw->phy.multispeed_fiber)
+			ethtool_link_ksettings_add_link_mode(cmd, supported, 
+							 1000baseX_Full);
+	}else {
+		ethtool_link_ksettings_add_link_mode(cmd, supported,
+						     10000baseKR_Full);	
+		ethtool_link_ksettings_add_link_mode(cmd, supported,
+						     10000baseKX4_Full);
+	}
+	
+	/* set the advertised speeds */
+	if (hw->phy.autoneg_advertised) {
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10GB_FULL) {
+			if (hw->phy.media_type == txgbe_media_type_copper) {
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseT_Full);
+			}else if (hw->phy.media_type == txgbe_media_type_fiber) {
+				txgbe_set_advertising_1g_10gtypes(hw, cmd, 
+					         hw->phy.autoneg_advertised);
+			}else {
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseKR_Full);
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseKX4_Full);
+			}
+		}
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_1GB_FULL) {
+			if (hw->phy.media_type == txgbe_media_type_copper) {
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 1000baseT_Full);
+			}else if (hw->phy.media_type == txgbe_media_type_fiber) {
+				txgbe_set_advertising_1g_10gtypes(hw, cmd, 
+							 hw->phy.autoneg_advertised);
+			}else {
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 1000baseKX_Full);
+			}
+		}
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_100_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 100baseT_Full);
+		}
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10_FULL) {
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10baseT_Full);
+		}			
+	} else {
+		if (hw->phy.multispeed_fiber && !autoneg) {
+			if (supported_link & TXGBE_LINK_SPEED_10GB_FULL)
+				ethtool_link_ksettings_add_link_mode(cmd, advertising, 
+							 10000baseT_Full);
+		}
+	}
+
+	if (autoneg) {
+		ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+		cmd->base.autoneg = AUTONEG_ENABLE;
+	} else
+		cmd->base.autoneg = AUTONEG_DISABLE;
+
+
+	/* Determine the remaining settings based on the PHY type. */
+	switch (adapter->hw.phy.type) {
+	case txgbe_phy_tn:
+	case txgbe_phy_aq:
+	case txgbe_phy_cu_unknown:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
+		cmd->base.port = PORT_TP;
+		break;
+	case txgbe_phy_qt:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+		cmd->base.port = PORT_FIBRE;
+		break;
+	case txgbe_phy_nl:
+	case txgbe_phy_sfp_passive_tyco:
+	case txgbe_phy_sfp_passive_unknown:
+	case txgbe_phy_sfp_ftl:
+	case txgbe_phy_sfp_avago:
+	case txgbe_phy_sfp_intel:
+	case txgbe_phy_sfp_unknown:
+		switch (adapter->hw.phy.sfp_type) {
+			/* SFP+ devices, further checking needed */
+		case txgbe_sfp_type_da_cu:
+		case txgbe_sfp_type_da_cu_core0:
+		case txgbe_sfp_type_da_cu_core1:
+			ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+			cmd->base.port = PORT_DA;
+			break;
+		case txgbe_sfp_type_sr:
+		case txgbe_sfp_type_lr:
+		case txgbe_sfp_type_srlr_core0:
+		case txgbe_sfp_type_srlr_core1:
+		case txgbe_sfp_type_1g_sx_core0:
+		case txgbe_sfp_type_1g_sx_core1:
+		case txgbe_sfp_type_1g_lx_core0:
+		case txgbe_sfp_type_1g_lx_core1:
+			ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+			cmd->base.port = PORT_FIBRE;
+			break;
+		case txgbe_sfp_type_not_present:
+			ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+			cmd->base.port = PORT_NONE;
+			break;
+		case txgbe_sfp_type_1g_cu_core0:
+		case txgbe_sfp_type_1g_cu_core1:
+			ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
+			cmd->base.port = PORT_TP;
+			break;
+		case txgbe_sfp_type_unknown:
+		default:
+			ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+			ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+			cmd->base.port = PORT_OTHER;
+			break;
+		}
+		break;
+	case txgbe_phy_xaui:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
+		cmd->base.port = PORT_TP;
+		break;
+	case txgbe_phy_unknown:
+	case txgbe_phy_generic:
+	case txgbe_phy_sfp_unsupported:
+	default:
+		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
+		cmd->base.port = PORT_OTHER;
+		break;
+	}
+
+	if (!in_interrupt()) {
+		TCALL(hw, mac.ops.check_link, &link_speed, &link_up, false);
+	} else {
+		/*
+		 * this case is a special workaround for RHEL5 bonding
+		 * that calls this routine from interrupt context
+		 */
+		link_speed = adapter->link_speed;
+		link_up = adapter->link_up;
+	}
+
+	/* Indicate pause support */
+	ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
+	
+	switch (hw->fc.requested_mode) {
+	case txgbe_fc_full:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
+		break;
+	case txgbe_fc_rx_pause:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
+		ethtool_link_ksettings_add_link_mode(cmd, advertising,
+						     Asym_Pause);
+		break;
+	case txgbe_fc_tx_pause:
+		ethtool_link_ksettings_add_link_mode(cmd, advertising,
+						     Asym_Pause);
+		break;
+	default:
+		ethtool_link_ksettings_del_link_mode(cmd, advertising, Pause);
+		ethtool_link_ksettings_del_link_mode(cmd, advertising,
+						     Asym_Pause);
+	}
+
+	if (link_up) {
+		switch (link_speed) {
+		case TXGBE_LINK_SPEED_10GB_FULL:
+			cmd->base.speed = SPEED_10000;
+			break;
+		case TXGBE_LINK_SPEED_1GB_FULL:
+			cmd->base.speed = SPEED_1000;
+			break;
+		case TXGBE_LINK_SPEED_100_FULL:
+			cmd->base.speed = SPEED_100;
+			break;
+		case TXGBE_LINK_SPEED_10_FULL:
+			cmd->base.speed = SPEED_10;
+			break;
+		default:
+			break;
+		}
+		cmd->base.duplex = DUPLEX_FULL;
+	} else {
+		cmd->base.speed = -1;
+		cmd->base.duplex = -1;
+	}
+	if(!(ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					10000baseT_Full) ||
+	ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					10000baseKR_Full)||
+	ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					10000baseKX4_Full)||
+	ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					10000baseLR_Full))&&
+	(ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					1000baseT_Full) ||
+	ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					1000baseKX_Full)||
+	ethtool_link_ksettings_test_link_mode(cmd, advertising, 
+					1000baseX_Full))
+	){
+		if(!adapter->an37)
+			ethtool_link_ksettings_del_link_mode(cmd, advertising, Autoneg);
+		else ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
+		cmd->base.autoneg = adapter->an37;
+		}
+	return 0;
+}
+#else /* !HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE */
+static __u32 txgbe_backplane_type(struct txgbe_hw *hw)
+{
+	__u32 mode = 0x00;
+	switch (hw->phy.link_mode) {
+	case TXGBE_PHYSICAL_LAYER_10GBASE_KX4:
+		mode = SUPPORTED_10000baseKX4_Full;
+		break;
+	case TXGBE_PHYSICAL_LAYER_10GBASE_KR:
+		mode = SUPPORTED_10000baseKR_Full;
+		break;
+	case TXGBE_PHYSICAL_LAYER_1000BASE_KX:
+		mode = SUPPORTED_1000baseKX_Full;
+		break;
+	default:
+		mode = (SUPPORTED_10000baseKX4_Full |
+			SUPPORTED_10000baseKR_Full |
+			SUPPORTED_1000baseKX_Full);
+		break;
+	}
+	return mode;
+}
+	
+int txgbe_get_settings(struct net_device *netdev,
+		       struct ethtool_cmd *ecmd)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 supported_link;
+	u32 link_speed = 0;
+	bool autoneg = false;
+	bool link_up;
+
+	TCALL(hw, mac.ops.get_link_capabilities, &supported_link, &autoneg);
+
+	if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4)
+		autoneg = adapter->backplane_an ? 1:0;
+	else if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII)
+		autoneg = adapter->an37?1:0;
+
+	/* set the supported link speeds */
+	if (supported_link & TXGBE_LINK_SPEED_10GB_FULL)
+		ecmd->supported |= (txgbe_isbackplane(hw->phy.media_type)) ?
+			txgbe_backplane_type(hw) : SUPPORTED_10000baseT_Full;
+	if (supported_link & TXGBE_LINK_SPEED_1GB_FULL)
+		ecmd->supported |= (txgbe_isbackplane(hw->phy.media_type)) ?
+			SUPPORTED_1000baseKX_Full : SUPPORTED_1000baseT_Full;
+	if (supported_link & TXGBE_LINK_SPEED_100_FULL)
+		ecmd->supported |= SUPPORTED_100baseT_Full;
+	if (supported_link & TXGBE_LINK_SPEED_10_FULL)
+		ecmd->supported |= SUPPORTED_10baseT_Full;
+
+	/* default advertised speed if phy.autoneg_advertised isn't set */
+	ecmd->advertising = ecmd->supported;
+
+	/* set the advertised speeds */
+	if (hw->phy.autoneg_advertised) {
+		ecmd->advertising = 0;
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_100_FULL)
+			ecmd->advertising |= ADVERTISED_100baseT_Full;
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10GB_FULL)
+			ecmd->advertising |= (ecmd->supported & ADVERTISED_MASK_10G);
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_1GB_FULL) {
+			if (ecmd->supported & SUPPORTED_1000baseKX_Full)
+				ecmd->advertising |= ADVERTISED_1000baseKX_Full;
+			else
+				ecmd->advertising |= ADVERTISED_1000baseT_Full;
+		}
+		if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10_FULL)
+			ecmd->advertising |= ADVERTISED_10baseT_Full;
+	} else {
+		/* default modes in case phy.autoneg_advertised isn't set */
+		if (supported_link & TXGBE_LINK_SPEED_10GB_FULL)
+			ecmd->advertising |= ADVERTISED_10000baseT_Full;
+		if (supported_link & TXGBE_LINK_SPEED_1GB_FULL)
+			ecmd->advertising |= ADVERTISED_1000baseT_Full;
+		if (supported_link & TXGBE_LINK_SPEED_100_FULL)
+			ecmd->advertising |= ADVERTISED_100baseT_Full;
+		if (hw->phy.multispeed_fiber && !autoneg) {
+			if (supported_link & TXGBE_LINK_SPEED_10GB_FULL)
+				ecmd->advertising = ADVERTISED_10000baseT_Full;
+		}
+		if (supported_link & TXGBE_LINK_SPEED_10_FULL)
+			ecmd->advertising |= ADVERTISED_10baseT_Full;
+	}
+
+	if (autoneg) {
+		ecmd->supported |= SUPPORTED_Autoneg;
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+	} else
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	/* Determine the remaining settings based on the PHY type. */
+	switch (adapter->hw.phy.type) {
+	case txgbe_phy_tn:
+	case txgbe_phy_aq:
+	case txgbe_phy_cu_unknown:
+		ecmd->supported |= SUPPORTED_TP;
+		ecmd->advertising |= ADVERTISED_TP;
+		ecmd->port = PORT_TP;
+		break;
+	case txgbe_phy_qt:
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
+		ecmd->port = PORT_FIBRE;
+		break;
+	case txgbe_phy_nl:
+	case txgbe_phy_sfp_passive_tyco:
+	case txgbe_phy_sfp_passive_unknown:
+	case txgbe_phy_sfp_ftl:
+	case txgbe_phy_sfp_avago:
+	case txgbe_phy_sfp_intel:
+	case txgbe_phy_sfp_unknown:
+		switch (adapter->hw.phy.sfp_type) {
+			/* SFP+ devices, further checking needed */
+		case txgbe_sfp_type_da_cu:
+		case txgbe_sfp_type_da_cu_core0:
+		case txgbe_sfp_type_da_cu_core1:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
+			ecmd->port = PORT_DA;
+			break;
+		case txgbe_sfp_type_sr:
+		case txgbe_sfp_type_lr:
+		case txgbe_sfp_type_srlr_core0:
+		case txgbe_sfp_type_srlr_core1:
+		case txgbe_sfp_type_1g_sx_core0:
+		case txgbe_sfp_type_1g_sx_core1:
+		case txgbe_sfp_type_1g_lx_core0:
+		case txgbe_sfp_type_1g_lx_core1:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
+			ecmd->port = PORT_FIBRE;
+			break;
+		case txgbe_sfp_type_not_present:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
+			ecmd->port = PORT_NONE;
+			break;
+		case txgbe_sfp_type_1g_cu_core0:
+		case txgbe_sfp_type_1g_cu_core1:
+			ecmd->supported |= SUPPORTED_TP;
+			ecmd->advertising |= ADVERTISED_TP;
+			ecmd->port = PORT_TP;
+			break;
+		case txgbe_sfp_type_unknown:
+		default:
+			ecmd->supported |= SUPPORTED_FIBRE;
+			ecmd->advertising |= ADVERTISED_FIBRE;
+			ecmd->port = PORT_OTHER;
+			break;
+		}
+		break;
+	case txgbe_phy_xaui:
+		ecmd->supported |= SUPPORTED_TP;
+		ecmd->advertising |= ADVERTISED_TP;
+		ecmd->port = PORT_TP;
+		break;
+	case txgbe_phy_unknown:
+	case txgbe_phy_generic:
+	case txgbe_phy_sfp_unsupported:
+	default:
+		ecmd->supported |= SUPPORTED_FIBRE;
+		ecmd->advertising |= ADVERTISED_FIBRE;
+		ecmd->port = PORT_OTHER;
+		break;
+	}
+
+	if (!in_interrupt()) {
+		TCALL(hw, mac.ops.check_link, &link_speed, &link_up, false);
+	} else {
+		/*
+		 * this case is a special workaround for RHEL5 bonding
+		 * that calls this routine from interrupt context
+		 */
+		link_speed = adapter->link_speed;
+		link_up = adapter->link_up;
+	}
+
+	ecmd->supported |= SUPPORTED_Pause;
+
+	switch (hw->fc.requested_mode) {
+	case txgbe_fc_full:
+		ecmd->advertising |= ADVERTISED_Pause;
+		break;
+	case txgbe_fc_rx_pause:
+		ecmd->advertising |= ADVERTISED_Pause |
+				     ADVERTISED_Asym_Pause;
+		break;
+	case txgbe_fc_tx_pause:
+		ecmd->advertising |= ADVERTISED_Asym_Pause;
+		break;
+	default:
+		ecmd->advertising &= ~(ADVERTISED_Pause |
+				       ADVERTISED_Asym_Pause);
+	}
+
+	if (link_up) {
+		switch (link_speed) {
+		case TXGBE_LINK_SPEED_10GB_FULL:
+			ecmd->speed = SPEED_10000;
+			break;
+		case TXGBE_LINK_SPEED_1GB_FULL:
+			ecmd->speed = SPEED_1000;
+			break;
+		case TXGBE_LINK_SPEED_100_FULL:
+			ecmd->speed = SPEED_100;
+			break;
+		case TXGBE_LINK_SPEED_10_FULL:
+			ecmd->speed = SPEED_10;
+			break;
+		default:
+			break;
+		}
+		ecmd->duplex = DUPLEX_FULL;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+	if((ecmd->advertising & ETHTOOL_LINK_MODE_SPEED_MASK) == ADVERTISED_1000baseT_Full ||
+		(ecmd->advertising & ETHTOOL_LINK_MODE_SPEED_MASK) == ADVERTISED_1000baseKX_Full){
+			if(!adapter->an37)
+				ecmd->advertising &= ~ADVERTISED_Autoneg;
+			}
+	ecmd->autoneg = adapter->an37?AUTONEG_ENABLE:AUTONEG_DISABLE;
+	return 0;
+}
+#endif /* !HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE */
+
+#ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
+static int txgbe_set_link_ksettings(struct net_device *netdev,
+				const struct ethtool_link_ksettings *cmd)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 advertised, old;
+	s32 err = 0;
+	struct ethtool_link_ksettings temp_ks;
+	u32 curr_autoneg = 2;
+	
+	if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4) {
+		adapter->backplane_an = cmd->base.autoneg?1:0;
+	}
+
+	if ((hw->phy.media_type == txgbe_media_type_copper) ||
+	    (hw->phy.multispeed_fiber)) { 
+	    memcpy(&temp_ks, cmd, sizeof(struct ethtool_link_ksettings));
+		/* To be compatible with test cases */	
+		if (hw->phy.media_type == txgbe_media_type_fiber) {
+			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseT_Full)) {
+				ethtool_link_ksettings_add_link_mode(&temp_ks, supported, 
+								 10000baseT_Full);
+				ethtool_link_ksettings_del_link_mode(&temp_ks, supported, 
+								 10000baseSR_Full);
+				ethtool_link_ksettings_del_link_mode(&temp_ks, supported, 
+								 10000baseLR_Full);
+			}
+			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseT_Full)) {
+				ethtool_link_ksettings_add_link_mode(&temp_ks, supported, 
+								 1000baseT_Full);
+				ethtool_link_ksettings_del_link_mode(&temp_ks, supported, 
+								 1000baseX_Full);
+			}
+		}
+		
+		/*
+		 * this function does not support duplex forcing, but can
+		 * limit the advertising of the adapter to the specified speed
+		 */
+		if (!bitmap_subset(cmd->link_modes.advertising,
+			   temp_ks.link_modes.supported,
+			   __ETHTOOL_LINK_MODE_MASK_NBITS))
+			return -EINVAL;
+								 
+		/* only allow one speed at a time if no autoneg */
+		if (!cmd->base.autoneg && hw->phy.multispeed_fiber) {
+			if ((ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								  10000baseSR_Full) &&
+				ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								  1000baseX_Full)) |
+				(ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								  10000baseLR_Full) &&
+				ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								  1000baseX_Full)))
+				return -EINVAL;
+		}
+		old = hw->phy.autoneg_advertised;
+		advertised = 0;
+
+		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseSR_Full) || 
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseLR_Full) ||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseT_Full))
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+
+		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseX_Full) ||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseT_Full))
+			advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  100baseT_Full))
+			advertised |= TXGBE_LINK_SPEED_100_FULL;
+
+		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10baseT_Full))
+			advertised |= TXGBE_LINK_SPEED_10_FULL;			
+
+		if(((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII) ||
+			((advertised == TXGBE_LINK_SPEED_1GB_FULL) &&
+			hw->phy.multispeed_fiber)){
+			adapter->an37 = cmd->base.autoneg?1:0;
+		}
+		if (advertised == TXGBE_LINK_SPEED_1GB_FULL){
+		curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+		curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+		}
+		if (old == advertised && (curr_autoneg == adapter->an37))
+			return err;
+		/* this sets the link speed and restarts auto-neg */
+		while (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+			usleep_range(1000, 2000);
+
+		hw->mac.autotry_restart = true;
+		err = TCALL(hw, mac.ops.setup_link, advertised, true);
+		if (err) {
+			e_info(probe, "setup link failed with code %d\n", err);
+			TCALL(hw, mac.ops.setup_link, old, true);
+		}
+		if ((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)
+				TCALL(hw, mac.ops.flap_tx_laser);
+		clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+	} else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4 ||
+			(hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII) {
+		if (!cmd->base.autoneg) {
+			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseKR_Full) | 
+				ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseKX_Full) |
+				ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseKX4_Full))
+				return -EINVAL;
+		} else {
+			err = txgbe_set_link_to_kr(hw, 1);
+			return err;
+		}
+		advertised = 0;
+		if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseKR_Full)) {
+			err = txgbe_set_link_to_kr(hw, 1);
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+			return err;
+		} else if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseKX4_Full)) {
+			err = txgbe_set_link_to_kx4(hw, 1);
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+			return err;
+		} else if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseKX_Full)) {
+			advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+			err = txgbe_set_link_to_kx(hw, TXGBE_LINK_SPEED_1GB_FULL, 0);
+			return err;
+		}
+		return err;
+	}else {
+		/* in this case we currently only support 10Gb/FULL */
+		u32 speed = cmd->base.speed;
+		if((ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					10000baseT_Full) ||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							10000baseKR_Full)||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							10000baseKX4_Full)||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							10000baseLR_Full))){
+		if ((cmd->base.autoneg == AUTONEG_ENABLE) ||
+		    (!ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  10000baseT_Full)) ||
+		    (speed + cmd->base.duplex != SPEED_10000 + DUPLEX_FULL))
+			return -EINVAL;}
+		else if((ethtool_link_ksettings_test_link_mode(cmd, advertising,
+					1000baseT_Full) ||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							1000baseKX_Full)||
+			ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							1000baseX_Full))){
+			memcpy(&temp_ks, cmd, sizeof(struct ethtool_link_ksettings));
+
+			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+							  1000baseT_Full)) {
+				ethtool_link_ksettings_add_link_mode(&temp_ks, supported,
+								 1000baseT_Full);
+				ethtool_link_ksettings_del_link_mode(&temp_ks, supported,
+								 1000baseX_Full);
+			}
+
+			if (!bitmap_subset(cmd->link_modes.advertising,
+			   temp_ks.link_modes.supported,
+			   __ETHTOOL_LINK_MODE_MASK_NBITS))
+			return -EINVAL;
+
+			old = hw->phy.autoneg_advertised;
+			advertised = 0;
+
+			if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								1000baseX_Full) ||
+				ethtool_link_ksettings_test_link_mode(cmd, advertising,
+								1000baseT_Full))
+				advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+			adapter->an37 = cmd->base.autoneg?1:0;
+
+			if (advertised == TXGBE_LINK_SPEED_1GB_FULL){
+			curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+			curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+			}
+			if (old == advertised && (curr_autoneg == adapter->an37))
+				return err;
+			/* this sets the link speed and restarts auto-neg */
+			while (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+				usleep_range(1000, 2000);
+
+			hw->mac.autotry_restart = true;
+			err = TCALL(hw, mac.ops.setup_link, advertised, true);
+			if (err) {
+				e_info(probe, "setup link failed with code %d\n", err);
+				TCALL(hw, mac.ops.setup_link, old, true);
+			}
+			if ((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)
+					TCALL(hw, mac.ops.flap_tx_laser);
+			clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+	}
+	}
+	return err;
+}
+#else /* !HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE */
+static int txgbe_set_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 advertised, old;
+	u32 curr_autoneg = 2;
+	s32 err = 0;
+
+	if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4) {
+		adapter->backplane_an = ecmd->autoneg?1:0;
+	}
+
+	if ((hw->phy.media_type == txgbe_media_type_copper) ||
+	    (hw->phy.multispeed_fiber)) {
+		/*
+		 * this function does not support duplex forcing, but can
+		 * limit the advertising of the adapter to the specified speed
+		 */
+		if (ecmd->advertising & ~ecmd->supported)
+			return -EINVAL;
+
+		/* only allow one speed at a time if no autoneg */
+		if (!ecmd->autoneg && hw->phy.multispeed_fiber) {
+			if (ecmd->advertising ==
+			    (ADVERTISED_10000baseT_Full |
+			     ADVERTISED_1000baseT_Full))
+				return -EINVAL;
+		}
+
+		old = hw->phy.autoneg_advertised;
+		advertised = 0;
+		if (ecmd->advertising & ADVERTISED_10000baseT_Full)
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+
+		if (ecmd->advertising & ADVERTISED_1000baseT_Full)
+			advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+		if (ecmd->advertising & ADVERTISED_100baseT_Full)
+			advertised |= TXGBE_LINK_SPEED_100_FULL;
+
+		if (ecmd->advertising & ADVERTISED_10baseT_Full)
+			advertised |= TXGBE_LINK_SPEED_10_FULL;
+		
+		if(((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII) ||
+			((advertised == TXGBE_LINK_SPEED_1GB_FULL) &&
+			hw->phy.multispeed_fiber)){
+				adapter->an37 = ecmd->autoneg?1:0;
+		}
+
+		if (advertised == TXGBE_LINK_SPEED_1GB_FULL){
+		curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+		curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+		}
+		if (old == advertised && (curr_autoneg == adapter->an37))
+			return err;
+		/* this sets the link speed and restarts auto-neg */
+		while (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+			usleep_range(1000, 2000);
+
+		hw->mac.autotry_restart = true;
+		err = TCALL(hw, mac.ops.setup_link, advertised, true);
+		if (err) {
+			e_info(probe, "setup link failed with code %d\n", err);
+			TCALL(hw, mac.ops.setup_link, old, true);
+		}
+		if ((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)
+				TCALL(hw, mac.ops.flap_tx_laser);
+		clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+	} else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4 ||
+			(hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII) {
+		if (!ecmd->autoneg ) {
+			if (ecmd->advertising ==
+			    (ADVERTISED_10000baseKR_Full |
+			     ADVERTISED_1000baseKX_Full |
+			     ADVERTISED_10000baseKX4_Full))
+				return -EINVAL;
+		} else {
+			err = txgbe_set_link_to_kr(hw, 1);
+			return err;
+		}
+		advertised = 0;
+		if (ecmd->advertising & ADVERTISED_10000baseKR_Full){
+			err = txgbe_set_link_to_kr(hw, 1);
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+			return err;
+		} else if (ecmd->advertising & ADVERTISED_10000baseKX4_Full){
+			err = txgbe_set_link_to_kx4(hw, 1);
+			advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+			return err;
+		} else if (ecmd->advertising & ADVERTISED_1000baseKX_Full){
+			advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+			err = txgbe_set_link_to_kx(hw, TXGBE_LINK_SPEED_1GB_FULL, 0);
+			return err;
+		}
+		return err;
+	} else {
+		/* in this case we currently only support 10Gb/FULL and 1Gb/FULL*/
+		u32 speed = ethtool_cmd_speed(ecmd);
+		if(ecmd->advertising & ADVERTISED_10000baseT_Full){
+		if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+		    (ecmd->advertising != ADVERTISED_10000baseT_Full) ||
+		    (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+			return -EINVAL;
+		}
+		else if (ecmd->advertising & ADVERTISED_1000baseT_Full){
+		if (ecmd->advertising & ~ecmd->supported)
+			return -EINVAL;
+
+		old = hw->phy.autoneg_advertised;
+		advertised = 0;
+
+		if (ecmd->advertising & ADVERTISED_1000baseT_Full)
+			advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+		adapter->an37 = ecmd->autoneg?1:0;
+		if (advertised == TXGBE_LINK_SPEED_1GB_FULL){
+		curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+		curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+		}
+		if (old == advertised && (curr_autoneg == adapter->an37))
+			return err;
+		/* this sets the link speed and restarts auto-neg */
+		while (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+			usleep_range(1000, 2000);
+
+		hw->mac.autotry_restart = true;
+		err = TCALL(hw, mac.ops.setup_link, advertised, true);
+		if (err) {
+			e_info(probe, "setup link failed with code %d\n", err);
+			TCALL(hw, mac.ops.setup_link, old, true);
+		}
+		if ((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)
+				TCALL(hw, mac.ops.flap_tx_laser);
+		clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+		}
+	}
+
+	return err;
+}
+#endif /* !HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE */
+
+static void txgbe_get_pauseparam(struct net_device *netdev,
+				 struct ethtool_pauseparam *pause)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (txgbe_device_supports_autoneg_fc(hw) &&
+	    !hw->fc.disable_fc_autoneg)
+		pause->autoneg = 1;
+	else
+		pause->autoneg = 0;
+
+	if (hw->fc.current_mode == txgbe_fc_rx_pause) {
+		pause->rx_pause = 1;
+	} else if (hw->fc.current_mode == txgbe_fc_tx_pause) {
+		pause->tx_pause = 1;
+	} else if (hw->fc.current_mode == txgbe_fc_full) {
+		pause->rx_pause = 1;
+		pause->tx_pause = 1;
+	}
+}
+
+static int txgbe_set_pauseparam(struct net_device *netdev,
+				struct ethtool_pauseparam *pause)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_fc_info fc = hw->fc;
+
+
+	/* some devices do not support autoneg of flow control */
+	if ((pause->autoneg == AUTONEG_ENABLE) &&
+	    !txgbe_device_supports_autoneg_fc(hw))
+	    return -EINVAL;
+
+	fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE);
+
+	if ((pause->rx_pause && pause->tx_pause) || pause->autoneg)
+		fc.requested_mode = txgbe_fc_full;
+	else if (pause->rx_pause)
+		fc.requested_mode = txgbe_fc_rx_pause;
+	else if (pause->tx_pause)
+		fc.requested_mode = txgbe_fc_tx_pause;
+	else
+		fc.requested_mode = txgbe_fc_none;
+
+	/* if the thing changed then we'll update and use new autoneg */
+	if (memcmp(&fc, &hw->fc, sizeof(struct txgbe_fc_info))) {
+		hw->fc = fc;
+		if (netif_running(netdev))
+			txgbe_reinit_locked(adapter);
+		else
+			txgbe_reset(adapter);
+	}
+
+	return 0;
+}
+
+static u32 txgbe_get_msglevel(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void txgbe_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	adapter->msg_enable = data;
+}
+
+static int txgbe_get_regs_len(struct net_device __always_unused *netdev)
+{
+#define TXGBE_REGS_LEN  4096
+	return TXGBE_REGS_LEN * sizeof(u32);
+}
+
+#define TXGBE_GET_STAT(_A_, _R_)        (_A_->stats._R_)
+
+
+static void txgbe_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
+			   void *p)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u32 i;
+	u32 id = 0;
+
+	memset(p, 0, TXGBE_REGS_LEN * sizeof(u32));
+	regs_buff[TXGBE_REGS_LEN - 1] = 0x55555555;
+
+	regs->version = hw->revision_id << 16 |
+			hw->device_id;
+
+	/* Global Registers */
+	/* chip control */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_PWR);//0
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_CTL);//1
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_PF_SM);//2
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_RST);//3
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_ST);//4
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_SWSM);//5
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_MIS_RST_ST);//6
+	/* pvt sensor */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_CTL);//7
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_EN);//8
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_ST);//9
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_ALARM_THRE);//10
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_DALARM_THRE);//11
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_INT_EN);//12
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TS_ALARM_ST);//13
+	/* Fmgr Register */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_CMD);//14
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_DATA);//15
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_STATUS);//16
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_USR_CMD);//17
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_CMDCFG0);//18
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_CMDCFG1);//19
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_ILDR_STATUS);//20
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_SPI_ILDR_SWPTR);//21
+
+	/* Port Registers */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_PORT_CTL);//22
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_PORT_ST);//23
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_EX_VTYPE);//24
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_VXLAN);//25
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_VXLAN_GPE);//26
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_GENEVE);//27
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TEREDO);//28
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TCP_TIME);//29
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_LED_CTL);//30
+	/* GPIO */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_DR);//31
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_DDR);//32
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_CTL);//33
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_INTEN);//34
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_INTMASK);//35
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_GPIO_INTSTATUS);//36
+	/* I2C */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CON);//37
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_TAR);//38
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_DATA_CMD);//39
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SS_SCL_HCNT);//40
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SS_SCL_LCNT);//41
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_FS_SCL_HCNT);//42
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_FS_SCL_LCNT);//43
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_HS_SCL_HCNT);//44
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_INTR_STAT);//45
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_INTR_MASK);//46
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_RAW_INTR_STAT);//47
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_RX_TL);//48
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_TX_TL);//49
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_INTR);//50
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_RX_UNDER);//51
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_RX_OVER);//52
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_TX_OVER);//53
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_RD_REQ);//54
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_TX_ABRT);//55
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_RX_DONE);//56
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_ACTIVITY);//57
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_STOP_DET);//58
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_START_DET);//59
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_GEN_CALL);//60
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_ENABLE);//61
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_STATUS);//62
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_TXFLR);//63
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_RXFLR);//64
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SDA_HOLD);//65
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_TX_ABRT_SOURCE);//66
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SDA_SETUP);//67
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_ENABLE_STATUS);//68
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_FS_SPKLEN);//69
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_HS_SPKLEN);//70
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SCL_STUCK_TIMEOUT);//71
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_SDA_STUCK_TIMEOUT);//72
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_CLR_SCL_STUCK_DET);//73
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_DEVICE_ID);//74
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_COMP_PARAM_1);//75
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_COMP_VERSION);//76
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_I2C_COMP_TYPE);//77
+	/* TX TPH */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TPH_TDESC);//78
+	/* RX TPH */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TPH_RDESC);//79
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TPH_RHDR);//80
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_CFG_TPH_RPL);//81
+
+	/* TDMA */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_CTL);//82
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VF_TE(0));//83
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VF_TE(1));//84
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_PB_THRE(i));//85-92
+	}
+	for (i = 0; i < 4; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_LLQ(i));//93-96
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_ETYPE_LB_L);//97
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_ETYPE_LB_H);//98
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_ETYPE_AS_L);//99
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_ETYPE_AS_H);//100
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_MAC_AS_L);//101
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_MAC_AS_H);//102
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VLAN_AS_L);//103
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VLAN_AS_H);//104
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_TCP_FLG_L);//105
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_TCP_FLG_H);//106
+	for (i = 0; i < 64; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VLAN_INS(i));//107-234
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_ETAG_INS(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_PBWARB_CTL);//235
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_MMW);//236
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_PBWARB_CFG(i));//237-244
+	}
+	for (i = 0; i < 128; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_VM_CREDIT(i));//245-372
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_FC_EOF);//373
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDM_FC_SOF);//374
+
+	/* RDMA */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_ARB_CTL);//375
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_VF_RE(0));//376
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_VF_RE(1));//377
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_RSC_CTL);//378
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_ARB_CFG(i));//379-386
+	}
+	for (i = 0; i < 4; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_PF_QDE(i));//387-394
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDM_PF_HIDE(i));
+	}
+
+	/* RDB */
+	/*flow control */
+	for (i = 0; i < 4; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RFCV(i));//395-398
+	}
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RFCL(i));//399-414
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RFCH(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RFCRT);//415
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RFCC);//416
+	/* receive packet buffer */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_PB_CTL);//417
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_PB_WRAP);//418
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_UP2TC);//419
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_PB_SZ(i));//420-435
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_MPCNT(i));
+	}
+	/* lli interrupt */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_LLI_THRE);//436
+	/* ring assignment */
+	for (i = 0; i < 64; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_PL_CFG(i));//437-500
+	}
+	for (i = 0; i < 32; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RSSTBL(i));//501-532
+	}
+	for (i = 0; i < 10; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RSSRK(i));//533-542
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RSS_TC);//543
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_RA_CTL);//544
+	for (i = 0; i < 128; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_5T_SA(i));//545-1184
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_5T_DA(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_5T_SDP(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_5T_CTL0(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_5T_CTL1(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_SYN_CLS);//1185
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_ETYPE_CLS(i));//1186-1193
+	}
+	/* fcoe redirection table */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FCRE_CTL);//1194
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FCRE_TBL(i));//1195-1202
+	}
+	/*flow director */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_CTL);//1203
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_HKEY);//1204
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_SKEY);//1205
+	for (i = 0; i < 16; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_FLEX_CFG(i));//1206-1221
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_FREE);//1222
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_LEN);//1223
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_USE_ST);//1224
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_FAIL_ST);//1225
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_MATCH);//1226
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_MISS);//1227
+	for (i = 0; i < 3; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_IP6(i));//1228-1230
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_SA);//1231
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_DA);//1232
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_PORT);//1233
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_FLEX);//1234
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_HASH);//1235
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_CMD);//1236
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_DA4_MSK);//1237
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_SA4_MSK);//1238
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_TCP_MSK);//1239
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_UDP_MSK);//1240
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_SCTP_MSK);//1241
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_IP6_MSK);//1242
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RDB_FDIR_OTHER_MSK);//1243
+
+	/* PSR */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_CTL);//1244
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_CTL);//1245
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VM_CTL);//1246
+	for (i = 0; i < 64; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VM_L2CTL(i));//1247-1310
+	}
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_ETYPE_SWC(i));//1311-1318
+	}
+	for (i = 0; i < 128; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MC_TBL(i));//1319-1702
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_UC_TBL(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_TBL(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MAC_SWC_AD_L);//1703
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MAC_SWC_AD_H);//1704
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MAC_SWC_VM_L);//1705
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MAC_SWC_VM_H);//1706
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MAC_SWC_IDX);//1707
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_SWC);//1708
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_SWC_VM_L);//1709
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_SWC_VM_H);//1710
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_VLAN_SWC_IDX);//1711
+	for (i = 0; i < 4; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MR_CTL(i));//1712-1731
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MR_VLAN_L(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MR_VLAN_H(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MR_VM_L(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_MR_VM_H(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_CTL);//1732
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_STMPL);//1733
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_STMPH);//1734
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_ATTRL);//1735
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_ATTRH);//1736
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_1588_MSGTYPE);//1737
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_WKUP_CTL);//1738
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_WKUP_IPV);//1739
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_LAN_FLEX_CTL);//1740
+	for (i = 0; i < 4; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_WKUP_IP4TBL(i));//1741-1748
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_WKUP_IP6TBL(i));
+	}
+	for (i = 0; i < 16; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_LAN_FLEX_DW_L(i));//1749-1796
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_LAN_FLEX_DW_H(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_LAN_FLEX_MSK(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PSR_LAN_FLEX_CTL);//1797
+
+	/* TDB */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_TFCS);//1798
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_PB_SZ(0));//1799
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_UP2TC);//1800
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_PBRARB_CTL);//1801
+	for (i = 0; i < 8; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_PBRARB_CFG(i));//1802-1809
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TDB_MNG_TC);//1810
+
+	/* tsec */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_CTL);//1811
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_ST);//1812
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_BUF_AF);//1813
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_BUF_AE);//1814
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_MIN_IFG);//1815
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_CTL);//1816
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_STMPL);//1817
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_STMPH);//1818
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_SYSTIML);//1819
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_SYSTIMH);//1820
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_INC);//1821
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_ADJL);//1822
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_TSC_1588_ADJH);//1823
+
+	/* RSEC */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RSC_CTL);//1824
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_RSC_ST);//1825
+
+	/* BAR register */
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_MISC_IC);//1826
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_MISC_ICS);//1827
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_MISC_IEN);//1828
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_GPIE);//1829
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IC(0));//1830
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IC(1));//1831
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ICS(0));//1832
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ICS(1));//1833
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IMS(0));//1834
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IMS(1));//1835
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IMC(0));//1836
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IMC(1));//1837
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ISB_ADDR_L);//1838
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ISB_ADDR_H);//1839
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ITRSEL);//1840
+	for (i = 0; i < 64; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_ITR(i));//1841-1968
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_IVAR(i));
+	}
+	regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_MISC_IVAR);//1969
+	for (i = 0; i < 128; i++) {
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_RR_BAL(i));//1970-3249
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_RR_BAH(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_RR_WP(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_RR_RP(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_RR_CFG(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_TR_BAL(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_TR_BAH(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_TR_WP(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_TR_RP(i));
+		regs_buff[id++] = TXGBE_R32_Q(hw, TXGBE_PX_TR_CFG(i));
+	}
+}
+
+static int txgbe_get_eeprom_len(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	return adapter->hw.eeprom.word_size * 2;
+}
+
+static int txgbe_get_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	int first_word, last_word, eeprom_len;
+	int ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_len = last_word - first_word + 1;
+
+	eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	ret_val = TCALL(hw, eeprom.ops.read_buffer, first_word, eeprom_len,
+					   eeprom_buff);
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < eeprom_len; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+}
+
+static int txgbe_set_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	void *ptr;
+	int max_len, first_word, last_word, ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+		return -EINVAL;
+
+	max_len = hw->eeprom.word_size * 2;
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	ptr = eeprom_buff;
+
+	if (eeprom->offset & 1) {
+		/*
+		 * need read/modify/write of first changed EEPROM word
+		 * only the second byte of the word is being modified
+		 */
+		ret_val = TCALL(hw, eeprom.ops.read, first_word,
+				&eeprom_buff[0]);
+		if (ret_val)
+			goto err;
+
+		ptr++;
+	}
+	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
+		/*
+		 * need read/modify/write of last changed EEPROM word
+		 * only the first byte of the word is being modified
+		 */
+		ret_val = TCALL(hw, eeprom.ops.read, last_word,
+				&eeprom_buff[last_word - first_word]);
+		if (ret_val)
+			goto err;
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(ptr, bytes, eeprom->len);
+
+	for (i = 0; i < last_word - first_word + 1; i++)
+		cpu_to_le16s(&eeprom_buff[i]);
+
+	ret_val = TCALL(hw, eeprom.ops.write_buffer, first_word,
+					    last_word - first_word + 1,
+					    eeprom_buff);
+
+	/* Update the checksum */
+	if (ret_val == 0)
+		TCALL(hw, eeprom.ops.update_checksum);
+
+err:
+	kfree(eeprom_buff);
+	return ret_val;
+}
+
+static void txgbe_get_drvinfo(struct net_device *netdev,
+			      struct ethtool_drvinfo *drvinfo)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	strncpy(drvinfo->driver, txgbe_driver_name,
+		sizeof(drvinfo->driver) - 1);
+	strncpy(drvinfo->version, txgbe_driver_version,
+		sizeof(drvinfo->version) - 1);
+	strncpy(drvinfo->fw_version, adapter->eeprom_id,
+		sizeof(drvinfo->fw_version));
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+		sizeof(drvinfo->bus_info) - 1);
+	if (adapter->num_tx_queues <= TXGBE_NUM_RX_QUEUES) {
+		drvinfo->n_stats = TXGBE_STATS_LEN -
+				   (TXGBE_NUM_RX_QUEUES - adapter->num_tx_queues)*
+					(sizeof(struct txgbe_queue_stats) / sizeof(u64))*2;
+	}else{
+		drvinfo->n_stats = TXGBE_STATS_LEN;
+	}
+	drvinfo->testinfo_len = TXGBE_TEST_LEN;
+	drvinfo->regdump_len = txgbe_get_regs_len(netdev);
+}
+
+static void txgbe_get_ringparam(struct net_device *netdev,
+#ifdef HAVE_ETHTOOL_EXTENDED_RINGPARAMS
+				struct ethtool_ringparam *ring,
+				struct kernel_ethtool_ringparam *ringp,
+				struct netlink_ext_ack *extack)
+#else
+				struct ethtool_ringparam *ring)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	ring->rx_max_pending = TXGBE_MAX_RXD;
+	ring->tx_max_pending = TXGBE_MAX_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = adapter->rx_ring_count;
+	ring->tx_pending = adapter->tx_ring_count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int txgbe_set_ringparam(struct net_device *netdev,
+#ifdef HAVE_ETHTOOL_EXTENDED_RINGPARAMS
+				struct ethtool_ringparam *ring,
+				struct kernel_ethtool_ringparam *ringp,
+				struct netlink_ext_ack *extack)
+#else
+				struct ethtool_ringparam *ring)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_ring *temp_ring;
+	int i, err = 0;
+	u32 new_rx_count, new_tx_count;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	new_tx_count = clamp_t(u32, ring->tx_pending,
+			       TXGBE_MIN_TXD, TXGBE_MAX_TXD);
+	new_tx_count = ALIGN(new_tx_count, TXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+	new_rx_count = clamp_t(u32, ring->rx_pending,
+			       TXGBE_MIN_RXD, TXGBE_MAX_RXD);
+	new_rx_count = ALIGN(new_rx_count, TXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+	if ((new_tx_count == adapter->tx_ring_count) &&
+	    (new_rx_count == adapter->rx_ring_count)) {
+		/* nothing to do */
+		return 0;
+	}
+
+	while (test_and_set_bit(__TXGBE_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
+
+	if (!netif_running(adapter->netdev)) {
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			adapter->tx_ring[i]->count = new_tx_count;
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			adapter->rx_ring[i]->count = new_rx_count;
+		adapter->tx_ring_count = new_tx_count;
+		adapter->rx_ring_count = new_rx_count;
+		goto clear_reset;
+	}
+
+	/* allocate temporary buffer to store rings in */
+	i = max_t(int, adapter->num_tx_queues, adapter->num_rx_queues);
+	temp_ring = vmalloc(i * sizeof(struct txgbe_ring));
+
+	if (!temp_ring) {
+		err = -ENOMEM;
+		goto clear_reset;
+	}
+
+	txgbe_down(adapter);
+
+	/*
+	 * Setup new Tx resources and free the old Tx resources in that order.
+	 * We can then assign the new resources to the rings via a memcpy.
+	 * The advantage to this approach is that we are guaranteed to still
+	 * have resources even in the case of an allocation failure.
+	 */
+	if (new_tx_count != adapter->tx_ring_count) {
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			memcpy(&temp_ring[i], adapter->tx_ring[i],
+			       sizeof(struct txgbe_ring));
+
+			temp_ring[i].count = new_tx_count;
+			err = txgbe_setup_tx_resources(&temp_ring[i]);
+			if (err) {
+				while (i) {
+					i--;
+					txgbe_free_tx_resources(&temp_ring[i]);
+				}
+				goto err_setup;
+			}
+		}
+
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			txgbe_free_tx_resources(adapter->tx_ring[i]);
+
+			memcpy(adapter->tx_ring[i], &temp_ring[i],
+			       sizeof(struct txgbe_ring));
+		}
+
+		adapter->tx_ring_count = new_tx_count;
+	}
+
+	/* Repeat the process for the Rx rings if needed */
+	if (new_rx_count != adapter->rx_ring_count) {
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			memcpy(&temp_ring[i], adapter->rx_ring[i],
+			       sizeof(struct txgbe_ring));
+
+			temp_ring[i].count = new_rx_count;
+			err = txgbe_setup_rx_resources(&temp_ring[i]);
+			if (err) {
+				while (i) {
+					i--;
+					txgbe_free_rx_resources(&temp_ring[i]);
+				}
+				goto err_setup;
+			}
+		}
+
+
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			txgbe_free_rx_resources(adapter->rx_ring[i]);
+
+			memcpy(adapter->rx_ring[i], &temp_ring[i],
+			       sizeof(struct txgbe_ring));
+		}
+
+		adapter->rx_ring_count = new_rx_count;
+	}
+
+err_setup:
+	txgbe_up(adapter);
+	vfree(temp_ring);
+clear_reset:
+	clear_bit(__TXGBE_RESETTING, &adapter->state);
+	return err;
+}
+
+#ifndef HAVE_ETHTOOL_GET_SSET_COUNT
+static int txgbe_get_stats_count(struct net_device *netdev)
+{
+	if (adapter->num_tx_queues <= TXGBE_NUM_RX_QUEUES) {
+		return  TXGBE_STATS_LEN - (TXGBE_NUM_RX_QUEUES - adapter->num_tx_queues)*
+					(sizeof(struct txgbe_queue_stats) / sizeof(u64))*2;
+	}else{
+		return TXGBE_STATS_LEN;
+	}
+
+}
+
+#else /* HAVE_ETHTOOL_GET_SSET_COUNT */
+static int txgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+#ifdef HAVE_TX_MQ
+#ifndef HAVE_NETDEV_SELECT_QUEUE
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#endif
+#endif
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	switch (sset) {
+	case ETH_SS_TEST:
+		return TXGBE_TEST_LEN;
+	case ETH_SS_STATS:
+		if (adapter->num_tx_queues <= TXGBE_NUM_RX_QUEUES) {
+			return  TXGBE_STATS_LEN - (TXGBE_NUM_RX_QUEUES - adapter->num_tx_queues)*
+					(sizeof(struct txgbe_queue_stats) / sizeof(u64))*2;
+		}else{
+			return TXGBE_STATS_LEN;
+		}
+	case ETH_SS_PRIV_FLAGS:
+		return TXGBE_PRIV_FLAGS_STR_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+#ifdef HAVE_ETHTOOL_GET_SSET_COUNT
+/**
+ * txgbe_get_priv_flags - report device private flags
+ * @dev: network interface device structure
+ *
+ * The get string set count and the string set should be matched for each
+ * flag returned.  Add new strings for each flag to the txgbe_gstrings_priv_flags
+ * array.
+ *
+ * Returns a u32 bitmap of flags.
+ **/
+static u32 txgbe_get_priv_flags(struct net_device *dev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i , ret_flags = 0;
+	if(txgbe_is_lldp(hw)) {
+		adapter->eth_priv_flags |= TXGBE_ETH_PRIV_FLAG_LLDP;
+}
+	else {
+		adapter->eth_priv_flags &= ~TXGBE_ETH_PRIV_FLAG_LLDP;
+}
+	for (i = 0; i < TXGBE_PRIV_FLAGS_STR_LEN; i++) {
+		const struct txgbe_priv_flags *priv_flags;
+
+		priv_flags = &txgbe_gstrings_priv_flags[i];
+
+		if (priv_flags->flag & adapter->eth_priv_flags)
+			ret_flags |= BIT(i);
+	}
+	return ret_flags;
+}
+
+/**
+ * txgbe_set_priv_flags - set private flags
+ * @dev: network interface device structure
+ * @flags: bit flags to be set
+ **/
+static int txgbe_set_priv_flags(struct net_device *dev, u32 flags)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	u32 orig_flags, new_flags, changed_flags;
+	bool reset_needed = 0;
+	u32 i;
+	s32 status = 0;
+
+	orig_flags = adapter->eth_priv_flags;
+	new_flags = orig_flags;
+
+	for (i = 0; i < TXGBE_PRIV_FLAGS_STR_LEN; i++) {
+		const struct txgbe_priv_flags *priv_flags;
+
+		priv_flags = &txgbe_gstrings_priv_flags[i];
+
+		if (flags & BIT(i))
+			new_flags |= priv_flags->flag;
+		else
+			new_flags &= ~(priv_flags->flag);
+
+		/* If this is a read-only flag, it can't be changed */
+		if (priv_flags->read_only &&
+		    ((orig_flags ^ new_flags) & ~BIT(i)))
+			return -EOPNOTSUPP;
+	}
+	
+	changed_flags = orig_flags ^ new_flags;
+
+	if(!changed_flags) return 0;
+
+	if (changed_flags & TXGBE_ETH_PRIV_FLAG_LLDP)
+		reset_needed = 1;
+
+	if (changed_flags & TXGBE_ETH_PRIV_FLAG_LLDP)
+		status = txgbe_hic_write_lldp(&adapter->hw, (u32)(new_flags & TXGBE_ETH_PRIV_FLAG_LLDP));
+
+	if(!status)
+		adapter->eth_priv_flags = new_flags;
+
+
+	return status;
+}
+
+#endif /*HAVE_ETHTOOL_GET_SSET_COUNT*/
+
+#endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+static void txgbe_get_ethtool_stats(struct net_device *netdev,
+				    struct ethtool_stats __always_unused *stats,
+				    u64 *data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#ifdef HAVE_NETDEV_STATS_IN_NETDEV
+	struct net_device_stats *net_stats = &netdev->stats;
+#else
+	struct net_device_stats *net_stats = &adapter->net_stats;
+#endif
+#ifdef HAVE_NDO_GET_STATS64
+	unsigned int start;
+#endif
+	struct txgbe_ring *ring;
+	int i, j;
+	char *p;
+
+	txgbe_update_stats(adapter);
+
+	for (i = 0; i < TXGBE_NETDEV_STATS_LEN; i++) {
+		p = (char *)net_stats + txgbe_gstrings_net_stats[i].stat_offset;
+		data[i] = (txgbe_gstrings_net_stats[i].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+	for (j = 0; j < TXGBE_GLOBAL_STATS_LEN; j++, i++) {
+		p = (char *)adapter + txgbe_gstrings_stats[j].stat_offset;
+		data[i] = (txgbe_gstrings_stats[j].sizeof_stat ==
+			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+	for (j = 0; j < adapter->num_tx_queues; j++) {
+		ring = adapter->tx_ring[j];
+		if (!ring) {
+			data[i++] = 0;
+			data[i++] = 0;
+#ifdef BP_EXTENDED_STATS
+			data[i++] = 0;
+			data[i++] = 0;
+			data[i++] = 0;
+#endif
+			continue;
+		}
+
+#ifdef HAVE_NDO_GET_STATS64
+		do {
+			start = u64_stats_fetch_begin_irq(&ring->syncp);
+#endif
+			data[i]   = ring->stats.packets;
+			data[i+1] = ring->stats.bytes;
+#ifdef HAVE_NDO_GET_STATS64
+		} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
+#endif
+		i += 2;
+#ifdef BP_EXTENDED_STATS
+		data[i] = ring->stats.yields;
+		data[i+1] = ring->stats.misses;
+		data[i+2] = ring->stats.cleaned;
+		i += 3;
+#endif
+	}
+	for (j = 0; j < adapter->num_rx_queues; j++) {
+		ring = adapter->rx_ring[j];
+		if (!ring) {
+			data[i++] = 0;
+			data[i++] = 0;
+#ifdef BP_EXTENDED_STATS
+			data[i++] = 0;
+			data[i++] = 0;
+			data[i++] = 0;
+#endif
+			continue;
+		}
+
+#ifdef HAVE_NDO_GET_STATS64
+		do {
+			start = u64_stats_fetch_begin_irq(&ring->syncp);
+#endif
+			data[i]   = ring->stats.packets;
+			data[i+1] = ring->stats.bytes;
+#ifdef HAVE_NDO_GET_STATS64
+		} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
+#endif
+		i += 2;
+#ifdef BP_EXTENDED_STATS
+		data[i] = ring->stats.yields;
+		data[i+1] = ring->stats.misses;
+		data[i+2] = ring->stats.cleaned;
+		i += 3;
+#endif
+	}
+	for (j = 0; j < TXGBE_MAX_PACKET_BUFFERS; j++) {
+		data[i++] = adapter->stats.pxontxc[j];
+		data[i++] = adapter->stats.pxofftxc[j];
+	}
+	for (j = 0; j < TXGBE_MAX_PACKET_BUFFERS; j++) {
+		data[i++] = adapter->stats.pxonrxc[j];
+		data[i++] = adapter->stats.pxoffrxc[j];
+	}
+}
+
+static void txgbe_get_priv_flag_strings(struct net_device *netdev, u8 *data)
+{
+	char *p = (char *)data;
+	unsigned int i;
+
+	for (i = 0; i < TXGBE_PRIV_FLAGS_STR_LEN; i++) {
+		snprintf(p, ETH_GSTRING_LEN, "%s",
+			txgbe_gstrings_priv_flags[i].flag_string);
+		p += ETH_GSTRING_LEN;
+	}
+}
+
+static void txgbe_get_strings(struct net_device *netdev, u32 stringset,
+			      u8 *data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	char *p = (char *)data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *txgbe_gstrings_test,
+		       TXGBE_TEST_LEN * ETH_GSTRING_LEN);
+		break;
+	case ETH_SS_STATS:
+		for (i = 0; i < TXGBE_NETDEV_STATS_LEN; i++) {
+			memcpy(p, txgbe_gstrings_net_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < TXGBE_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, txgbe_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			sprintf(p, "tx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+#ifdef BP_EXTENDED_STATS
+			sprintf(p, "tx_queue_%u_bp_napi_yield", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bp_misses", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bp_cleaned", i);
+			p += ETH_GSTRING_LEN;
+#endif /* BP_EXTENDED_STATS */
+		}
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			sprintf(p, "rx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+#ifdef BP_EXTENDED_STATS
+			sprintf(p, "rx_queue_%u_bp_poll_yield", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bp_misses", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bp_cleaned", i);
+			p += ETH_GSTRING_LEN;
+#endif /* BP_EXTENDED_STATS */
+		}
+		for (i = 0; i < TXGBE_MAX_PACKET_BUFFERS; i++) {
+			sprintf(p, "tx_pb_%u_pxon", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_pb_%u_pxoff", i);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < TXGBE_MAX_PACKET_BUFFERS; i++) {
+			sprintf(p, "rx_pb_%u_pxon", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_pb_%u_pxoff", i);
+			p += ETH_GSTRING_LEN;
+		}
+		/* BUG_ON(p - data != TXGBE_STATS_LEN * ETH_GSTRING_LEN); */
+		break;
+	case ETH_SS_PRIV_FLAGS:
+		txgbe_get_priv_flag_strings(netdev, data);
+		break;
+	}
+}
+
+static int txgbe_link_test(struct txgbe_adapter *adapter, u64 *data)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	bool link_up;
+	u32 link_speed = 0;
+
+	if (TXGBE_REMOVED(hw->hw_addr)) {
+		*data = 1;
+		return 1;
+	}
+	*data = 0;
+    TCALL(hw, mac.ops.check_link, &link_speed, &link_up, true);
+	if (link_up)
+		return *data;
+	else
+		*data = 1;
+	return *data;
+}
+
+/* ethtool register test data */
+struct txgbe_reg_test {
+	u32 reg;
+	u8  array_len;
+	u8  test_type;
+	u32 mask;
+	u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x40 bytes apart, or in contiguous tables.  We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST    1
+#define SET_READ_TEST   2
+#define WRITE_NO_TEST   3
+#define TABLE32_TEST    4
+#define TABLE64_TEST_LO 5
+#define TABLE64_TEST_HI 6
+
+/* default sapphire register test */
+static struct txgbe_reg_test reg_test_sapphire[] = {
+	{ TXGBE_RDB_RFCL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+	{ TXGBE_RDB_RFCH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+	{ TXGBE_PSR_VLAN_CTL, 1, PATTERN_TEST, 0x00000000, 0x00000000 },
+	{ TXGBE_PX_RR_BAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
+	{ TXGBE_PX_RR_BAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ TXGBE_PX_RR_CFG(0), 4, WRITE_NO_TEST, 0, TXGBE_PX_RR_CFG_RR_EN },
+	{ TXGBE_RDB_RFCH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+	{ TXGBE_RDB_RFCV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ TXGBE_PX_TR_BAL(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ TXGBE_PX_TR_BAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ TXGBE_RDB_PB_CTL, 1, SET_READ_TEST, 0x00000001, 0x00000001 },
+	{ TXGBE_PSR_MC_TBL(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ .reg = 0 }
+};
+
+
+static bool reg_pattern_test(struct txgbe_adapter *adapter, u64 *data, int reg,
+			     u32 mask, u32 write)
+{
+	u32 pat, val, before;
+	static const u32 test_pattern[] = {
+		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+	};
+
+	if (TXGBE_REMOVED(adapter->hw.hw_addr)) {
+		*data = 1;
+		return true;
+	}
+	for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
+		before = rd32(&adapter->hw, reg);
+		wr32(&adapter->hw, reg, test_pattern[pat] & write);
+		val = rd32(&adapter->hw, reg);
+		if (val != (test_pattern[pat] & write & mask)) {
+			e_err(drv,
+			      "pattern test reg %04X failed: got 0x%08X "
+			      "expected 0x%08X\n",
+			      reg, val, test_pattern[pat] & write & mask);
+			*data = reg;
+			wr32(&adapter->hw, reg, before);
+			return true;
+		}
+		wr32(&adapter->hw, reg, before);
+	}
+	return false;
+}
+
+static bool reg_set_and_check(struct txgbe_adapter *adapter, u64 *data, int reg,
+			      u32 mask, u32 write)
+{
+	u32 val, before;
+
+	if (TXGBE_REMOVED(adapter->hw.hw_addr)) {
+		*data = 1;
+		return true;
+	}
+	before = rd32(&adapter->hw, reg);
+	wr32(&adapter->hw, reg, write & mask);
+	val = rd32(&adapter->hw, reg);
+	if ((write & mask) != (val & mask)) {
+		e_err(drv,
+		      "set/check reg %04X test failed: got 0x%08X expected"
+		      "0x%08X\n",
+		      reg, (val & mask), (write & mask));
+		*data = reg;
+		wr32(&adapter->hw, reg, before);
+		return true;
+	}
+	wr32(&adapter->hw, reg, before);
+	return false;
+}
+
+static bool txgbe_reg_test(struct txgbe_adapter *adapter, u64 *data)
+{
+	struct txgbe_reg_test *test;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i;
+
+	if (TXGBE_REMOVED(hw->hw_addr)) {
+		e_err(drv, "Adapter removed - register test blocked\n");
+		*data = 1;
+		return true;
+	}
+
+	test = reg_test_sapphire;
+
+	/*
+	 * Perform the remainder of the register test, looping through
+	 * the test table until we either fail or reach the null entry.
+	 */
+	while (test->reg) {
+		for (i = 0; i < test->array_len; i++) {
+			bool b = false;
+
+			switch (test->test_type) {
+			case PATTERN_TEST:
+				b = reg_pattern_test(adapter, data,
+						      test->reg + (i * 0x40),
+						      test->mask,
+						      test->write);
+				break;
+			case SET_READ_TEST:
+				b = reg_set_and_check(adapter, data,
+						       test->reg + (i * 0x40),
+						       test->mask,
+						       test->write);
+				break;
+			case WRITE_NO_TEST:
+				wr32(hw, test->reg + (i * 0x40),
+						test->write);
+				break;
+			case TABLE32_TEST:
+				b = reg_pattern_test(adapter, data,
+						      test->reg + (i * 4),
+						      test->mask,
+						      test->write);
+				break;
+			case TABLE64_TEST_LO:
+				b = reg_pattern_test(adapter, data,
+						      test->reg + (i * 8),
+						      test->mask,
+						      test->write);
+				break;
+			case TABLE64_TEST_HI:
+				b = reg_pattern_test(adapter, data,
+						      (test->reg + 4) + (i * 8),
+						      test->mask,
+						      test->write);
+				break;
+			}
+			if (b)
+				return true;
+		}
+		test++;
+	}
+
+	*data = 0;
+	return false;
+}
+
+static bool txgbe_eeprom_test(struct txgbe_adapter *adapter, u64 *data)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (TCALL(hw, eeprom.ops.validate_checksum, NULL)) {
+		*data = 1;
+		return true;
+	} else {
+		*data = 0;
+		return false;
+	}
+}
+
+static irqreturn_t txgbe_test_intr(int __always_unused irq, void *data)
+{
+	struct net_device *netdev = (struct net_device *) data;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u64 icr;
+
+	/* get misc interrupt, as cannot get ring interrupt status */
+	icr = txgbe_misc_isb(adapter, TXGBE_ISB_VEC1);
+	icr <<= 32;
+	icr |= txgbe_misc_isb(adapter, TXGBE_ISB_VEC0);
+
+	adapter->test_icr = icr;
+
+	return IRQ_HANDLED;
+}
+
+static int txgbe_intr_test(struct txgbe_adapter *adapter, u64 *data)
+{
+	struct net_device *netdev = adapter->netdev;
+	u64 mask;
+	u32 i = 0, shared_int = true;
+	u32 irq = adapter->pdev->irq;
+
+	if (TXGBE_REMOVED(adapter->hw.hw_addr)) {
+		*data = 1;
+		return -1;
+	}
+	*data = 0;
+
+	txgbe_setup_isb_resources(adapter);
+	txgbe_configure_isb(adapter);
+	/* Hook up test interrupt handler just for this test */
+	if (adapter->msix_entries) {
+		/* NOTE: we don't test MSI-X interrupts here, yet */
+		return 0;
+	} else if (adapter->flags & TXGBE_FLAG_MSI_ENABLED) {
+		shared_int = false;
+		if (request_irq(irq, &txgbe_test_intr, 0, netdev->name,
+				netdev)) {
+			*data = 1;
+			return -1;
+		}
+	} else if (!request_irq(irq, &txgbe_test_intr, IRQF_PROBE_SHARED,
+				netdev->name, netdev)) {
+		shared_int = false;
+	} else if (request_irq(irq, &txgbe_test_intr, IRQF_SHARED,
+			       netdev->name, netdev)) {
+		*data = 1;
+		return -1;
+	}
+	e_info(hw, "testing %s interrupt\n",
+	       (shared_int ? "shared" : "unshared"));
+
+	/* Disable all the interrupts */
+	txgbe_irq_disable(adapter);
+	TXGBE_WRITE_FLUSH(&adapter->hw);
+	usleep_range(10000, 20000);
+
+	/* Test each interrupt */
+	for (; i < 1; i++) {
+		/* Interrupt to test */
+		mask = 1ULL << i;
+
+		if (!shared_int) {
+			/*
+			 * Disable the interrupts to be reported in
+			 * the cause register and then force the same
+			 * interrupt and see if one gets posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			txgbe_intr_disable(&adapter->hw, ~mask);
+			txgbe_intr_trigger(&adapter->hw, ~mask);
+			TXGBE_WRITE_FLUSH(&adapter->hw);
+			usleep_range(10000, 20000);
+
+			if (adapter->test_icr & mask) {
+				*data = 3;
+				break;
+			}
+		}
+
+		/*
+		 * Enable the interrupt to be reported in the cause
+		 * register and then force the same interrupt and see
+		 * if one gets posted.  If an interrupt was not posted
+		 * to the bus, the test failed.
+		 */
+		adapter->test_icr = 0;
+		txgbe_intr_enable(&adapter->hw, mask);
+		txgbe_intr_trigger(&adapter->hw, mask);
+		TXGBE_WRITE_FLUSH(&adapter->hw);
+		usleep_range(10000, 20000);
+
+		if (!(adapter->test_icr & mask)) {
+			*data = 4;
+			break;
+		}
+	}
+
+	/* Disable all the interrupts */
+	txgbe_intr_disable(&adapter->hw, TXGBE_INTR_ALL);
+	TXGBE_WRITE_FLUSH(&adapter->hw);
+	usleep_range(10000, 20000);
+
+	/* Unhook test interrupt handler */
+	free_irq(irq, netdev);
+	txgbe_free_isb_resources(adapter);
+	
+	return *data;
+}
+
+static void txgbe_free_desc_rings(struct txgbe_adapter *adapter)
+{
+	struct txgbe_ring *tx_ring = &adapter->test_tx_ring;
+	struct txgbe_ring *rx_ring = &adapter->test_rx_ring;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	/* shut down the DMA engines now so they can be reinitialized later */
+
+	/* first Rx */
+	TCALL(hw, mac.ops.disable_rx);
+	txgbe_disable_rx_queue(adapter, rx_ring);
+
+	/* now Tx */
+	wr32(hw, TXGBE_PX_TR_CFG(tx_ring->reg_idx), 0);
+
+	wr32m(hw, TXGBE_TDM_CTL, TXGBE_TDM_CTL_TE, 0);
+
+	txgbe_reset(adapter);
+
+	txgbe_free_tx_resources(&adapter->test_tx_ring);
+	txgbe_free_rx_resources(&adapter->test_rx_ring);
+}
+
+static int txgbe_setup_desc_rings(struct txgbe_adapter *adapter)
+{
+	struct txgbe_ring *tx_ring = &adapter->test_tx_ring;
+	struct txgbe_ring *rx_ring = &adapter->test_rx_ring;
+	struct txgbe_hw *hw = &adapter->hw;
+	int ret_val;
+	int err;
+
+	TCALL(hw, mac.ops.setup_rxpba, 0, 0, PBA_STRATEGY_EQUAL);
+
+	/* Setup Tx descriptor ring and Tx buffers */
+	tx_ring->count = TXGBE_DEFAULT_TXD;
+	tx_ring->queue_index = 0;
+	tx_ring->dev = pci_dev_to_dev(adapter->pdev);
+	tx_ring->netdev = adapter->netdev;
+	tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx;
+
+	err = txgbe_setup_tx_resources(tx_ring);
+	if (err)
+		return 1;
+
+	wr32m(&adapter->hw, TXGBE_TDM_CTL,
+		TXGBE_TDM_CTL_TE, TXGBE_TDM_CTL_TE);
+
+	txgbe_configure_tx_ring(adapter, tx_ring);
+
+	/* enable mac transmitter */
+	wr32m(hw, TXGBE_MAC_TX_CFG,
+		TXGBE_MAC_TX_CFG_TE | TXGBE_MAC_TX_CFG_SPEED_MASK,
+		TXGBE_MAC_TX_CFG_TE | TXGBE_MAC_TX_CFG_SPEED_10G);
+
+	/* Setup Rx Descriptor ring and Rx buffers */
+	rx_ring->count = TXGBE_DEFAULT_RXD;
+	rx_ring->queue_index = 0;
+	rx_ring->dev = pci_dev_to_dev(adapter->pdev);
+	rx_ring->netdev = adapter->netdev;
+	rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	rx_ring->rx_buf_len = TXGBE_RXBUFFER_2K;
+#endif
+
+	err = txgbe_setup_rx_resources(rx_ring);
+	if (err) {
+		ret_val = 4;
+		goto err_nomem;
+	}
+
+	TCALL(hw, mac.ops.disable_rx);
+
+	txgbe_configure_rx_ring(adapter, rx_ring);
+
+	TCALL(hw, mac.ops.enable_rx);
+
+	return 0;
+
+err_nomem:
+	txgbe_free_desc_rings(adapter);
+	return ret_val;
+}
+
+static int txgbe_setup_config(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 reg_data;
+
+	/* Setup traffic loopback */
+	reg_data = rd32(hw, TXGBE_PSR_CTL);
+	reg_data |= TXGBE_PSR_CTL_BAM | TXGBE_PSR_CTL_UPE |
+		TXGBE_PSR_CTL_MPE | TXGBE_PSR_CTL_TPE;
+	wr32(hw, TXGBE_PSR_CTL, reg_data);
+
+	wr32(hw, TXGBE_RSC_CTL,
+		(rd32(hw, TXGBE_RSC_CTL) |
+		TXGBE_RSC_CTL_SAVE_MAC_ERR) & ~TXGBE_RSC_CTL_SECRX_DIS);
+
+	wr32(hw, TXGBE_RSC_LSEC_CTL, 0x4);
+
+	wr32(hw, TXGBE_PSR_VLAN_CTL,
+		rd32(hw, TXGBE_PSR_VLAN_CTL) &
+		~TXGBE_PSR_VLAN_CTL_VFE);
+
+	wr32m(&adapter->hw, TXGBE_MAC_RX_CFG,
+		TXGBE_MAC_RX_CFG_LM, ~TXGBE_MAC_RX_CFG_LM);
+	wr32m(&adapter->hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_FORCE_LKUP, ~TXGBE_CFG_PORT_CTL_FORCE_LKUP);
+
+
+	TXGBE_WRITE_FLUSH(hw);
+	usleep_range(10000, 20000);
+
+	return 0;
+}
+
+static int txgbe_setup_phy_loopback_test(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 value;
+	/* setup phy loopback */
+	value = txgbe_rd32_epcs(hw, TXGBE_PHY_MISC_CTL0);
+	value |= TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_0 |
+		TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_3_1;
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, value);
+
+	value = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1,
+		value | TXGBE_SR_PMA_MMD_CTL1_LB_EN);
+	return 0;
+}
+
+static void txgbe_phy_loopback_cleanup(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 value;
+
+	value = txgbe_rd32_epcs(hw, TXGBE_PHY_MISC_CTL0);
+	value &= ~(TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_0 |
+		TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_3_1);
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, value);
+	value = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1,
+		value & ~TXGBE_SR_PMA_MMD_CTL1_LB_EN);
+}
+
+
+static void txgbe_create_lbtest_frame(struct sk_buff *skb,
+				      unsigned int frame_size)
+{
+	memset(skb->data, 0xFF, frame_size);
+	frame_size >>= 1;
+	memset(&skb->data[frame_size], 0xAA, frame_size / 2 - 1);
+	memset(&skb->data[frame_size + 10], 0xBE, 1);
+	memset(&skb->data[frame_size + 12], 0xAF, 1);
+}
+
+static bool txgbe_check_lbtest_frame(struct txgbe_rx_buffer *rx_buffer,
+				     unsigned int frame_size)
+{
+	unsigned char *data;
+	bool match = true;
+
+	frame_size >>= 1;
+
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	data = rx_buffer->skb->data;
+#else
+	data = kmap(rx_buffer->page) + rx_buffer->page_offset;
+#endif
+
+	if (data[3] != 0xFF ||
+	    data[frame_size + 10] != 0xBE ||
+	    data[frame_size + 12] != 0xAF)
+		match = false;
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	kunmap(rx_buffer->page);
+
+#endif
+	return match;
+}
+
+static u16 txgbe_clean_test_rings(struct txgbe_ring *rx_ring,
+				  struct txgbe_ring *tx_ring,
+				  unsigned int size)
+{
+	union txgbe_rx_desc *rx_desc;
+	struct txgbe_rx_buffer *rx_buffer;
+	struct txgbe_tx_buffer *tx_buffer;
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	const int bufsz = rx_ring->rx_buf_len;
+#else
+	const int bufsz = txgbe_rx_bufsz(rx_ring);
+#endif
+	u16 rx_ntc, tx_ntc, count = 0;
+
+	/* initialize next to clean and descriptor values */
+	rx_ntc = rx_ring->next_to_clean;
+	tx_ntc = tx_ring->next_to_clean;
+	rx_desc = TXGBE_RX_DESC(rx_ring, rx_ntc);
+
+	while (txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_DD)) {
+		/* unmap buffer on Tx side */
+		tx_buffer = &tx_ring->tx_buffer_info[tx_ntc];
+		txgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer);
+
+		/* check Rx buffer */
+		rx_buffer = &rx_ring->rx_buffer_info[rx_ntc];
+
+		/* sync Rx buffer for CPU read */
+		dma_sync_single_for_cpu(rx_ring->dev,
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+					rx_buffer->page_dma,
+#else
+					rx_buffer->dma,
+#endif
+					bufsz,
+					DMA_FROM_DEVICE);
+
+		/* verify contents of skb */
+		if (txgbe_check_lbtest_frame(rx_buffer, size))
+			count++;
+
+		/* sync Rx buffer for device write */
+		dma_sync_single_for_device(rx_ring->dev,
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+					rx_buffer->page_dma,
+#else
+					rx_buffer->dma,
+#endif
+					bufsz,
+					DMA_FROM_DEVICE);
+
+		/* increment Rx/Tx next to clean counters */
+		rx_ntc++;
+		if (rx_ntc == rx_ring->count)
+			rx_ntc = 0;
+		tx_ntc++;
+		if (tx_ntc == tx_ring->count)
+			tx_ntc = 0;
+
+		/* fetch next descriptor */
+		rx_desc = TXGBE_RX_DESC(rx_ring, rx_ntc);
+	}
+
+	/* re-map buffers to ring, store next to clean values */
+	txgbe_alloc_rx_buffers(rx_ring, count);
+	rx_ring->next_to_clean = rx_ntc;
+	tx_ring->next_to_clean = tx_ntc;
+
+	return count;
+}
+
+static int txgbe_run_loopback_test(struct txgbe_adapter *adapter)
+{
+	struct txgbe_ring *tx_ring = &adapter->test_tx_ring;
+	struct txgbe_ring *rx_ring = &adapter->test_rx_ring;
+	int i, j, lc, good_cnt, ret_val = 0;
+	unsigned int size = 1024;
+	netdev_tx_t tx_ret_val;
+	struct sk_buff *skb;
+	u32 flags_orig = adapter->flags;
+
+
+	/* DCB can modify the frames on Tx */
+	adapter->flags &= ~TXGBE_FLAG_DCB_ENABLED;
+
+	/* allocate test skb */
+	skb = alloc_skb(size, GFP_KERNEL);
+	if (!skb)
+		return 11;
+
+	/* place data into test skb */
+	txgbe_create_lbtest_frame(skb, size);
+	skb_put(skb, size);
+
+	/*
+	 * Calculate the loop count based on the largest descriptor ring
+	 * The idea is to wrap the largest ring a number of times using 64
+	 * send/receive pairs during each loop
+	 */
+
+	if (rx_ring->count <= tx_ring->count)
+		lc = ((tx_ring->count / 64) * 2) + 1;
+	else
+		lc = ((rx_ring->count / 64) * 2) + 1;
+
+	for (j = 0; j <= lc; j++) {
+		/* reset count of good packets */
+		good_cnt = 0;
+
+		/* place 64 packets on the transmit queue*/
+		for (i = 0; i < 64; i++) {
+			skb_get(skb);
+			tx_ret_val = txgbe_xmit_frame_ring(skb,
+							   adapter,
+							   tx_ring);
+			if (tx_ret_val == NETDEV_TX_OK)
+				good_cnt++;
+		}
+
+		if (good_cnt != 64) {
+			ret_val = 12;
+			break;
+		}
+
+		/* allow 200 milliseconds for packets to go from Tx to Rx */
+		msleep(200);
+
+		good_cnt = txgbe_clean_test_rings(rx_ring, tx_ring, size);
+		if(j == 0)
+			continue;
+		else if (good_cnt != 64) {
+			ret_val = 13;
+			break;
+		}
+	}
+
+	/* free the original skb */
+	kfree_skb(skb);
+	adapter->flags = flags_orig;
+
+	return ret_val;
+}
+
+static int txgbe_loopback_test(struct txgbe_adapter *adapter, u64 *data)
+{
+	*data = txgbe_setup_desc_rings(adapter);
+	if (*data)
+		goto out;
+
+	*data = txgbe_setup_config(adapter);
+	if (*data)
+		goto err_loopback;
+
+	*data = txgbe_setup_phy_loopback_test(adapter);
+	if (*data)
+			goto err_loopback;
+	*data = txgbe_run_loopback_test(adapter);
+	if (*data)
+			e_info(hw, "phy loopback testing failed\n");
+	txgbe_phy_loopback_cleanup(adapter);
+
+err_loopback:
+	txgbe_free_desc_rings(adapter);
+out:
+	return *data;
+}
+
+#ifndef HAVE_ETHTOOL_GET_SSET_COUNT
+static int txgbe_diag_test_count(struct net_device __always_unused *netdev)
+{
+	return TXGBE_TEST_LEN;
+}
+
+#endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+static void txgbe_diag_test(struct net_device *netdev,
+			    struct ethtool_test *eth_test, u64 *data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	bool if_running = netif_running(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (TXGBE_REMOVED(hw->hw_addr)) {
+		e_err(hw, "Adapter removed - test blocked\n");
+		data[0] = 1;
+		data[1] = 1;
+		data[2] = 1;
+		data[3] = 1;
+		data[4] = 1;
+		eth_test->flags |= ETH_TEST_FL_FAILED;
+		return;
+	}
+	set_bit(__TXGBE_TESTING, &adapter->state);
+	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+		if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+			int i;
+			for (i = 0; i < adapter->num_vfs; i++) {
+				if (adapter->vfinfo[i].clear_to_send) {
+					e_warn(drv, "Please take active VFS "
+					       "offline and restart the "
+					       "adapter before running NIC "
+					       "diagnostics\n");
+					data[0] = 1;
+					data[1] = 1;
+					data[2] = 1;
+					data[3] = 1;
+					data[4] = 1;
+					eth_test->flags |= ETH_TEST_FL_FAILED;
+					clear_bit(__TXGBE_TESTING,
+						  &adapter->state);
+					goto skip_ol_tests;
+				}
+			}
+		}
+
+		/* Offline tests */
+		e_info(hw, "offline testing starting\n");
+
+		/* Link test performed before hardware reset so autoneg doesn't
+		 * interfere with test result */
+		if (txgbe_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		if (if_running)
+			/* indicate we're in test mode */
+			txgbe_close(netdev);
+		else
+			txgbe_reset(adapter);
+
+		e_info(hw, "register testing starting\n");
+		if (txgbe_reg_test(adapter, &data[0]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+		txgbe_reset(adapter);
+		e_info(hw, "eeprom testing starting\n");
+		if (txgbe_eeprom_test(adapter, &data[1]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		txgbe_reset(adapter);
+		e_info(hw, "interrupt testing starting\n");
+		if (txgbe_intr_test(adapter, &data[2]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+	
+	if ( !(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP) ||
+			((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP)) ){
+		/* If SRIOV or VMDq is enabled then skip MAC
+		 * loopback diagnostic. */
+		if (adapter->flags & (TXGBE_FLAG_SRIOV_ENABLED |
+				      TXGBE_FLAG_VMDQ_ENABLED)) {
+			e_info(hw, "skip MAC loopback diagnostic in VT mode\n");
+			data[3] = 0;
+			goto skip_loopback;
+		}
+
+		txgbe_reset(adapter);
+		e_info(hw, "loopback testing starting\n");
+		if (txgbe_loopback_test(adapter, &data[3]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+	}
+
+skip_loopback:
+		txgbe_reset(adapter);
+
+		/* clear testing bit and return adapter to previous state */
+		clear_bit(__TXGBE_TESTING, &adapter->state);
+		if (if_running)
+			txgbe_open(netdev);
+		else
+			TCALL(hw, mac.ops.disable_tx_laser);
+	} else {
+		e_info(hw, "online testing starting\n");
+
+		/* Online tests */
+		if (txgbe_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* Offline tests aren't run; pass by default */
+		data[0] = 0;
+		data[1] = 0;
+		data[2] = 0;
+		data[3] = 0;
+
+		clear_bit(__TXGBE_TESTING, &adapter->state);
+	}
+
+skip_ol_tests:
+	msleep_interruptible(4 * 1000);
+}
+
+
+static int txgbe_wol_exclusion(struct txgbe_adapter *adapter,
+			       struct ethtool_wolinfo *wol)
+{
+	int retval = 0;
+
+	/* WOL not supported for all devices */
+	if (!txgbe_wol_supported(adapter)) {
+		retval = 1;
+		wol->supported = 0;
+	}
+
+	return retval;
+}
+
+static void txgbe_get_wol(struct net_device *netdev,
+			  struct ethtool_wolinfo *wol)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	wol->supported = WAKE_UCAST | WAKE_MCAST |
+			 WAKE_BCAST | WAKE_MAGIC;
+	wol->wolopts = 0;
+
+	if (txgbe_wol_exclusion(adapter, wol) ||
+	    !device_can_wakeup(pci_dev_to_dev(adapter->pdev)))
+		return;
+	if((hw->subsystem_device_id & TXGBE_WOL_MASK) != TXGBE_WOL_SUP)
+		return;
+
+	if (adapter->wol & TXGBE_PSR_WKUP_CTL_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & TXGBE_PSR_WKUP_CTL_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & TXGBE_PSR_WKUP_CTL_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & TXGBE_PSR_WKUP_CTL_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+	
+
+}
+
+static int txgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+
+
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+		return -EOPNOTSUPP;
+
+	if (txgbe_wol_exclusion(adapter, wol))
+		return wol->wolopts ? -EOPNOTSUPP : 0;
+	if((hw->subsystem_device_id & TXGBE_WOL_MASK) != TXGBE_WOL_SUP)
+		return -EOPNOTSUPP;
+
+	adapter->wol = 0;
+
+	if (wol->wolopts & WAKE_UCAST)
+		adapter->wol |= TXGBE_PSR_WKUP_CTL_EX;
+	if (wol->wolopts & WAKE_MCAST)
+		adapter->wol |= TXGBE_PSR_WKUP_CTL_MC;
+	if (wol->wolopts & WAKE_BCAST)
+		adapter->wol |= TXGBE_PSR_WKUP_CTL_BC;
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= TXGBE_PSR_WKUP_CTL_MAG;
+
+	hw->wol_enabled = !!(adapter->wol);
+	wr32(hw, TXGBE_PSR_WKUP_CTL, adapter->wol);
+
+	device_set_wakeup_enable(pci_dev_to_dev(adapter->pdev), adapter->wol);
+
+	return 0;
+
+	return -EOPNOTSUPP;
+}
+
+static int txgbe_nway_reset(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		txgbe_reinit_locked(adapter);
+
+	return 0;
+}
+
+#ifdef HAVE_ETHTOOL_SET_PHYS_ID
+static int txgbe_set_phys_id(struct net_device *netdev,
+			     enum ethtool_phys_id_state state)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 value = 0;
+	
+	switch (state) {
+	case ETHTOOL_ID_ACTIVE:
+		adapter->led_reg = rd32(hw, TXGBE_CFG_LED_CTL);
+		return 2;
+
+	case ETHTOOL_ID_ON:
+		if (hw->oem_ssid != 0x0085 && hw->oem_svid == 0x1bd4) {
+			if (adapter->link_up) {
+				switch (adapter->link_speed) {
+				case TXGBE_LINK_SPEED_10GB_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_10G);
+					break;
+				case TXGBE_LINK_SPEED_1GB_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_1G);
+					break;
+				case TXGBE_LINK_SPEED_100_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_100M);
+					break;
+				default:
+					break;
+				}
+			} else 
+				TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_10G);
+		} else
+			TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_UP);
+		break;
+
+	case ETHTOOL_ID_OFF:
+		if (hw->oem_ssid != 0x0085 && hw->oem_svid == 0x1bd4) {
+			if (adapter->link_up) {
+				switch (adapter->link_speed) {
+				case TXGBE_LINK_SPEED_10GB_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_10G);
+					break;
+				case TXGBE_LINK_SPEED_1GB_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_1G);
+					break;
+				case TXGBE_LINK_SPEED_100_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_100M);
+					break;
+				default:
+					break;
+				}
+			} else 
+				TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_10G);
+		} else
+			TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_UP);
+		break;
+
+	case ETHTOOL_ID_INACTIVE:
+		/* Restore LED settings */
+		wr32(&adapter->hw, TXGBE_CFG_LED_CTL,
+				adapter->led_reg);
+		if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) {
+			txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, &value);
+			txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, (value & 0xFFFC) | 0x0);
+		}
+		break;
+	}
+
+	return 0;
+}
+#else
+static int txgbe_phys_id(struct net_device *netdev, u32 data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 led_reg = rd32(hw, TXGBE_CFG_LED_CTL);
+	u32 i;
+
+	if (!data || data > 300)
+		data = 300;
+
+	for (i = 0; i < (data * 1000); i += 400) {
+		if (hw->oem_ssid != 0x0085 && hw->oem_svid == 0x1bd4) {
+			if (adapter->link_up) {
+				switch (adapter->link_speed) {
+				case TXGBE_LINK_SPEED_10GB_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_10G);
+					break;
+				case TXGBE_LINK_SPEED_1GB_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_1G);
+					break;
+				case TXGBE_LINK_SPEED_100_FULL:
+					TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_100M);
+					break;
+				default:
+					break;
+				}
+			} else 
+				TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_10G);
+		} else
+			TCALL(hw, mac.ops.led_on, TXGBE_LED_LINK_UP);
+		msleep_interruptible(200);
+		if (hw->oem_ssid != 0x0085 && hw->oem_svid == 0x1bd4) {
+			if (adapter->link_up) {
+				switch (adapter->link_speed) {
+				case TXGBE_LINK_SPEED_10GB_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_10G);
+					break;
+				case TXGBE_LINK_SPEED_1GB_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_1G);
+					break;
+				case TXGBE_LINK_SPEED_100_FULL:
+					TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_100M);
+					break;
+				default:
+					break;
+				}
+			} else 
+				TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_10G);
+		} else
+			TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_UP);
+		msleep_interruptible(200);
+	}
+
+	/* Restore LED settings */
+	wr32(hw, TXGBE_CFG_LED_CTL, led_reg);
+
+	return 0;
+}
+#endif /* HAVE_ETHTOOL_SET_PHYS_ID */
+
+static int txgbe_get_coalesce(struct net_device *netdev,
+#ifdef HAVE_ETHTOOL_COALESCE_EXTACK
+			      struct ethtool_coalesce *ec,
+			      struct kernel_ethtool_coalesce *kernel_coal,
+			      struct netlink_ext_ack *extack)
+#else
+			      struct ethtool_coalesce *ec)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	ec->tx_max_coalesced_frames_irq = adapter->tx_work_limit;
+	/* only valid if in constant ITR mode */
+	if (adapter->rx_itr_setting <= 1)
+		ec->rx_coalesce_usecs = adapter->rx_itr_setting;
+	else
+		ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
+
+	/* if in mixed tx/rx queues per vector mode, report only rx settings */
+	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
+		return 0;
+
+	/* only valid if in constant ITR mode */
+	if (adapter->tx_itr_setting <= 1)
+		ec->tx_coalesce_usecs = adapter->tx_itr_setting;
+	else
+		ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
+
+	return 0;
+}
+
+/*
+ * this function must be called before setting the new value of
+ * rx_itr_setting
+ */
+static bool txgbe_update_rsc(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	/* nothing to do if LRO or RSC are not enabled */
+	if (!(adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) ||
+	    !(netdev->features & NETIF_F_LRO))
+		return false;
+
+	/* check the feature flag value and enable RSC if necessary */
+	if (adapter->rx_itr_setting == 1 ||
+	    adapter->rx_itr_setting > TXGBE_MIN_RSC_ITR) {
+		if (!(adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)) {
+			adapter->flags2 |= TXGBE_FLAG2_RSC_ENABLED;
+			e_info(probe, "rx-usecs value high enough "
+				      "to re-enable RSC\n");
+			return true;
+		}
+	/* if interrupt rate is too high then disable RSC */
+	} else if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED) {
+		adapter->flags2 &= ~TXGBE_FLAG2_RSC_ENABLED;
+#ifdef TXGBE_NO_LRO
+		e_info(probe, "rx-usecs set too low, disabling RSC\n");
+#else
+		e_info(probe, "rx-usecs set too low, "
+			      "falling back to software LRO\n");
+#endif
+		return true;
+	}
+	return false;
+}
+
+static int txgbe_set_coalesce(struct net_device *netdev,
+#ifdef HAVE_ETHTOOL_COALESCE_EXTACK
+			      struct ethtool_coalesce *ec,
+			      struct kernel_ethtool_coalesce *kernel_coal,
+			      struct netlink_ext_ack *extack)
+#else
+			      struct ethtool_coalesce *ec)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_q_vector *q_vector;
+	int i;
+	u16 tx_itr_param, rx_itr_param;
+	u16  tx_itr_prev;
+	bool need_reset = false;
+
+	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) {
+		/* reject Tx specific changes in case of mixed RxTx vectors */
+		if (ec->tx_coalesce_usecs)
+			return -EINVAL;
+		tx_itr_prev = adapter->rx_itr_setting;
+	} else {
+		tx_itr_prev = adapter->tx_itr_setting;
+	}
+
+	if (ec->tx_max_coalesced_frames_irq)
+		adapter->tx_work_limit = ec->tx_max_coalesced_frames_irq;
+
+	if ((ec->rx_coalesce_usecs > (TXGBE_MAX_EITR >> 2)) ||
+	    (ec->tx_coalesce_usecs > (TXGBE_MAX_EITR >> 2)))
+		return -EINVAL;
+
+	if (ec->rx_coalesce_usecs > 1)
+		adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2;
+	else
+		adapter->rx_itr_setting = ec->rx_coalesce_usecs;
+
+	if (adapter->rx_itr_setting == 1)
+		rx_itr_param = TXGBE_20K_ITR;
+	else
+		rx_itr_param = adapter->rx_itr_setting;
+
+	if (ec->tx_coalesce_usecs > 1)
+		adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2;
+	else
+		adapter->tx_itr_setting = ec->tx_coalesce_usecs;
+
+	if (adapter->tx_itr_setting == 1)
+		tx_itr_param = TXGBE_12K_ITR;
+	else
+		tx_itr_param = adapter->tx_itr_setting;
+
+	/* mixed Rx/Tx */
+	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
+		adapter->tx_itr_setting = adapter->rx_itr_setting;
+
+	/* detect ITR changes that require update of TXDCTL.WTHRESH */
+	if ((adapter->tx_itr_setting != 1) &&
+	    (adapter->tx_itr_setting < TXGBE_100K_ITR)) {
+		if ((tx_itr_prev == 1) ||
+		    (tx_itr_prev >= TXGBE_100K_ITR))
+			need_reset = true;
+	} else {
+		if ((tx_itr_prev != 1) &&
+		    (tx_itr_prev < TXGBE_100K_ITR))
+			need_reset = true;
+	}
+
+	/* check the old value and enable RSC if necessary */
+	need_reset |= txgbe_update_rsc(adapter);
+
+	if (adapter->hw.mac.dmac_config.watchdog_timer &&
+	    (!adapter->rx_itr_setting && !adapter->tx_itr_setting)) {
+		e_info(probe,
+		       "Disabling DMA coalescing because interrupt throttling "
+		       "is disabled\n");
+		adapter->hw.mac.dmac_config.watchdog_timer = 0;
+		TCALL(hw, mac.ops.dmac_config);
+	}
+
+	for (i = 0; i < adapter->num_q_vectors; i++) {
+		q_vector = adapter->q_vector[i];
+		q_vector->tx.work_limit = adapter->tx_work_limit;
+		q_vector->rx.work_limit = adapter->rx_work_limit;
+		if (q_vector->tx.count && !q_vector->rx.count)
+			/* tx only */
+			q_vector->itr = tx_itr_param;
+		else
+			/* rx only or mixed */
+			q_vector->itr = rx_itr_param;
+		txgbe_write_eitr(q_vector);
+	}
+
+	/*
+	 * do reset here at the end to make sure EITR==0 case is handled
+	 * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings
+	 * also locks in RSC enable/disable which requires reset
+	 */
+	if (need_reset)
+		txgbe_do_reset(netdev);
+
+	return 0;
+}
+
+#ifndef HAVE_NDO_SET_FEATURES
+static u32 txgbe_get_rx_csum(struct net_device *netdev)
+{
+	return !!(netdev->features & NETIF_F_RXCSUM);
+}
+
+static int txgbe_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	bool need_reset = false;
+
+	if (data)
+		netdev->features |= NETIF_F_RXCSUM;
+	else
+		netdev->features &= ~NETIF_F_RXCSUM;
+
+	/* LRO and RSC both depend on RX checksum to function */
+	if (!data && (netdev->features & NETIF_F_LRO)) {
+		netdev->features &= ~NETIF_F_LRO;
+
+		if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED) {
+			adapter->flags2 &= ~TXGBE_FLAG2_RSC_ENABLED;
+			need_reset = true;
+		}
+	}
+
+#ifdef HAVE_VXLAN_RX_OFFLOAD
+	if (adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE && data) {
+		netdev->hw_enc_features |= NETIF_F_RXCSUM |
+					   NETIF_F_IP_CSUM |
+					   NETIF_F_IPV6_CSUM;
+		if (!need_reset)
+			adapter->flags2 |= TXGBE_FLAG2_VXLAN_REREG_NEEDED;
+	} else {
+		netdev->hw_enc_features &= ~(NETIF_F_RXCSUM |
+					     NETIF_F_IP_CSUM |
+					     NETIF_F_IPV6_CSUM);
+		txgbe_clear_vxlan_port(adapter);
+	}
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+
+	if (need_reset)
+		txgbe_do_reset(netdev);
+
+	return 0;
+}
+
+static int txgbe_set_tx_csum(struct net_device *netdev, u32 data)
+{
+#ifdef NETIF_F_IPV6_CSUM
+	u32 feature_list = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+#else
+	u32 feature_list = NETIF_F_IP_CSUM;
+#endif
+
+
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	if (data)
+		netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
+	else
+		netdev->hw_enc_features &= ~NETIF_F_GSO_UDP_TUNNEL;
+	feature_list |= NETIF_F_GSO_UDP_TUNNEL;
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+	feature_list |= NETIF_F_SCTP_CSUM;
+
+
+	if (data)
+		netdev->features |= feature_list;
+	else
+		netdev->features &= ~feature_list;
+
+	return 0;
+}
+
+#ifdef NETIF_F_TSO
+static int txgbe_set_tso(struct net_device *netdev, u32 data)
+{
+#ifdef NETIF_F_TSO6
+	u32 feature_list = NETIF_F_TSO | NETIF_F_TSO6;
+#else
+	u32 feature_list = NETIF_F_TSO;
+#endif
+
+	if (data)
+		netdev->features |= feature_list;
+	else
+		netdev->features &= ~feature_list;
+
+#ifndef HAVE_NETDEV_VLAN_FEATURES
+	if (!data) {
+		struct txgbe_adapter *adapter = netdev_priv(netdev);
+		struct net_device *v_netdev;
+		int i;
+
+		/* disable TSO on all VLANs if they're present */
+		if (!adapter->vlgrp)
+			goto tso_out;
+
+		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+			v_netdev = vlan_group_get_device(adapter->vlgrp, i);
+			if (!v_netdev)
+				continue;
+
+			v_netdev->features &= ~feature_list;
+			vlan_group_set_device(adapter->vlgrp, i, v_netdev);
+		}
+	}
+
+tso_out:
+
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+	return 0;
+}
+
+#endif /* NETIF_F_TSO */
+#ifdef ETHTOOL_GFLAGS
+static int txgbe_set_flags(struct net_device *netdev, u32 data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	u32 supported_flags = ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
+	u32 changed = netdev->features ^ data;
+	bool need_reset = false;
+	int rc;
+
+#ifndef HAVE_VLAN_RX_REGISTER
+	if ((adapter->flags & TXGBE_FLAG_DCB_ENABLED) &&
+	    !(data & ETH_FLAG_RXVLAN))
+		return -EINVAL;
+
+#endif
+#ifdef TXGBE_NO_LRO
+	if (adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE)
+#endif
+		supported_flags |= ETH_FLAG_LRO;
+
+#ifdef ETHTOOL_GRXRINGS
+
+	supported_flags |= ETH_FLAG_NTUPLE;
+
+
+#endif
+#ifdef NETIF_F_RXHASH
+	supported_flags |= ETH_FLAG_RXHASH;
+
+#endif
+	rc = ethtool_op_set_flags(netdev, data, supported_flags);
+	if (rc)
+		return rc;
+
+#ifndef HAVE_VLAN_RX_REGISTER
+	if (changed & ETH_FLAG_RXVLAN)
+		txgbe_vlan_mode(netdev, netdev->features);
+
+#endif
+
+#ifdef HAVE_VXLAN_CHECKS
+	if (adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE &&
+	    netdev->features & NETIF_F_RXCSUM) {
+		vxlan_get_rx_port(netdev);
+	else
+		txgbe_clear_vxlan_port(adapter);
+	}
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+
+	/* if state changes we need to update adapter->flags and reset */
+	if (!(netdev->features & NETIF_F_LRO)) {
+		if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)
+			need_reset = true;
+		adapter->flags2 &= ~TXGBE_FLAG2_RSC_ENABLED;
+	} else if ((adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) &&
+		   !(adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)) {
+		if (adapter->rx_itr_setting == 1 ||
+		    adapter->rx_itr_setting > TXGBE_MIN_RSC_ITR) {
+			adapter->flags2 |= TXGBE_FLAG2_RSC_ENABLED;
+			need_reset = true;
+		} else if (changed & ETH_FLAG_LRO) {
+#ifdef TXGBE_NO_LRO
+			e_info(probe, "rx-usecs set too low, "
+			       "disabling RSC\n");
+#else
+			e_info(probe, "rx-usecs set too low, "
+			       "falling back to software LRO\n");
+#endif
+		}
+	}
+
+#ifdef ETHTOOL_GRXRINGS
+	/*
+	 * Check if Flow Director n-tuple support was enabled or disabled.  If
+	 * the state changed, we need to reset.
+	 */
+	switch (netdev->features & NETIF_F_NTUPLE) {
+	case NETIF_F_NTUPLE:
+		/* turn off ATR, enable perfect filters and reset */
+		if (!(adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+			need_reset = true;
+
+		adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+		adapter->flags |= TXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+		break;
+	default:
+		/* turn off perfect filters, enable ATR and reset */
+		if (adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+			need_reset = true;
+
+		adapter->flags &= ~TXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+
+		/* We cannot enable ATR if VMDq is enabled */
+		if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED)
+			break;
+
+		/* We cannot enable ATR if we have 2 or more traffic classes */
+		if (netdev_get_num_tc(netdev) > 1)
+			break;
+
+		/* We cannot enable ATR if RSS is disabled */
+		if (adapter->ring_feature[RING_F_RSS].limit <= 1)
+			break;
+
+		/* A sample rate of 0 indicates ATR disabled */
+		if (!adapter->atr_sample_rate)
+			break;
+
+		adapter->flags |= TXGBE_FLAG_FDIR_HASH_CAPABLE;
+		break;
+	}
+
+#endif /* ETHTOOL_GRXRINGS */
+	if (need_reset)
+		txgbe_do_reset(netdev);
+
+	return 0;
+}
+
+#endif /* ETHTOOL_GFLAGS */
+#endif /* HAVE_NDO_SET_FEATURES */
+#ifdef ETHTOOL_GRXRINGS
+static int txgbe_get_ethtool_fdir_entry(struct txgbe_adapter *adapter,
+					struct ethtool_rxnfc *cmd)
+{
+	union txgbe_atr_input *mask = &adapter->fdir_mask;
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+	struct hlist_node *node;
+	struct txgbe_fdir_filter *rule = NULL;
+
+	/* report total rule count */
+	cmd->data = (1024 << adapter->fdir_pballoc) - 2;
+
+	hlist_for_each_entry_safe(rule, node,
+				  &adapter->fdir_filter_list, fdir_node) {
+		if (fsp->location <= rule->sw_idx)
+			break;
+	}
+
+	if (!rule || fsp->location != rule->sw_idx)
+		return -EINVAL;
+
+	/* fill out the flow spec entry */
+
+	/* set flow type field */
+	switch (rule->filter.formatted.flow_type) {
+	case TXGBE_ATR_FLOW_TYPE_TCPV4:
+		fsp->flow_type = TCP_V4_FLOW;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_UDPV4:
+		fsp->flow_type = UDP_V4_FLOW;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_SCTPV4:
+		fsp->flow_type = SCTP_V4_FLOW;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_IPV4:
+		fsp->flow_type = IP_USER_FLOW;
+		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+		fsp->h_u.usr_ip4_spec.proto = 0;
+		fsp->m_u.usr_ip4_spec.proto = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port;
+	fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port;
+	fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port;
+	fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port;
+	fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0];
+	fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0];
+	fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0];
+	fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0];
+	fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes;
+	fsp->m_ext.vlan_etype = mask->formatted.flex_bytes;
+	fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool);
+	fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool);
+	fsp->flow_type |= FLOW_EXT;
+
+	/* record action */
+	if (rule->action == TXGBE_RDB_FDIR_DROP_QUEUE)
+		fsp->ring_cookie = RX_CLS_FLOW_DISC;
+	else
+		fsp->ring_cookie = rule->action;
+
+	return 0;
+}
+
+static int txgbe_get_ethtool_fdir_all(struct txgbe_adapter *adapter,
+				      struct ethtool_rxnfc *cmd,
+				      u32 *rule_locs)
+{
+	struct hlist_node *node;
+	struct txgbe_fdir_filter *rule;
+	int cnt = 0;
+
+	/* report total rule count */
+	cmd->data = (1024 << adapter->fdir_pballoc) - 2;
+
+	hlist_for_each_entry_safe(rule, node,
+				  &adapter->fdir_filter_list, fdir_node) {
+		if (cnt == cmd->rule_cnt)
+			return -EMSGSIZE;
+		rule_locs[cnt] = rule->sw_idx;
+		cnt++;
+	}
+
+	cmd->rule_cnt = cnt;
+
+	return 0;
+}
+
+static int txgbe_get_rss_hash_opts(struct txgbe_adapter *adapter,
+				   struct ethtool_rxnfc *cmd)
+{
+	cmd->data = 0;
+
+	/* Report default options for RSS on txgbe */
+	switch (cmd->flow_type) {
+	case TCP_V4_FLOW:
+		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		fallthrough;
+	case UDP_V4_FLOW:
+		if (adapter->flags2 & TXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
+			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		fallthrough;
+	case SCTP_V4_FLOW:
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case IPV4_FLOW:
+		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+		break;
+	case TCP_V6_FLOW:
+		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		fallthrough;
+	case UDP_V6_FLOW:
+		if (adapter->flags2 & TXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
+			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+		fallthrough;
+	case SCTP_V6_FLOW:
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case IPV6_FLOW:
+		cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int txgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+#ifdef HAVE_ETHTOOL_GET_RXNFC_VOID_RULE_LOCS
+			   void *rule_locs)
+#else
+			   u32 *rule_locs)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_GRXRINGS:
+		cmd->data = adapter->num_rx_queues;
+		ret = 0;
+		break;
+	case ETHTOOL_GRXCLSRLCNT:
+		cmd->rule_cnt = adapter->fdir_filter_count;
+		ret = 0;
+		break;
+	case ETHTOOL_GRXCLSRULE:
+		ret = txgbe_get_ethtool_fdir_entry(adapter, cmd);
+		break;
+	case ETHTOOL_GRXCLSRLALL:
+		ret = txgbe_get_ethtool_fdir_all(adapter, cmd,
+						 (u32 *)rule_locs);
+		break;
+	case ETHTOOL_GRXFH:
+		ret = txgbe_get_rss_hash_opts(adapter, cmd);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int txgbe_update_ethtool_fdir_entry(struct txgbe_adapter *adapter,
+					   struct txgbe_fdir_filter *input,
+					   u16 sw_idx)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct hlist_node *node, *parent;
+	struct txgbe_fdir_filter *rule;
+	bool deleted = false;
+	s32 err;
+
+	parent = NULL;
+	rule = NULL;
+
+	hlist_for_each_entry_safe(rule, node,
+				  &adapter->fdir_filter_list, fdir_node) {
+		/* hash found, or no matching entry */
+		if (rule->sw_idx >= sw_idx)
+			break;
+		parent = node;
+	}
+
+	/* if there is an old rule occupying our place remove it */
+	if (rule && (rule->sw_idx == sw_idx)) {
+		/* hardware filters are only configured when interface is up,
+		 * and we should not issue filter commands while the interface
+		 * is down
+		 */
+		if (netif_running(adapter->netdev) &&
+		    (!input || (rule->filter.formatted.bkt_hash !=
+				input->filter.formatted.bkt_hash))) {
+			err = txgbe_fdir_erase_perfect_filter(hw,
+								&rule->filter,
+								sw_idx);
+			if (err)
+				return -EINVAL;
+		}
+
+		hlist_del(&rule->fdir_node);
+		kfree(rule);
+		adapter->fdir_filter_count--;
+		deleted = true;
+	}
+
+	/* If we weren't given an input, then this was a request to delete a
+	 * filter. We should return -EINVAL if the filter wasn't found, but
+	 * return 0 if the rule was successfully deleted.
+	 */
+	if (!input)
+		return deleted ? 0 : -EINVAL;
+
+	/* initialize node and set software index */
+	INIT_HLIST_NODE(&input->fdir_node);
+
+	/* add filter to the list */
+	if (parent)
+		hlist_add_behind(&input->fdir_node, parent);
+	else
+		hlist_add_head(&input->fdir_node,
+			       &adapter->fdir_filter_list);
+
+	/* update counts */
+	adapter->fdir_filter_count++;
+
+	return 0;
+}
+
+static int txgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
+				       u8 *flow_type)
+{
+	switch (fsp->flow_type & ~FLOW_EXT) {
+	case TCP_V4_FLOW:
+		*flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
+		break;
+	case UDP_V4_FLOW:
+		*flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
+		break;
+	case SCTP_V4_FLOW:
+		*flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
+		break;
+	case IP_USER_FLOW:
+		switch (fsp->h_u.usr_ip4_spec.proto) {
+		case IPPROTO_TCP:
+			*flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
+			break;
+		case IPPROTO_UDP:
+			*flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
+			break;
+		case IPPROTO_SCTP:
+			*flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
+			break;
+		case 0:
+			if (!fsp->m_u.usr_ip4_spec.proto) {
+				*flow_type = TXGBE_ATR_FLOW_TYPE_IPV4;
+				break;
+			}
+			fallthrough;
+		default:
+			return 0;
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+ static bool txgbe_match_ethtool_fdir_entry(struct txgbe_adapter *adapter,
+						  struct txgbe_fdir_filter *input)
+{
+	struct hlist_node *node2;
+	struct txgbe_fdir_filter *rule = NULL;
+
+	hlist_for_each_entry_safe(rule, node2,
+					 &adapter->fdir_filter_list, fdir_node) {
+		if (rule->filter.formatted.bkt_hash ==
+			input->filter.formatted.bkt_hash &&
+			rule->action == input->action) {
+			e_info(drv, "FDIR entry already exist\n");
+			return true;
+		}
+	}
+	return false;
+}
+
+static int txgbe_add_ethtool_fdir_entry(struct txgbe_adapter *adapter,
+					struct ethtool_rxnfc *cmd)
+{
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_fdir_filter *input;
+	union txgbe_atr_input mask;
+	u8 queue;
+	int err;
+	u16 ptype = 0;
+
+	if (!(adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+		return -EOPNOTSUPP;
+
+	/* ring_cookie is a masked into a set of queues and ixgbe pools or
+	 * we use drop index
+	 */
+	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
+		queue = TXGBE_RDB_FDIR_DROP_QUEUE;
+	} else {
+		u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
+		u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
+
+		if (!vf && ring >= adapter->num_rx_queues)
+			return -EINVAL;
+		else if (vf &&
+			 ((vf > adapter->num_vfs) ||
+			   ring >= adapter->num_rx_queues_per_pool))
+			return -EINVAL;
+
+		/* Map the ring onto the absolute queue index */
+		if (!vf)
+			queue = adapter->rx_ring[ring]->reg_idx;
+		else
+			queue = ((vf - 1) *
+				adapter->num_rx_queues_per_pool) + ring;
+	}
+
+
+	/* Don't allow indexes to exist outside of available space */
+	if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) {
+		e_err(drv, "Location out of range\n");
+		return -EINVAL;
+	}
+
+	input = kzalloc(sizeof(*input), GFP_ATOMIC);
+	if (!input)
+		return -ENOMEM;
+
+	memset(&mask, 0, sizeof(union txgbe_atr_input));
+
+	/* set SW index */
+	input->sw_idx = fsp->location;
+
+	/* record flow type */
+	if (!txgbe_flowspec_to_flow_type(fsp,
+					 &input->filter.formatted.flow_type)) {
+		e_err(drv, "Unrecognized flow type\n");
+		goto err_out;
+	}
+
+	mask.formatted.flow_type = TXGBE_ATR_L4TYPE_IPV6_MASK |
+				   TXGBE_ATR_L4TYPE_MASK;
+
+	if (input->filter.formatted.flow_type == TXGBE_ATR_FLOW_TYPE_IPV4)
+		mask.formatted.flow_type &= TXGBE_ATR_L4TYPE_IPV6_MASK;
+
+	/* Copy input into formatted structures */
+	input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
+	mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
+	input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
+	mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
+	input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc;
+	mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc;
+	input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
+	mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
+
+	if (fsp->flow_type & FLOW_EXT) {
+		input->filter.formatted.vm_pool =
+				(unsigned char)ntohl(fsp->h_ext.data[1]);
+		mask.formatted.vm_pool =
+				(unsigned char)ntohl(fsp->m_ext.data[1]);
+		input->filter.formatted.flex_bytes =
+						fsp->h_ext.vlan_etype;
+		mask.formatted.flex_bytes = fsp->m_ext.vlan_etype;
+#ifdef FIXED
+		/* need fix */
+		input->filter.formatted.tunnel_type =
+				(unsigned char)ntohl(fsp->h_ext.data[0]);
+		mask.formatted.tunnel_type =
+				(unsigned char)ntohl(fsp->m_ext.data[0]);
+#endif
+	}
+
+	switch (input->filter.formatted.flow_type) {
+	case TXGBE_ATR_FLOW_TYPE_TCPV4:
+		ptype = TXGBE_PTYPE_L2_IPV4_TCP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_UDPV4:
+		ptype = TXGBE_PTYPE_L2_IPV4_UDP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_SCTPV4:
+		ptype = TXGBE_PTYPE_L2_IPV4_SCTP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_IPV4:
+		ptype = TXGBE_PTYPE_L2_IPV4;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_TCPV6:
+		ptype = TXGBE_PTYPE_L2_IPV6_TCP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_UDPV6:
+		ptype = TXGBE_PTYPE_L2_IPV6_UDP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_SCTPV6:
+		ptype = TXGBE_PTYPE_L2_IPV6_SCTP;
+		break;
+	case TXGBE_ATR_FLOW_TYPE_IPV6:
+		ptype = TXGBE_PTYPE_L2_IPV6;
+		break;
+	default:
+		break;
+	}
+
+	input->filter.formatted.vlan_id = htons(ptype);
+	if (mask.formatted.flow_type & TXGBE_ATR_L4TYPE_MASK)
+		mask.formatted.vlan_id = 0xFFFF;
+	else
+		mask.formatted.vlan_id = htons(0xFFF8);
+
+	/* determine if we need to drop or route the packet */
+	if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
+		input->action = TXGBE_RDB_FDIR_DROP_QUEUE;
+	else
+		input->action = fsp->ring_cookie;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+
+	if (hlist_empty(&adapter->fdir_filter_list)) {
+		/* save mask and program input mask into HW */
+		memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
+		err = txgbe_fdir_set_input_mask(hw, &mask,
+							 adapter->cloud_mode);
+		if (err) {
+			e_err(drv, "Error writing mask\n");
+			goto err_out_w_lock;
+		}
+	} else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
+		e_err(drv, "Hardware only supports one mask per port. To change"
+		      "the mask you must first delete all the rules.\n");
+		goto err_out_w_lock;
+	}
+
+	/* apply mask and compute/store hash */
+	txgbe_atr_compute_perfect_hash(&input->filter, &mask);
+
+	/* check if new entry does not exist on filter list */
+	if (txgbe_match_ethtool_fdir_entry(adapter, input))
+		goto err_out_w_lock;
+
+	/* only program filters to hardware if the net device is running, as
+	 * we store the filters in the Rx buffer which is not allocated when
+	 * the device is down
+	 */
+	if (netif_running(adapter->netdev)) {
+		err = txgbe_fdir_write_perfect_filter(hw,
+				&input->filter, input->sw_idx,
+				queue,
+				adapter->cloud_mode);
+		if (err)
+			goto err_out_w_lock;
+	}
+
+	txgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
+
+	spin_unlock(&adapter->fdir_perfect_lock);
+
+	return err;
+err_out_w_lock:
+	spin_unlock(&adapter->fdir_perfect_lock);
+err_out:
+	kfree(input);
+	return -EINVAL;
+}
+
+static int txgbe_del_ethtool_fdir_entry(struct txgbe_adapter *adapter,
+					struct ethtool_rxnfc *cmd)
+{
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+	int err;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+	err = txgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location);
+	spin_unlock(&adapter->fdir_perfect_lock);
+
+	return err;
+}
+
+#ifdef ETHTOOL_SRXNTUPLE
+/*
+ * We need to keep this around for kernels 2.6.33 - 2.6.39 in order to avoid
+ * a null pointer dereference as it was assumend if the NETIF_F_NTUPLE flag
+ * was defined that this function was present.
+ */
+static int txgbe_set_rx_ntuple(struct net_device __always_unused *dev,
+			       struct ethtool_rx_ntuple __always_unused *cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+#define UDP_RSS_FLAGS (TXGBE_FLAG2_RSS_FIELD_IPV4_UDP | \
+		       TXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
+static int txgbe_set_rss_hash_opt(struct txgbe_adapter *adapter,
+				  struct ethtool_rxnfc *nfc)
+{
+	u32 flags2 = adapter->flags2;
+
+	/*
+	 * RSS does not support anything other than hashing
+	 * to queues on src and dst IPs and ports
+	 */
+	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
+			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
+		return -EINVAL;
+
+	switch (nfc->flow_type) {
+	case TCP_V4_FLOW:
+	case TCP_V6_FLOW:
+		if (!(nfc->data & RXH_IP_SRC) ||
+		    !(nfc->data & RXH_IP_DST) ||
+		    !(nfc->data & RXH_L4_B_0_1) ||
+		    !(nfc->data & RXH_L4_B_2_3))
+			return -EINVAL;
+		break;
+	case UDP_V4_FLOW:
+		if (!(nfc->data & RXH_IP_SRC) ||
+		    !(nfc->data & RXH_IP_DST))
+			return -EINVAL;
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			flags2 &= ~TXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			flags2 |= TXGBE_FLAG2_RSS_FIELD_IPV4_UDP;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case UDP_V6_FLOW:
+		if (!(nfc->data & RXH_IP_SRC) ||
+		    !(nfc->data & RXH_IP_DST))
+			return -EINVAL;
+		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+		case 0:
+			flags2 &= ~TXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
+			break;
+		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+			flags2 |= TXGBE_FLAG2_RSS_FIELD_IPV6_UDP;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case SCTP_V6_FLOW:
+		if (!(nfc->data & RXH_IP_SRC) ||
+		    !(nfc->data & RXH_IP_DST) ||
+		    (nfc->data & RXH_L4_B_0_1) ||
+		    (nfc->data & RXH_L4_B_2_3))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* if we changed something we need to update flags */
+	if (flags2 != adapter->flags2) {
+		struct txgbe_hw *hw = &adapter->hw;
+		u32 mrqc;
+
+		mrqc = rd32(hw, TXGBE_RDB_RA_CTL);
+
+		if ((flags2 & UDP_RSS_FLAGS) &&
+		    !(adapter->flags2 & UDP_RSS_FLAGS))
+			e_warn(drv, "enabling UDP RSS: fragmented packets"
+			       " may arrive out of order to the stack above\n");
+
+		adapter->flags2 = flags2;
+
+		/* Perform hash on these packet types */
+		mrqc |= TXGBE_RDB_RA_CTL_RSS_IPV4
+		      | TXGBE_RDB_RA_CTL_RSS_IPV4_TCP
+		      | TXGBE_RDB_RA_CTL_RSS_IPV6
+		      | TXGBE_RDB_RA_CTL_RSS_IPV6_TCP;
+
+		mrqc &= ~(TXGBE_RDB_RA_CTL_RSS_IPV4_UDP |
+			  TXGBE_RDB_RA_CTL_RSS_IPV6_UDP);
+
+		if (flags2 & TXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
+			mrqc |= TXGBE_RDB_RA_CTL_RSS_IPV4_UDP;
+
+		if (flags2 & TXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
+			mrqc |= TXGBE_RDB_RA_CTL_RSS_IPV6_UDP;
+
+		wr32(hw, TXGBE_RDB_RA_CTL, mrqc);
+	}
+
+	return 0;
+}
+
+static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_SRXCLSRLINS:
+		ret = txgbe_add_ethtool_fdir_entry(adapter, cmd);
+		break;
+	case ETHTOOL_SRXCLSRLDEL:
+		ret = txgbe_del_ethtool_fdir_entry(adapter, cmd);
+		break;
+	case ETHTOOL_SRXFH:
+		ret = txgbe_set_rss_hash_opt(adapter, cmd);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+#if defined(ETHTOOL_GRSSH) && defined(ETHTOOL_SRSSH)
+static int txgbe_rss_indir_tbl_max(struct txgbe_adapter *adapter)
+{
+	return 64;
+}
+
+
+static u32 txgbe_get_rxfh_key_size(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	return sizeof(adapter->rss_key);
+}
+
+static u32 txgbe_rss_indir_size(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	return txgbe_rss_indir_tbl_entries(adapter);
+}
+
+static void txgbe_get_reta(struct txgbe_adapter *adapter, u32 *indir)
+{
+	int i, reta_size = txgbe_rss_indir_tbl_entries(adapter);
+
+	for (i = 0; i < reta_size; i++)
+		indir[i] = adapter->rss_indir_tbl[i];
+}
+
+#ifdef HAVE_RXFH_HASHFUNC
+static int txgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+			  u8 *hfunc)
+#else /* HAVE_RXFH_HASHFUNC */
+static int txgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+#endif /* HAVE_RXFH_HASHFUNC */
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+#ifdef HAVE_RXFH_HASHFUNC
+	if (hfunc)
+		*hfunc = ETH_RSS_HASH_TOP;
+#endif
+
+	if (indir)
+		txgbe_get_reta(adapter, indir);
+	if (key)
+		memcpy(key, adapter->rss_key, txgbe_get_rxfh_key_size(netdev));
+
+	return 0;
+}
+
+#ifdef HAVE_RXFH_HASHFUNC
+static int txgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
+			  const u8 *key, const u8 hfunc)
+#else
+#ifdef HAVE_RXFH_NONCONST
+static int txgbe_set_rxfh(struct net_device *netdev, u32 *indir, u8 *key)
+#else /* HAVE_RXFH_NONCONST */
+static int txgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
+			  const u8 *key)
+#endif /* HAVE_RXFH_NONCONST */
+#endif /* HAVE_RXFH_HASHFUNC */
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int i;
+	u32 reta_entries = txgbe_rss_indir_tbl_entries(adapter);
+
+#ifdef HAVE_RXFH_HASHFUNC
+	if (hfunc)
+		return -EINVAL;
+#endif
+
+	/* Fill out the redirection table */
+	if (indir) {
+		int max_queues = min_t(int, adapter->num_rx_queues,
+				       txgbe_rss_indir_tbl_max(adapter));
+
+		/*Allow at least 2 queues w/ SR-IOV.*/
+		if ((adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) &&
+		    (max_queues < 2))
+			max_queues = 2;
+
+		/* Verify user input. */
+		for (i = 0; i < reta_entries; i++)
+			if (indir[i] >= max_queues)
+				return -EINVAL;
+
+		for (i = 0; i < reta_entries; i++)
+			adapter->rss_indir_tbl[i] = indir[i];
+	}
+
+	if (key)
+		memcpy(adapter->rss_key, key, txgbe_get_rxfh_key_size(netdev));
+
+	txgbe_store_reta(adapter);
+
+	return 0;
+}
+#endif /* ETHTOOL_GRSSH && ETHTOOL_SRSSH */
+
+#ifdef HAVE_ETHTOOL_GET_TS_INFO
+static int txgbe_get_ts_info(struct net_device *dev,
+			     struct ethtool_ts_info *info)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+
+	/* we always support timestamping disabled */
+	info->rx_filters = 1 << HWTSTAMP_FILTER_NONE;
+
+#ifdef HAVE_PTP_1588_CLOCK
+
+	info->so_timestamping =
+		SOF_TIMESTAMPING_TX_SOFTWARE |
+		SOF_TIMESTAMPING_RX_SOFTWARE |
+		SOF_TIMESTAMPING_SOFTWARE |
+		SOF_TIMESTAMPING_TX_HARDWARE |
+		SOF_TIMESTAMPING_RX_HARDWARE |
+		SOF_TIMESTAMPING_RAW_HARDWARE;
+
+	if (adapter->ptp_clock)
+		info->phc_index = ptp_clock_index(adapter->ptp_clock);
+	else
+		info->phc_index = -1;
+
+	info->tx_types =
+		(1 << HWTSTAMP_TX_OFF) |
+		(1 << HWTSTAMP_TX_ON);
+
+	info->rx_filters |=
+		(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+		(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+#endif /* HAVE_PTP_1588_CLOCK */
+	return 0;
+}
+#endif /* HAVE_ETHTOOL_GET_TS_INFO */
+
+#endif /* ETHTOOL_GRXRINGS */
+#ifdef ETHTOOL_SCHANNELS
+static unsigned int txgbe_max_channels(struct txgbe_adapter *adapter)
+{
+	unsigned int max_combined;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	if (!(adapter->flags & TXGBE_FLAG_MSIX_ENABLED)) {
+		/* We only support one q_vector without MSI-X */
+		max_combined = 1;
+	} else if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+		/* SR-IOV currently only allows one queue on the PF */
+		max_combined = 1;
+	} else if (tcs > 1) {
+		/* For DCB report channels per traffic class */
+		if (tcs > 4) {
+			/* 8 TC w/ 8 queues per TC */
+			max_combined = 8;
+		} else {
+			/* 4 TC w/ 16 queues per TC */
+			max_combined = 16;
+		}
+	} else if (adapter->atr_sample_rate) {
+		/* support up to 64 queues with ATR */
+		max_combined = TXGBE_MAX_FDIR_INDICES;
+	} else {
+		/* support up to max allowed queues with RSS */
+		max_combined = txgbe_max_rss_indices(adapter);
+	}
+
+	return max_combined;
+}
+
+static void txgbe_get_channels(struct net_device *dev,
+			       struct ethtool_channels *ch)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+
+	/* report maximum channels */
+	ch->max_combined = txgbe_max_channels(adapter);
+
+	/* report info for other vector */
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED) {
+		ch->max_other = NON_Q_VECTORS;
+		ch->other_count = NON_Q_VECTORS;
+	}
+
+	/* record RSS queues */
+	ch->combined_count = adapter->ring_feature[RING_F_RSS].indices;
+
+	/* nothing else to report if RSS is disabled */
+	if (ch->combined_count == 1)
+		return;
+
+	/* we do not support ATR queueing if SR-IOV is enabled */
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED)
+		return;
+
+	/* same thing goes for being DCB enabled */
+	if (netdev_get_num_tc(dev) > 1)
+		return;
+
+	/* if ATR is disabled we can exit */
+	if (!adapter->atr_sample_rate)
+		return;
+
+	/* report flow director queues as maximum channels */
+	ch->combined_count = adapter->ring_feature[RING_F_FDIR].indices;
+}
+
+static int txgbe_set_channels(struct net_device *dev,
+			      struct ethtool_channels *ch)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	unsigned int count = ch->combined_count;
+	u8 max_rss_indices = txgbe_max_rss_indices(adapter);
+
+	/* verify they are not requesting separate vectors */
+	if (!count || ch->rx_count || ch->tx_count)
+		return -EINVAL;
+
+	/* verify other_count has not changed */
+	if (ch->other_count != NON_Q_VECTORS)
+		return -EINVAL;
+
+	/* verify the number of channels does not exceed hardware limits */
+	if (count > txgbe_max_channels(adapter))
+		return -EINVAL;
+
+	/* update feature limits from largest to smallest supported values */
+	adapter->ring_feature[RING_F_FDIR].limit = count;
+
+	/* cap RSS limit */
+	if (count > max_rss_indices)
+		count = max_rss_indices;
+	adapter->ring_feature[RING_F_RSS].limit = count;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* cap FCoE limit at 8 */
+	if (count > TXGBE_RDB_FCRE_TBL_SIZE)
+		count = TXGBE_RDB_FCRE_TBL_SIZE;
+	adapter->ring_feature[RING_F_FCOE].limit = count;
+#endif /* CONFIG_FCOE */
+
+	/* use setup TC to update any traffic class queue mapping */
+	return txgbe_setup_tc(dev, netdev_get_num_tc(dev));
+}
+#endif /* ETHTOOL_SCHANNELS */
+
+#ifdef ETHTOOL_GMODULEINFO
+static int txgbe_get_module_info(struct net_device *dev,
+				       struct ethtool_modinfo *modinfo)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 status;
+	u8 sff8472_rev, addr_mode;
+	bool page_swap = false;
+	
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		cancel_work_sync(&adapter->sfp_sta_task);
+
+	/* Check whether we support SFF-8472 or not */
+	status = TCALL(hw, phy.ops.read_i2c_eeprom,
+					     TXGBE_SFF_SFF_8472_COMP,
+					     &sff8472_rev);
+	if (status != 0)
+		return -EIO;
+
+	/* addressing mode is not supported */
+	status = TCALL(hw, phy.ops.read_i2c_eeprom,
+					     TXGBE_SFF_SFF_8472_SWAP,
+					     &addr_mode);
+	if (status != 0)
+		return -EIO;
+
+	if (addr_mode & TXGBE_SFF_ADDRESSING_MODE) {
+		e_err(drv, "Address change required to access page 0xA2, "
+		      "but not supported. Please report the module type to the "
+		      "driver maintainers.\n");
+		page_swap = true;
+	}
+
+	if (sff8472_rev == TXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+		/* We have a SFP, but it does not support SFF-8472 */
+		modinfo->type = ETH_MODULE_SFF_8079;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+	} else {
+		/* We have a SFP which supports a revision of SFF-8472. */
+		modinfo->type = ETH_MODULE_SFF_8472;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+	}
+
+	return 0;
+}
+
+static int txgbe_get_module_eeprom(struct net_device *dev,
+					 struct ethtool_eeprom *ee,
+					 u8 *data)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 status = TXGBE_ERR_PHY_ADDR_INVALID;
+	u8 databyte = 0xFF;
+	int i = 0;
+
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		cancel_work_sync(&adapter->sfp_sta_task);
+
+	if (ee->len == 0)
+		return -EINVAL;
+
+	for (i = ee->offset; i < ee->offset + ee->len; i++) {
+		/* I2C reads can take long time */
+		if (test_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+			return -EBUSY;
+
+		if (i < ETH_MODULE_SFF_8079_LEN)
+			status = TCALL(hw, phy.ops.read_i2c_eeprom, i,
+				       &databyte);
+		else
+			status = TCALL(hw, phy.ops.read_i2c_sff8472, i,
+				       &databyte);
+
+		if (status != 0)
+			return -EIO;
+
+		data[i - ee->offset] = databyte;
+	}
+
+	return 0;
+}
+#endif /* ETHTOOL_GMODULEINFO */
+
+#ifdef ETHTOOL_GEEE
+static int txgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+	return 0;
+}
+#endif /* ETHTOOL_GEEE */
+
+#ifdef ETHTOOL_SEEE
+static int txgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	struct ethtool_eee eee_data;
+	s32 ret_val;
+
+	if (!(hw->mac.ops.setup_eee &&
+	    (adapter->flags2 & TXGBE_FLAG2_EEE_CAPABLE)))
+		return -EOPNOTSUPP;
+
+	memset(&eee_data, 0, sizeof(struct ethtool_eee));
+
+	ret_val = txgbe_get_eee(netdev, &eee_data);
+	if (ret_val)
+		return ret_val;
+
+	if (eee_data.eee_enabled && !edata->eee_enabled) {
+		if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) {
+			e_dev_err("Setting EEE tx-lpi is not supported\n");
+			return -EINVAL;
+		}
+
+		if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) {
+			e_dev_err("Setting EEE Tx LPI timer is not "
+				  "supported\n");
+			return -EINVAL;
+		}
+
+		if (eee_data.advertised != edata->advertised) {
+			e_dev_err("Setting EEE advertised speeds is not "
+				  "supported\n");
+			return -EINVAL;
+		}
+
+	}
+
+	if (eee_data.eee_enabled != edata->eee_enabled) {
+
+		if (edata->eee_enabled)
+			adapter->flags2 |= TXGBE_FLAG2_EEE_ENABLED;
+		else
+			adapter->flags2 &= ~TXGBE_FLAG2_EEE_ENABLED;
+
+		/* reset link */
+		if (netif_running(netdev))
+			txgbe_reinit_locked(adapter);
+		else
+			txgbe_reset(adapter);
+	}
+
+	return 0;
+}
+#endif /* ETHTOOL_SEEE */
+
+static int txgbe_set_flash(struct net_device *netdev, struct ethtool_flash *ef)
+{
+	int ret;
+	const struct firmware *fw;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	ret = request_firmware(&fw, ef->data, &netdev->dev);
+	if (ret < 0)
+		return ret;
+
+	if (ef->region == 0) {
+		ret = txgbe_upgrade_flash(&adapter->hw, ef->region,
+							fw->data, fw->size);
+	} else {
+		if (txgbe_mng_present(&adapter->hw)) {
+		ret = txgbe_upgrade_flash_hostif(&adapter->hw, ef->region,
+						fw->data, fw->size);
+		} else
+			ret = -EOPNOTSUPP;
+	}
+
+	release_firmware(fw);
+	if (!ret)
+		dev_info(&netdev->dev,
+			 "loaded firmware %s, reboot to make firmware work\n", ef->data);
+	return ret;
+}
+
+
+static struct ethtool_ops txgbe_ethtool_ops = {
+#ifdef ETHTOOL_COALESCE_USECS
+	.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
+#endif
+#ifdef HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
+	.get_link_ksettings = txgbe_get_link_ksettings,
+	.set_link_ksettings = txgbe_set_link_ksettings,
+#else
+	.get_settings		= txgbe_get_settings,
+	.set_settings		= txgbe_set_settings,
+#endif
+	.get_drvinfo            = txgbe_get_drvinfo,
+	.get_regs_len           = txgbe_get_regs_len,
+	.get_regs               = txgbe_get_regs,
+	.get_wol                = txgbe_get_wol,
+	.set_wol                = txgbe_set_wol,
+	.nway_reset             = txgbe_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_eeprom_len         = txgbe_get_eeprom_len,
+	.get_eeprom             = txgbe_get_eeprom,
+	.set_eeprom             = txgbe_set_eeprom,
+	.get_ringparam          = txgbe_get_ringparam,
+	.set_ringparam          = txgbe_set_ringparam,
+	.get_pauseparam         = txgbe_get_pauseparam,
+	.set_pauseparam         = txgbe_set_pauseparam,
+	.get_msglevel           = txgbe_get_msglevel,
+	.set_msglevel           = txgbe_set_msglevel,
+#ifndef HAVE_ETHTOOL_GET_SSET_COUNT
+	.self_test_count        = txgbe_diag_test_count,
+#endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+	.self_test              = txgbe_diag_test,
+	.get_strings            = txgbe_get_strings,
+#ifndef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
+#ifdef HAVE_ETHTOOL_SET_PHYS_ID
+	.set_phys_id            = txgbe_set_phys_id,
+#else
+	.phys_id                = txgbe_phys_id,
+#endif /* HAVE_ETHTOOL_SET_PHYS_ID */
+#endif /* HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT */
+#ifndef HAVE_ETHTOOL_GET_SSET_COUNT
+	.get_stats_count        = txgbe_get_stats_count,
+#else /* HAVE_ETHTOOL_GET_SSET_COUNT */
+	.get_sset_count         = txgbe_get_sset_count,
+	.get_priv_flags			= txgbe_get_priv_flags,
+	.set_priv_flags			= txgbe_set_priv_flags,
+#endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+	.get_ethtool_stats      = txgbe_get_ethtool_stats,
+#ifdef HAVE_ETHTOOL_GET_PERM_ADDR
+	.get_perm_addr          = ethtool_op_get_perm_addr,
+#endif
+	.get_coalesce           = txgbe_get_coalesce,
+	.set_coalesce           = txgbe_set_coalesce,
+#ifndef HAVE_NDO_SET_FEATURES
+	.get_rx_csum            = txgbe_get_rx_csum,
+	.set_rx_csum            = txgbe_set_rx_csum,
+	.get_tx_csum            = ethtool_op_get_tx_csum,
+	.set_tx_csum            = txgbe_set_tx_csum,
+	.get_sg                 = ethtool_op_get_sg,
+	.set_sg                 = ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
+	.get_tso                = ethtool_op_get_tso,
+	.set_tso                = txgbe_set_tso,
+#endif
+#ifdef ETHTOOL_GFLAGS
+	.get_flags              = ethtool_op_get_flags,
+	.set_flags              = txgbe_set_flags,
+#endif
+#endif /* HAVE_NDO_SET_FEATURES */
+#ifdef ETHTOOL_GRXRINGS
+	.get_rxnfc              = txgbe_get_rxnfc,
+	.set_rxnfc              = txgbe_set_rxnfc,
+#ifdef ETHTOOL_SRXNTUPLE
+	.set_rx_ntuple          = txgbe_set_rx_ntuple,
+#endif
+#endif /* ETHTOOL_GRXRINGS */
+#ifndef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
+
+#ifdef ETHTOOL_GEEE
+	.get_eee                = txgbe_get_eee,
+#endif /* ETHTOOL_GEEE */
+#ifdef ETHTOOL_SEEE
+	.set_eee                = txgbe_set_eee,
+#endif /* ETHTOOL_SEEE */
+#ifdef ETHTOOL_SCHANNELS
+	.get_channels           = txgbe_get_channels,
+	.set_channels           = txgbe_set_channels,
+#endif
+#ifdef ETHTOOL_GMODULEINFO
+	.get_module_info        = txgbe_get_module_info,
+	.get_module_eeprom      = txgbe_get_module_eeprom,
+#endif
+#ifdef HAVE_ETHTOOL_GET_TS_INFO
+	.get_ts_info            = txgbe_get_ts_info,
+#endif
+#if defined(ETHTOOL_GRSSH) && defined(ETHTOOL_SRSSH)
+	.get_rxfh_indir_size	= txgbe_rss_indir_size,
+	.get_rxfh_key_size		= txgbe_get_rxfh_key_size,
+	.get_rxfh		= txgbe_get_rxfh,
+	.set_rxfh		= txgbe_set_rxfh,
+#endif /* ETHTOOL_GRSSH && ETHTOOL_SRSSH */
+#endif /* HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT */
+	.flash_device      	= txgbe_set_flash,
+};
+
+#ifdef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
+static const struct ethtool_ops_ext txgbe_ethtool_ops_ext = {
+	.size                   = sizeof(struct ethtool_ops_ext),
+	.get_ts_info            = txgbe_get_ts_info,
+	.set_phys_id            = txgbe_set_phys_id,
+	.get_channels           = txgbe_get_channels,
+	.set_channels           = txgbe_set_channels,
+#ifdef ETHTOOL_GMODULEINFO
+	.get_module_info        = txgbe_get_module_info,
+	.get_module_eeprom      = txgbe_get_module_eeprom,
+#endif
+#if defined(ETHTOOL_GRSSH) && defined(ETHTOOL_SRSSH)
+	.get_rxfh_indir_size	= txgbe_rss_indir_size,
+	.get_rxfh_key_size	= txgbe_get_rxfh_key_size,
+	.get_rxfh		= txgbe_get_rxfh,
+	.set_rxfh		= txgbe_set_rxfh,
+#endif /* ETHTOOL_GRSSH && ETHTOOL_SRSSH */
+#ifdef ETHTOOL_GEEE
+	.get_eee                = txgbe_get_eee,
+#endif /* ETHTOOL_GEEE */
+#ifdef ETHTOOL_SEEE
+	.set_eee                = txgbe_set_eee,
+#endif /* ETHTOOL_SEEE */
+};
+
+#endif /* HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT */
+void txgbe_set_ethtool_ops(struct net_device *netdev)
+{
+#ifndef ETHTOOL_OPS_COMPAT
+	netdev->ethtool_ops = &txgbe_ethtool_ops;
+#else
+	SET_ETHTOOL_OPS(netdev, &txgbe_ethtool_ops);
+#endif
+
+#ifdef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
+	set_ethtool_ops_ext(netdev, &txgbe_ethtool_ops_ext);
+#endif /* HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT */
+}
+#endif /* SIOCETHTOOL */
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.c
new file mode 100644
index 000000000000..f9cfe1581b5b
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.c
@@ -0,0 +1,984 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_fcoe.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#include "txgbe.h"
+
+#if IS_ENABLED(CONFIG_FCOE)
+#if IS_ENABLED(CONFIG_DCB)
+#include "txgbe_dcb.h"
+#endif /* CONFIG_DCB */
+#include <linux/if_ether.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/fc/fc_fs.h>
+#include <scsi/fc/fc_fcoe.h>
+#include <scsi/libfc.h>
+#include <scsi/libfcoe.h>
+
+/**
+ * txgbe_fcoe_clear_ddp - clear the given ddp context
+ * @ddp - ptr to the txgbe_fcoe_ddp
+ *
+ * Returns : none
+ *
+ */
+static inline void txgbe_fcoe_clear_ddp(struct txgbe_fcoe_ddp *ddp)
+{
+	ddp->len = 0;
+	ddp->err = 1;
+	ddp->udl = NULL;
+	ddp->udp = 0UL;
+	ddp->sgl = NULL;
+	ddp->sgc = 0;
+}
+
+/**
+ * txgbe_fcoe_ddp_put - free the ddp context for a given xid
+ * @netdev: the corresponding net_device
+ * @xid: the xid that corresponding ddp will be freed
+ *
+ * This is the implementation of net_device_ops.ndo_fcoe_ddp_done
+ * and it is expected to be called by ULD, i.e., FCP layer of libfc
+ * to release the corresponding ddp context when the I/O is done.
+ *
+ * Returns : data length already ddp-ed in bytes
+ */
+int txgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid)
+{
+	int len = 0;
+	struct txgbe_fcoe *fcoe;
+	struct txgbe_adapter *adapter;
+	struct txgbe_hw *hw;
+	struct txgbe_fcoe_ddp *ddp;
+	u32 fcbuff;
+
+	if (!netdev)
+		goto out_ddp_put;
+
+	if (xid > netdev->fcoe_ddp_xid)
+		goto out_ddp_put;
+
+	adapter = netdev_priv(netdev);
+	hw = &adapter->hw;
+	fcoe = &adapter->fcoe;
+	ddp = &fcoe->ddp[xid];
+	if (!ddp->udl)
+		goto out_ddp_put;
+
+	len = ddp->len;
+	/* if there an error, force to invalidate ddp context */
+	if (ddp->err) {
+
+		/* other hardware requires DDP FCoE lock */
+		spin_lock_bh(&fcoe->lock);
+
+		wr32(hw, TXGBE_PSR_FC_FLT_CTXT, 0);
+		wr32(hw, TXGBE_PSR_FC_FLT_RW,
+				(xid | TXGBE_PSR_FC_FLT_RW_WE));
+		wr32(hw, TXGBE_RDM_FCBUF, 0);
+		wr32(hw, TXGBE_RDM_FCRW,
+				(xid | TXGBE_RDM_FCRW_WE));
+
+		/* read FCBUFF to check context invalidated */
+		wr32(hw, TXGBE_RDM_FCRW,
+				(xid | TXGBE_RDM_FCRW_RE));
+		fcbuff = rd32(hw, TXGBE_RDM_FCBUF);
+
+		spin_unlock_bh(&fcoe->lock);
+
+		/* guaranteed to be invalidated after 100us */
+		if (fcbuff & TXGBE_RDM_FCBUF_VALID)
+			udelay(100);
+	}
+	if (ddp->sgl)
+		dma_unmap_sg(pci_dev_to_dev(adapter->pdev), ddp->sgl, ddp->sgc,
+			     DMA_FROM_DEVICE);
+	if (ddp->pool) {
+		dma_pool_free(ddp->pool, ddp->udl, ddp->udp);
+		ddp->pool = NULL;
+	}
+
+	txgbe_fcoe_clear_ddp(ddp);
+
+out_ddp_put:
+	return len;
+}
+
+/**
+ * txgbe_fcoe_ddp_setup - called to set up ddp context
+ * @netdev: the corresponding net_device
+ * @xid: the exchange id requesting ddp
+ * @sgl: the scatter-gather list for this request
+ * @sgc: the number of scatter-gather items
+ *
+ * Returns : 1 for success and 0 for no ddp
+ */
+static int txgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
+				struct scatterlist *sgl, unsigned int sgc,
+				int target_mode)
+{
+	struct txgbe_adapter *adapter;
+	struct txgbe_hw *hw;
+	struct txgbe_fcoe *fcoe;
+	struct txgbe_fcoe_ddp *ddp;
+	struct txgbe_fcoe_ddp_pool *ddp_pool;
+	struct scatterlist *sg;
+	unsigned int i, j, dmacount;
+	unsigned int len;
+	static const unsigned int bufflen = TXGBE_FCBUFF_MIN;
+	unsigned int firstoff = 0;
+	unsigned int lastsize;
+	unsigned int thisoff = 0;
+	unsigned int thislen = 0;
+	u32 fcbuff, fcdmarw, fcfltrw, fcfltctxt;
+	dma_addr_t addr = 0;
+
+	if (!netdev || !sgl || !sgc)
+		return 0;
+
+	adapter = netdev_priv(netdev);
+	if (xid > netdev->fcoe_ddp_xid) {
+		e_warn(drv, "xid=0x%x out-of-range\n", xid);
+		return 0;
+	}
+
+	/* no DDP if we are already down or resetting */
+	if (test_bit(__TXGBE_DOWN, &adapter->state) ||
+	    test_bit(__TXGBE_RESETTING, &adapter->state))
+		return 0;
+
+	fcoe = &adapter->fcoe;
+	ddp = &fcoe->ddp[xid];
+	if (ddp->sgl) {
+		e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
+			xid, ddp->sgl, ddp->sgc);
+		return 0;
+	}
+	txgbe_fcoe_clear_ddp(ddp);
+
+
+	if (!fcoe->ddp_pool) {
+		e_warn(drv, "No ddp_pool resources allocated\n");
+		return 0;
+	}
+
+	ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu());
+	if (!ddp_pool->pool) {
+		e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid);
+		goto out_noddp;
+	}
+
+	/* setup dma from scsi command sgl */
+	dmacount = dma_map_sg(pci_dev_to_dev(adapter->pdev), sgl, sgc,
+					     DMA_FROM_DEVICE);
+	if (dmacount == 0) {
+		e_err(drv, "xid 0x%x DMA map error\n", xid);
+		goto out_noddp;
+	}
+
+	/* alloc the udl from per cpu ddp pool */
+	ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp);
+	if (!ddp->udl) {
+		e_err(drv, "failed allocated ddp context\n");
+		goto out_noddp_unmap;
+	}
+	ddp->pool = ddp_pool->pool;
+	ddp->sgl = sgl;
+	ddp->sgc = sgc;
+
+	j = 0;
+	for_each_sg(sgl, sg, dmacount, i) {
+		addr = sg_dma_address(sg);
+		len = sg_dma_len(sg);
+		while (len) {
+			/* max number of buffers allowed in one DDP context */
+			if (j >= TXGBE_BUFFCNT_MAX) {
+				ddp_pool->noddp++;
+				goto out_noddp_free;
+			}
+
+			/* get the offset of length of current buffer */
+			thisoff = addr & ((dma_addr_t)bufflen - 1);
+			thislen = min((bufflen - thisoff), len);
+			/*
+			 * all but the 1st buffer (j == 0)
+			 * must be aligned on bufflen
+			 */
+			if ((j != 0) && (thisoff))
+				goto out_noddp_free;
+			/*
+			 * all but the last buffer
+			 * ((i == (dmacount - 1)) && (thislen == len))
+			 * must end at bufflen
+			 */
+			if (((i != (dmacount - 1)) || (thislen != len))
+			    && ((thislen + thisoff) != bufflen))
+				goto out_noddp_free;
+
+			ddp->udl[j] = (u64)(addr - thisoff);
+			/* only the first buffer may have none-zero offset */
+			if (j == 0)
+				firstoff = thisoff;
+			len -= thislen;
+			addr += thislen;
+			j++;
+		}
+	}
+	/* only the last buffer may have non-full bufflen */
+	lastsize = thisoff + thislen;
+
+	/*
+	 * lastsize can not be bufflen.
+	 * If it is then adding another buffer with lastsize = 1.
+	 * Since lastsize is 1 there will be no HW access to this buffer.
+	 */
+	if (lastsize == bufflen) {
+		if (j >= TXGBE_BUFFCNT_MAX) {
+			ddp_pool->noddp_ext_buff++;
+			goto out_noddp_free;
+		}
+
+		ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
+		j++;
+		lastsize = 1;
+	}
+	put_cpu();
+
+	fcbuff = TXGBE_RDM_FCBUF_SIZE(TXGBE_FCBUFF_4KB) |
+			TXGBE_RDM_FCBUF_COUNT(j) |
+			TXGBE_RDM_FCBUF_OFFSET(firstoff) |
+			TXGBE_RDM_FCBUF_VALID;
+
+	/* Set WRCONTX bit to allow DDP for target */
+	fcfltctxt = TXGBE_PSR_FC_FLT_CTXT_VALID;
+	if (!target_mode)
+		fcfltctxt |= TXGBE_PSR_FC_FLT_CTXT_WR;
+
+	fcdmarw = xid | TXGBE_RDM_FCRW_WE |
+		  TXGBE_RDM_FCRW_LASTSIZE(lastsize);
+
+	fcfltrw = xid;
+	fcfltrw |= TXGBE_PSR_FC_FLT_RW_WE;
+
+	/* program DMA context */
+	hw = &adapter->hw;
+
+	/* turn on last frame indication for target mode as FCP_RSPtarget is
+	 * supposed to send FCP_RSP when it is done. */
+	if (target_mode && !test_bit(__TXGBE_FCOE_TARGET, &fcoe->mode)) {
+		set_bit(__TXGBE_FCOE_TARGET, &fcoe->mode);
+		wr32m(hw, TXGBE_PSR_FC_CTL,
+			TXGBE_PSR_FC_CTL_LASTSEQH, TXGBE_PSR_FC_CTL_LASTSEQH);
+	}
+
+	/* other devices require DDP lock with direct DDP context access */
+	spin_lock_bh(&fcoe->lock);
+
+	wr32(hw, TXGBE_RDM_FCPTRL, ddp->udp & DMA_BIT_MASK(32));
+	wr32(hw, TXGBE_RDM_FCPTRH, (u64)ddp->udp >> 32);
+	wr32(hw, TXGBE_RDM_FCBUF, fcbuff);
+	wr32(hw, TXGBE_RDM_FCRW, fcdmarw);
+	/* program filter context */
+	wr32(hw, TXGBE_PSR_FC_PARAM, 0);
+	wr32(hw, TXGBE_PSR_FC_FLT_CTXT, fcfltctxt);
+	wr32(hw, TXGBE_PSR_FC_FLT_RW, fcfltrw);
+
+	spin_unlock_bh(&fcoe->lock);
+
+
+	return 1;
+
+out_noddp_free:
+	dma_pool_free(ddp->pool, ddp->udl, ddp->udp);
+	txgbe_fcoe_clear_ddp(ddp);
+
+out_noddp_unmap:
+	dma_unmap_sg(pci_dev_to_dev(adapter->pdev), sgl, sgc, DMA_FROM_DEVICE);
+out_noddp:
+	put_cpu();
+	return 0;
+}
+
+/**
+ * txgbe_fcoe_ddp_get - called to set up ddp context in initiator mode
+ * @netdev: the corresponding net_device
+ * @xid: the exchange id requesting ddp
+ * @sgl: the scatter-gather list for this request
+ * @sgc: the number of scatter-gather items
+ *
+ * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup
+ * and is expected to be called from ULD, e.g., FCP layer of libfc
+ * to set up ddp for the corresponding xid of the given sglist for
+ * the corresponding I/O.
+ *
+ * Returns : 1 for success and 0 for no ddp
+ */
+int txgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
+		       struct scatterlist *sgl, unsigned int sgc)
+{
+	return txgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0);
+}
+
+#ifdef HAVE_NETDEV_OPS_FCOE_DDP_TARGET
+/**
+ * txgbe_fcoe_ddp_target - called to set up ddp context in target mode
+ * @netdev: the corresponding net_device
+ * @xid: the exchange id requesting ddp
+ * @sgl: the scatter-gather list for this request
+ * @sgc: the number of scatter-gather items
+ *
+ * This is the implementation of net_device_ops.ndo_fcoe_ddp_target
+ * and is expected to be called from ULD, e.g., FCP layer of libfc
+ * to set up ddp for the corresponding xid of the given sglist for
+ * the corresponding I/O. The DDP in target mode is a write I/O request
+ * from the initiator.
+ *
+ * Returns : 1 for success and 0 for no ddp
+ */
+int txgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid,
+			  struct scatterlist *sgl, unsigned int sgc)
+{
+	return txgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1);
+}
+
+#endif /* HAVE_NETDEV_OPS_FCOE_DDP_TARGET */
+/**
+ * txgbe_fcoe_ddp - check ddp status and mark it done
+ * @adapter: txgbe adapter
+ * @rx_desc: advanced rx descriptor
+ * @skb: the skb holding the received data
+ *
+ * This checks ddp status.
+ *
+ * Returns : < 0 indicates an error or not a FCoE ddp, 0 indicates
+ * not passing the skb to ULD, > 0 indicates is the length of data
+ * being ddped.
+ */
+int txgbe_fcoe_ddp(struct txgbe_adapter *adapter,
+		   union txgbe_rx_desc *rx_desc,
+		   struct sk_buff *skb)
+{
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+	struct txgbe_fcoe_ddp *ddp;
+	struct fc_frame_header *fh;
+	int rc = -EINVAL, ddp_max;
+	__le32 fcerr = txgbe_test_staterr(rx_desc, TXGBE_RXD_ERR_FCERR);
+	__le32 ddp_err;
+	u32 fctl;
+	u16 xid;
+
+	if (fcerr == cpu_to_le32(TXGBE_FCERR_BADCRC))
+		skb->ip_summed = CHECKSUM_NONE;
+	else
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	/* verify header contains at least the FCOE header */
+	BUG_ON(skb_headlen(skb) < FCOE_HEADER_LEN);
+
+	fh = (struct fc_frame_header *)(skb->data + sizeof(struct fcoe_hdr));
+
+	if (skb->protocol == htons(ETH_P_8021Q))
+		fh = (struct fc_frame_header *)((char *)fh + VLAN_HLEN);
+
+	fctl = ntoh24(fh->fh_f_ctl);
+	if (fctl & FC_FC_EX_CTX)
+		xid =  ntohs(fh->fh_ox_id);
+	else
+		xid =  ntohs(fh->fh_rx_id);
+
+	ddp_max = TXGBE_FCOE_DDP_MAX;
+
+	if (xid >= ddp_max)
+		goto ddp_out;
+
+	ddp = &fcoe->ddp[xid];
+	if (!ddp->udl)
+		goto ddp_out;
+
+	ddp_err = txgbe_test_staterr(rx_desc, TXGBE_RXD_ERR_FCEOFE |
+					      TXGBE_RXD_ERR_FCERR);
+	if (ddp_err)
+		goto ddp_out;
+
+	switch (txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_FCSTAT)) {
+	/* return 0 to bypass going to ULD for DDPed data */
+	case __constant_cpu_to_le32(TXGBE_RXD_STAT_FCSTAT_DDP):
+		/* update length of DDPed data */
+		ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+		rc = 0;
+		break;
+	/* unmap the sg list when FCPRSP is received */
+	case __constant_cpu_to_le32(TXGBE_RXD_STAT_FCSTAT_FCPRSP):
+		dma_unmap_sg(pci_dev_to_dev(adapter->pdev), ddp->sgl,
+			     ddp->sgc, DMA_FROM_DEVICE);
+		ddp->err = ddp_err;
+		ddp->sgl = NULL;
+		ddp->sgc = 0;
+		fallthrough;
+	/* if DDP length is present pass it through to ULD */
+	case __constant_cpu_to_le32(TXGBE_RXD_STAT_FCSTAT_NODDP):
+		/* update length of DDPed data */
+		ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+		if (ddp->len)
+			rc = ddp->len;
+		break;
+	/* no match will return as an error */
+	case __constant_cpu_to_le32(TXGBE_RXD_STAT_FCSTAT_NOMTCH):
+	default:
+		break;
+	}
+
+	/* In target mode, check the last data frame of the sequence.
+	 * For DDP in target mode, data is already DDPed but the header
+	 * indication of the last data frame ould allow is to tell if we
+	 * got all the data and the ULP can send FCP_RSP back, as this is
+	 * not a full fcoe frame, we fill the trailer here so it won't be
+	 * dropped by the ULP stack.
+	 */
+	if ((fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA) &&
+	    (fctl & FC_FC_END_SEQ)) {
+		struct fcoe_crc_eof *crc;
+		skb_linearize(skb);
+		crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc));
+		crc->fcoe_eof = FC_EOF_T;
+	}
+ddp_out:
+	return rc;
+}
+
+/**
+ * txgbe_fso - txgbe FCoE Sequence Offload (FSO)
+ * @tx_ring: tx desc ring
+ * @first: first tx_buffer structure containing skb, tx_flags, and protocol
+ * @hdr_len: hdr_len to be returned
+ *
+ * This sets up large send offload for FCoE
+ *
+ * Returns : 0 indicates success, < 0 for error
+ */
+int txgbe_fso(struct txgbe_ring *tx_ring,
+	      struct txgbe_tx_buffer *first,
+	      u8 *hdr_len)
+{
+	struct sk_buff *skb = first->skb;
+	struct fc_frame_header *fh;
+	u32 vlan_macip_lens;
+	u32 fcoe_sof_eof = 0;
+	u32 mss_l4len_idx;
+	u8 sof, eof;
+
+#ifdef NETIF_F_FSO
+	if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type != SKB_GSO_FCOE) {
+		dev_err(tx_ring->dev, "Wrong gso type %d:expecting "
+			"SKB_GSO_FCOE\n", skb_shinfo(skb)->gso_type);
+		return -EINVAL;
+	}
+
+#endif
+	/* resets the header to point fcoe/fc */
+	skb_set_network_header(skb, skb->mac_len);
+	skb_set_transport_header(skb, skb->mac_len +
+				 sizeof(struct fcoe_hdr));
+
+	/* sets up SOF and ORIS */
+	sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof;
+	switch (sof) {
+	case FC_SOF_I2:
+		fcoe_sof_eof = TXGBE_TXD_FCOEF_ORIS;
+		break;
+	case FC_SOF_I3:
+		fcoe_sof_eof = TXGBE_TXD_FCOEF_SOF |
+			       TXGBE_TXD_FCOEF_ORIS;
+		break;
+	case FC_SOF_N2:
+		break;
+	case FC_SOF_N3:
+		fcoe_sof_eof = TXGBE_TXD_FCOEF_SOF;
+		break;
+	default:
+		dev_warn(tx_ring->dev, "unknown sof = 0x%x\n", sof);
+		return -EINVAL;
+	}
+
+	/* the first byte of the last dword is EOF */
+	skb_copy_bits(skb, skb->len - 4, &eof, 1);
+	/* sets up EOF and ORIE */
+	switch (eof) {
+	case FC_EOF_N:
+		fcoe_sof_eof |= TXGBE_TXD_FCOEF_EOF_N;
+		break;
+	case FC_EOF_T:
+		/* lso needs ORIE */
+		if (skb_is_gso(skb))
+			fcoe_sof_eof |= TXGBE_TXD_FCOEF_EOF_N |
+					TXGBE_TXD_FCOEF_ORIE;
+		else
+			fcoe_sof_eof |= TXGBE_TXD_FCOEF_EOF_T;
+		break;
+	case FC_EOF_NI:
+		fcoe_sof_eof |= TXGBE_TXD_FCOEF_EOF_NI;
+		break;
+	case FC_EOF_A:
+		fcoe_sof_eof |= TXGBE_TXD_FCOEF_EOF_A;
+		break;
+	default:
+		dev_warn(tx_ring->dev, "unknown eof = 0x%x\n", eof);
+		return -EINVAL;
+	}
+
+	/* sets up PARINC indicating data offset */
+	fh = (struct fc_frame_header *)skb_transport_header(skb);
+	if (fh->fh_f_ctl[2] & FC_FC_REL_OFF)
+		fcoe_sof_eof |= TXGBE_TXD_FCOEF_PARINC;
+
+	/* include trailer in headlen as it is replicated per frame */
+	*hdr_len = sizeof(struct fcoe_crc_eof);
+
+	/* hdr_len includes fc_hdr if FCoE LSO is enabled */
+	if (skb_is_gso(skb)) {
+		*hdr_len += skb_transport_offset(skb) +
+			    sizeof(struct fc_frame_header);
+		/* update gso_segs and bytecount */
+		first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len,
+					       skb_shinfo(skb)->gso_size);
+		first->bytecount += (first->gso_segs - 1) * *hdr_len;
+		first->tx_flags |= TXGBE_TX_FLAGS_TSO;
+	}
+
+	/* set flag indicating FCOE to txgbe_tx_map call */
+	first->tx_flags |= TXGBE_TX_FLAGS_FCOE | TXGBE_TX_FLAGS_CC;
+
+	/* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */
+	mss_l4len_idx = skb_shinfo(skb)->gso_size << TXGBE_TXD_MSS_SHIFT;
+
+	/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
+	vlan_macip_lens = skb_transport_offset(skb) +
+			  sizeof(struct fc_frame_header);
+	vlan_macip_lens |= (skb_transport_offset(skb) - 4)
+			   << TXGBE_TXD_MACLEN_SHIFT;
+	vlan_macip_lens |= first->tx_flags & TXGBE_TX_FLAGS_VLAN_MASK;
+
+	/* write context desc */
+	txgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fcoe_sof_eof,
+			  TXGBE_TXD_TUCMD_FCOE, mss_l4len_idx);
+
+	return 0;
+}
+
+static void txgbe_fcoe_dma_pool_free(struct txgbe_fcoe *fcoe, unsigned int cpu)
+{
+	struct txgbe_fcoe_ddp_pool *ddp_pool;
+
+	ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu);
+	if (ddp_pool->pool)
+		dma_pool_destroy(ddp_pool->pool);
+	ddp_pool->pool = NULL;
+}
+
+static int txgbe_fcoe_dma_pool_alloc(struct txgbe_fcoe *fcoe,
+				     struct device *dev,
+				     unsigned int cpu)
+{
+	struct txgbe_fcoe_ddp_pool *ddp_pool;
+	struct dma_pool *pool;
+	char pool_name[32];
+
+	snprintf(pool_name, 32, "txgbe_fcoe_ddp_%d", cpu);
+
+	pool = dma_pool_create(pool_name, dev, TXGBE_FCPTR_MAX,
+			       TXGBE_FCPTR_ALIGN, PAGE_SIZE);
+	if (!pool)
+		return -ENOMEM;
+
+	ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu);
+	ddp_pool->pool = pool;
+	ddp_pool->noddp = 0;
+	ddp_pool->noddp_ext_buff = 0;
+
+	return 0;
+}
+
+/**
+ * txgbe_configure_fcoe - configures registers for fcoe at start
+ * @adapter: ptr to txgbe adapter
+ *
+ * This sets up FCoE related registers
+ *
+ * Returns : none
+ */
+void txgbe_configure_fcoe(struct txgbe_adapter *adapter)
+{
+	struct txgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE];
+	struct txgbe_hw *hw = &adapter->hw;
+	int i, fcoe_i;
+	u32 fcoe_q;
+	u32 etqf;
+	int fcreta_size;
+
+	/* Minimal funcionality for FCoE requires at least CRC offloads */
+	if (!(adapter->netdev->features & NETIF_F_FCOE_CRC))
+		return;
+
+	/* Enable L2 EtherType filter for FCoE, needed for FCoE CRC and DDP */
+	etqf = ETH_P_FCOE | TXGBE_PSR_ETYPE_SWC_FCOE |
+	       TXGBE_PSR_ETYPE_SWC_FILTER_EN;
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+		etqf |= TXGBE_PSR_ETYPE_SWC_POOL_ENABLE;
+		etqf |= VMDQ_P(0) << TXGBE_PSR_ETYPE_SWC_POOL_SHIFT;
+	}
+	wr32(hw,
+			TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_FCOE),
+			etqf);
+	wr32(hw,
+			TXGBE_RDB_ETYPE_CLS(TXGBE_PSR_ETYPE_SWC_FILTER_FCOE),
+			0);
+
+	/* leave remaining registers unconfigued if FCoE is disabled */
+	if (!(adapter->flags & TXGBE_FLAG_FCOE_ENABLED))
+		return;
+
+	/* Use one or more Rx queues for FCoE by redirection table */
+	fcreta_size = TXGBE_RDB_FCRE_TBL_SIZE;
+
+	for (i = 0; i < fcreta_size; i++) {
+		fcoe_i =
+		    TXGBE_RDB_FCRE_TBL_RING(fcoe->offset + (i % fcoe->indices));
+		fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx;
+		wr32(hw, TXGBE_RDB_FCRE_TBL(i), fcoe_q);
+	}
+	wr32(hw, TXGBE_RDB_FCRE_CTL, TXGBE_RDB_FCRE_CTL_ENA);
+
+	/* Enable L2 EtherType filter for FIP */
+	etqf = ETH_P_FIP | TXGBE_PSR_ETYPE_SWC_FILTER_EN;
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+		etqf |= TXGBE_PSR_ETYPE_SWC_POOL_ENABLE;
+		etqf |= VMDQ_P(0) << TXGBE_PSR_ETYPE_SWC_POOL_SHIFT;
+	}
+	wr32(hw, TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_FIP),
+			etqf);
+
+	/* Send FIP frames to the first FCoE queue */
+	fcoe_q = adapter->rx_ring[fcoe->offset]->reg_idx;
+	wr32(hw, TXGBE_RDB_ETYPE_CLS(TXGBE_PSR_ETYPE_SWC_FILTER_FIP),
+			TXGBE_RDB_ETYPE_CLS_QUEUE_EN |
+			(fcoe_q << TXGBE_RDB_ETYPE_CLS_RX_QUEUE_SHIFT));
+
+	/* Configure FCoE Rx control */
+	wr32(hw, TXGBE_PSR_FC_CTL,
+			TXGBE_PSR_FC_CTL_FCCRCBO |
+			TXGBE_PSR_FC_CTL_FCOEVER(FC_FCOE_VER) |
+			TXGBE_PSR_FC_CTL_ALLH);
+}
+
+/**
+ * txgbe_free_fcoe_ddp_resources - release all fcoe ddp context resources
+ * @adapter : txgbe adapter
+ *
+ * Cleans up outstanding ddp context resources
+ *
+ * Returns : none
+ */
+void txgbe_free_fcoe_ddp_resources(struct txgbe_adapter *adapter)
+{
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+	int cpu, i, ddp_max;
+
+	/* do nothing if no DDP pools were allocated */
+	if (!fcoe->ddp_pool)
+		return;
+
+	ddp_max = TXGBE_FCOE_DDP_MAX;
+
+	for (i = 0; i < ddp_max; i++)
+		txgbe_fcoe_ddp_put(adapter->netdev, i);
+
+	for_each_possible_cpu(cpu)
+		txgbe_fcoe_dma_pool_free(fcoe, cpu);
+
+	dma_unmap_single(pci_dev_to_dev(adapter->pdev),
+			 fcoe->extra_ddp_buffer_dma,
+			 TXGBE_FCBUFF_MIN,
+			 DMA_FROM_DEVICE);
+	kfree(fcoe->extra_ddp_buffer);
+
+	fcoe->extra_ddp_buffer = NULL;
+	fcoe->extra_ddp_buffer_dma = 0;
+}
+
+/**
+ * txgbe_setup_fcoe_ddp_resources - setup all fcoe ddp context resources
+ * @adapter: txgbe adapter
+ *
+ * Sets up ddp context resouces
+ *
+ * Returns : 0 indicates success or -EINVAL on failure
+ */
+int txgbe_setup_fcoe_ddp_resources(struct txgbe_adapter *adapter)
+{
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+	struct device *dev = pci_dev_to_dev(adapter->pdev);
+	void *buffer;
+	dma_addr_t dma;
+	unsigned int cpu;
+
+	/* do nothing if no DDP pools were allocated */
+	if (!fcoe->ddp_pool)
+		return 0;
+
+	/* Extra buffer to be shared by all DDPs for HW work around */
+	buffer = kmalloc(TXGBE_FCBUFF_MIN, GFP_ATOMIC);
+	if (!buffer) {
+		e_err(drv, "failed to allocate extra DDP buffer\n");
+		return -ENOMEM;
+	}
+
+	dma = dma_map_single(dev, buffer, TXGBE_FCBUFF_MIN, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, dma)) {
+		e_err(drv, "failed to map extra DDP buffer\n");
+		kfree(buffer);
+		return -ENOMEM;
+	}
+
+	fcoe->extra_ddp_buffer = buffer;
+	fcoe->extra_ddp_buffer_dma = dma;
+
+	/* allocate pci pool for each cpu */
+	for_each_possible_cpu(cpu) {
+		int err = txgbe_fcoe_dma_pool_alloc(fcoe, dev, cpu);
+		if (!err)
+			continue;
+
+		e_err(drv, "failed to alloc DDP pool on cpu:%d\n", cpu);
+		txgbe_free_fcoe_ddp_resources(adapter);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+#ifndef HAVE_NETDEV_OPS_FCOE_ENABLE
+int txgbe_fcoe_ddp_enable(struct txgbe_adapter *adapter)
+#else
+static int txgbe_fcoe_ddp_enable(struct txgbe_adapter *adapter)
+#endif
+{
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+
+	if (!(adapter->flags & TXGBE_FLAG_FCOE_CAPABLE))
+		return -EINVAL;
+
+	fcoe->ddp_pool = alloc_percpu(struct txgbe_fcoe_ddp_pool);
+
+	if (!fcoe->ddp_pool) {
+		e_err(drv, "failed to allocate percpu DDP resources\n");
+		return -ENOMEM;
+	}
+
+	adapter->netdev->fcoe_ddp_xid = TXGBE_FCOE_DDP_MAX - 1;
+
+	return 0;
+}
+
+#ifndef HAVE_NETDEV_OPS_FCOE_ENABLE
+void txgbe_fcoe_ddp_disable(struct txgbe_adapter *adapter)
+#else
+static void txgbe_fcoe_ddp_disable(struct txgbe_adapter *adapter)
+#endif
+{
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+
+	adapter->netdev->fcoe_ddp_xid = 0;
+
+	if (!fcoe->ddp_pool)
+		return;
+
+	free_percpu(fcoe->ddp_pool);
+	fcoe->ddp_pool = NULL;
+}
+
+#ifdef HAVE_NETDEV_OPS_FCOE_ENABLE
+/**
+ * txgbe_fcoe_enable - turn on FCoE offload feature
+ * @netdev: the corresponding netdev
+ *
+ * Turns on FCoE offload feature in sapphire.
+ *
+ * Returns : 0 indicates success or -EINVAL on failure
+ */
+int txgbe_fcoe_enable(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_fcoe *fcoe = &adapter->fcoe;
+
+	atomic_inc(&fcoe->refcnt);
+
+	if (!(adapter->flags & TXGBE_FLAG_FCOE_CAPABLE))
+		return -EINVAL;
+
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED)
+		return -EINVAL;
+
+	e_info(drv, "Enabling FCoE offload features.\n");
+
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED)
+		e_warn(probe, "Enabling FCoE on PF will disable legacy VFs\n");
+
+	if (netif_running(netdev))
+		netdev->netdev_ops->ndo_stop(netdev);
+
+	/* Allocate per CPU memory to track DDP pools */
+	txgbe_fcoe_ddp_enable(adapter);
+
+	/* enable FCoE and notify stack */
+	adapter->flags |= TXGBE_FLAG_FCOE_ENABLED;
+	netdev->features |= NETIF_F_FCOE_MTU;
+	netdev_features_change(netdev);
+
+	/* release existing queues and reallocate them */
+	txgbe_clear_interrupt_scheme(adapter);
+	txgbe_init_interrupt_scheme(adapter);
+
+	if (netif_running(netdev))
+		netdev->netdev_ops->ndo_open(netdev);
+
+	return 0;
+}
+
+/**
+ * txgbe_fcoe_disable - turn off FCoE offload feature
+ * @netdev: the corresponding netdev
+ *
+ * Turns off FCoE offload feature in sapphire.
+ *
+ * Returns : 0 indicates success or -EINVAL on failure
+ */
+int txgbe_fcoe_disable(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (!atomic_dec_and_test(&adapter->fcoe.refcnt))
+		return -EINVAL;
+
+	if (!(adapter->flags & TXGBE_FLAG_FCOE_ENABLED))
+		return -EINVAL;
+
+	e_info(drv, "Disabling FCoE offload features.\n");
+	if (netif_running(netdev))
+		netdev->netdev_ops->ndo_stop(netdev);
+
+	/* Free per CPU memory to track DDP pools */
+	txgbe_fcoe_ddp_disable(adapter);
+
+	/* disable FCoE and notify stack */
+	adapter->flags &= ~TXGBE_FLAG_FCOE_ENABLED;
+	netdev->features &= ~NETIF_F_FCOE_MTU;
+
+	netdev_features_change(netdev);
+
+	/* release existing queues and reallocate them */
+	txgbe_clear_interrupt_scheme(adapter);
+	txgbe_init_interrupt_scheme(adapter);
+
+	if (netif_running(netdev))
+		netdev->netdev_ops->ndo_open(netdev);
+
+	return 0;
+}
+#endif /* HAVE_NETDEV_OPS_FCOE_ENABLE */
+
+#if IS_ENABLED(CONFIG_DCB)
+#ifdef HAVE_DCBNL_OPS_GETAPP
+/**
+ * txgbe_fcoe_getapp - retrieves current user priority bitmap for FCoE
+ * @netdev: the corresponding net_device
+ *
+ * Finds out the corresponding user priority bitmap from the current
+ * traffic class that FCoE belongs to. Returns 0 as the invalid user
+ * priority bitmap to indicate an error.
+ *
+ * Returns : 802.1p user priority bitmap for FCoE
+ */
+u8 txgbe_fcoe_getapp(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	return 1 << adapter->fcoe.up;
+}
+#endif /* HAVE_DCBNL_OPS_GETAPP */
+#endif /* CONFIG_DCB */
+#ifdef HAVE_NETDEV_OPS_FCOE_GETWWN
+/**
+ * txgbe_fcoe_get_wwn - get world wide name for the node or the port
+ * @netdev : txgbe adapter
+ * @wwn : the world wide name
+ * @type: the type of world wide name
+ *
+ * Returns the node or port world wide name if both the prefix and the san
+ * mac address are valid, then the wwn is formed based on the NAA-2 for
+ * IEEE Extended name identifier (ref. to T10 FC-LS Spec., Sec. 15.3).
+ *
+ * Returns : 0 on success
+ */
+int txgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
+{
+	int rc = -EINVAL;
+	u16 prefix = 0xffff;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_mac_info *mac = &adapter->hw.mac;
+
+	switch (type) {
+	case NETDEV_FCOE_WWNN:
+		prefix = mac->wwnn_prefix;
+		break;
+	case NETDEV_FCOE_WWPN:
+		prefix = mac->wwpn_prefix;
+		break;
+	default:
+		break;
+	}
+
+	if ((prefix != 0xffff) &&
+	    is_valid_ether_addr(mac->san_addr)) {
+		*wwn = ((u64) prefix << 48) |
+		       ((u64) mac->san_addr[0] << 40) |
+		       ((u64) mac->san_addr[1] << 32) |
+		       ((u64) mac->san_addr[2] << 24) |
+		       ((u64) mac->san_addr[3] << 16) |
+		       ((u64) mac->san_addr[4] << 8)  |
+		       ((u64) mac->san_addr[5]);
+		rc = 0;
+	}
+	return rc;
+}
+
+#endif /* HAVE_NETDEV_OPS_FCOE_GETWWN */
+/**
+ * txgbe_fcoe_get_tc - get the current TC that fcoe is mapped to
+ * @adapter - pointer to the device adapter structure
+ *
+ * Return : TC that FCoE is mapped to
+ */
+u8 txgbe_fcoe_get_tc(struct txgbe_adapter *adapter)
+{
+	return netdev_get_prio_tc_map(adapter->netdev, adapter->fcoe.up);
+}
+#endif /* CONFIG_FCOE */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.h
new file mode 100644
index 000000000000..93ebc91c85dd
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_fcoe.h
@@ -0,0 +1,91 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_fcoe.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#ifndef _TXGBE_FCOE_H_
+#define _TXGBE_FCOE_H_
+
+#if IS_ENABLED(CONFIG_FCOE)
+
+#include <scsi/fc/fc_fs.h>
+#include <scsi/fc/fc_fcoe.h>
+
+/* shift bits within STAT fo FCSTAT */
+#define TXGBE_RXD_FCSTAT_SHIFT  4
+
+/* ddp user buffer */
+#define TXGBE_BUFFCNT_MAX       256     /* 8 bits bufcnt */
+#define TXGBE_FCPTR_ALIGN       16
+#define TXGBE_FCPTR_MAX         (TXGBE_BUFFCNT_MAX * sizeof(dma_addr_t))
+#define TXGBE_FCBUFF_4KB        0x0
+#define TXGBE_FCBUFF_8KB        0x1
+#define TXGBE_FCBUFF_16KB       0x2
+#define TXGBE_FCBUFF_64KB       0x3
+#define TXGBE_FCBUFF_MAX        65536   /* 64KB max */
+#define TXGBE_FCBUFF_MIN        4096    /* 4KB min */
+#define TXGBE_FCOE_DDP_MAX      512     /* 9 bits xid */
+
+/* Default user priority to use for FCoE */
+#define TXGBE_FCOE_DEFUP        3
+
+/* fcerr */
+#define TXGBE_FCERR_BADCRC      0x00100000
+#define TXGBE_FCERR_EOFSOF      0x00200000
+#define TXGBE_FCERR_NOFIRST     0x00300000
+#define TXGBE_FCERR_OOOSEQ      0x00400000
+#define TXGBE_FCERR_NODMA       0x00500000
+#define TXGBE_FCERR_PKTLOST     0x00600000
+
+/* FCoE DDP for target mode */
+#define __TXGBE_FCOE_TARGET     1
+
+struct txgbe_fcoe_ddp {
+	int len;
+	u32 err;
+	unsigned int sgc;
+	struct scatterlist *sgl;
+	dma_addr_t udp;
+	u64 *udl;
+	struct dma_pool *pool;
+};
+
+/* per cpu variables */
+struct txgbe_fcoe_ddp_pool {
+	struct dma_pool *pool;
+	u64 noddp;
+	u64 noddp_ext_buff;
+};
+
+struct txgbe_fcoe {
+	struct txgbe_fcoe_ddp_pool __percpu *ddp_pool;
+	atomic_t refcnt;
+	spinlock_t lock;
+	struct txgbe_fcoe_ddp ddp[TXGBE_FCOE_DDP_MAX];
+	void *extra_ddp_buffer;
+	dma_addr_t extra_ddp_buffer_dma;
+	unsigned long mode;
+	u8 up;
+	u8 up_set;
+};
+#endif /* CONFIG_FCOE */
+
+#endif /* _TXGBE_FCOE_H */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
new file mode 100644
index 000000000000..b29692c1df6d
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
@@ -0,0 +1,7399 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_82599.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe_type.h"
+#include "txgbe_hw.h"
+#include "txgbe_phy.h"
+#include "txgbe_dcb.h"
+#include "txgbe.h"
+
+#define TXGBE_SP_MAX_TX_QUEUES  128
+#define TXGBE_SP_MAX_RX_QUEUES  128
+
+#define TXGBE_SP_RAR_ENTRIES    128
+#define TXGBE_SP_MC_TBL_SIZE    128
+#define TXGBE_SP_VFT_TBL_SIZE   128
+#define TXGBE_SP_RX_PB_SIZE     512
+
+STATIC s32 txgbe_get_eeprom_semaphore(struct txgbe_hw *hw);
+STATIC void txgbe_release_eeprom_semaphore(struct txgbe_hw *hw);
+STATIC s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr);
+STATIC s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw,
+					 u16 *san_mac_offset);
+
+STATIC s32 txgbe_setup_copper_link(struct txgbe_hw *hw,
+					 u32 speed,
+					 bool autoneg_wait_to_complete);
+s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed,
+				  bool *link_up, bool link_up_wait_to_complete);
+
+
+
+u32 rd32_ephy(struct txgbe_hw *hw, u32 addr)
+{
+	unsigned int portRegOffset;
+	u32 data;
+
+	/* Set the LAN port indicator to portRegOffset[1] */
+	/* 1st, write the regOffset to IDA_ADDR register */
+	portRegOffset = TXGBE_ETHPHY_IDA_ADDR;
+	wr32(hw, portRegOffset, addr);
+
+	/* 2nd, read the data from IDA_DATA register */
+	portRegOffset = TXGBE_ETHPHY_IDA_DATA;
+	data = rd32(hw, portRegOffset);
+	return data;
+}
+
+
+u32 txgbe_rd32_epcs(struct txgbe_hw *hw, u32 addr)
+{
+	unsigned int portRegOffset;
+	u32 data;
+	/* Set the LAN port indicator to portRegOffset[1] */
+	/* 1st, write the regOffset to IDA_ADDR register */
+	portRegOffset = TXGBE_XPCS_IDA_ADDR;
+	wr32(hw, portRegOffset, addr);
+
+	/* 2nd, read the data from IDA_DATA register */
+	portRegOffset = TXGBE_XPCS_IDA_DATA;
+	data = rd32(hw, portRegOffset);
+
+	return data;
+}
+
+
+void txgbe_wr32_ephy(struct txgbe_hw *hw, u32 addr, u32 data)
+{
+	unsigned int portRegOffset;
+
+	/* Set the LAN port indicator to portRegOffset[1] */
+	/* 1st, write the regOffset to IDA_ADDR register */
+	portRegOffset = TXGBE_ETHPHY_IDA_ADDR;
+	wr32(hw, portRegOffset, addr);
+
+	/* 2nd, read the data from IDA_DATA register */
+	portRegOffset = TXGBE_ETHPHY_IDA_DATA;
+	wr32(hw, portRegOffset, data);
+}
+
+void txgbe_wr32_epcs(struct txgbe_hw *hw, u32 addr, u32 data)
+{
+	unsigned int portRegOffset;
+
+	/* Set the LAN port indicator to portRegOffset[1] */
+	/* 1st, write the regOffset to IDA_ADDR register */
+	portRegOffset = TXGBE_XPCS_IDA_ADDR;
+	wr32(hw, portRegOffset, addr);
+
+	/* 2nd, read the data from IDA_DATA register */
+	portRegOffset = TXGBE_XPCS_IDA_DATA;
+	wr32(hw, portRegOffset, data);
+}
+
+
+/**
+ * txgbe_dcb_get_rtrup2tc - read rtrup2tc reg
+ * @hw: pointer to hardware structure
+ * @map: pointer to u8 arr for returning map
+ *
+ * Read the rtrup2tc HW register and resolve its content into map
+ **/
+void txgbe_dcb_get_rtrup2tc(struct txgbe_hw *hw, u8 *map)
+{
+	u32 reg, i;
+
+	reg = rd32(hw, TXGBE_RDB_UP2TC);
+	for (i = 0; i < TXGBE_DCB_MAX_USER_PRIORITY; i++)
+		map[i] = TXGBE_RDB_UP2TC_UP_MASK &
+			(reg >> (i * TXGBE_RDB_UP2TC_UP_SHIFT));
+	return;
+}
+
+/**
+ *  txgbe_get_pcie_msix_count - Gets MSI-X vector count
+ *  @hw: pointer to hardware structure
+ *
+ *  Read PCIe configuration space, and get the MSI-X vector count from
+ *  the capabilities table.
+ **/
+u16 txgbe_get_pcie_msix_count(struct txgbe_hw *hw)
+{
+	u16 msix_count = 1;
+	u16 max_msix_count;
+	u32 pos;
+
+	max_msix_count = TXGBE_MAX_MSIX_VECTORS_SAPPHIRE;
+	pos = pci_find_capability(((struct txgbe_adapter *)hw->back)->pdev, PCI_CAP_ID_MSIX);
+	if (!pos)
+		return msix_count;
+	pci_read_config_word(((struct txgbe_adapter *)hw->back)->pdev,
+			pos + PCI_MSIX_FLAGS, &msix_count);
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		msix_count = 0;
+	msix_count &= TXGBE_PCIE_MSIX_TBL_SZ_MASK;
+
+	/* MSI-X count is zero-based in HW */
+	msix_count++;
+
+	if (msix_count > max_msix_count)
+		msix_count = max_msix_count;
+
+	return msix_count;
+}
+
+/**
+ *  txgbe_init_hw - Generic hardware initialization
+ *  @hw: pointer to hardware structure
+ *
+ *  Initialize the hardware by resetting the hardware, filling the bus info
+ *  structure and media type, clears all on chip counters, initializes receive
+ *  address registers, multicast table, VLAN filter table, calls routine to set
+ *  up link and flow control settings, and leaves transmit and receive units
+ *  disabled and uninitialized
+ **/
+s32 txgbe_init_hw(struct txgbe_hw *hw)
+{
+	s32 status;
+
+	/* Reset the hardware */
+	status = TCALL(hw, mac.ops.reset_hw);
+
+	if (status == 0) {
+		/* Start the HW */
+		status = TCALL(hw, mac.ops.start_hw);
+	}
+
+	return status;
+}
+
+
+/**
+ *  txgbe_clear_hw_cntrs - Generic clear hardware counters
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears all hardware statistics counters by reading them from the hardware
+ *  Statistics counters are clear on read.
+ **/
+s32 txgbe_clear_hw_cntrs(struct txgbe_hw *hw)
+{
+	u16 i = 0;
+
+	rd32(hw, TXGBE_RX_CRC_ERROR_FRAMES_LOW);
+	for (i = 0; i < 8; i++)
+		rd32(hw, TXGBE_RDB_MPCNT(i));
+
+	rd32(hw, TXGBE_RX_LEN_ERROR_FRAMES_LOW);
+	rd32(hw, TXGBE_RDB_LXONTXC);
+	rd32(hw, TXGBE_RDB_LXOFFTXC);
+	rd32(hw, TXGBE_MAC_LXONRXC);
+	rd32(hw, TXGBE_MAC_LXOFFRXC);
+
+	for (i = 0; i < 8; i++) {
+		rd32(hw, TXGBE_RDB_PXONTXC(i));
+		rd32(hw, TXGBE_RDB_PXOFFTXC(i));
+		rd32(hw, TXGBE_MAC_PXONRXC(i));
+		wr32m(hw, TXGBE_MMC_CONTROL, TXGBE_MMC_CONTROL_UP, i<<16);
+		rd32(hw, TXGBE_MAC_PXOFFRXC);
+	}
+	for (i = 0; i < 8; i++)
+		rd32(hw, TXGBE_RDB_PXON2OFFCNT(i));
+	for (i = 0; i < 128; i++) {
+		wr32(hw, TXGBE_PX_MPRC(i), 0);
+	}
+
+	rd32(hw, TXGBE_PX_GPRC);
+	rd32(hw, TXGBE_PX_GPTC);
+	rd32(hw, TXGBE_PX_GORC_MSB);
+	rd32(hw, TXGBE_PX_GOTC_MSB);
+
+	rd32(hw, TXGBE_RX_BC_FRAMES_GOOD_LOW);
+	rd32(hw, TXGBE_RX_UNDERSIZE_FRAMES_GOOD);
+	rd32(hw, TXGBE_RX_OVERSIZE_FRAMES_GOOD);
+	rd32(hw, TXGBE_RX_FRAME_CNT_GOOD_BAD_LOW);
+	rd32(hw, TXGBE_TX_FRAME_CNT_GOOD_BAD_LOW);
+	rd32(hw, TXGBE_TX_MC_FRAMES_GOOD_LOW);
+	rd32(hw, TXGBE_TX_BC_FRAMES_GOOD_LOW);
+	rd32(hw, TXGBE_RDM_DRP_PKT);
+	return 0;
+}
+
+/**
+ * txgbe_device_supports_autoneg_fc - Check if device supports autonegotiation
+ * of flow control
+ * @hw: pointer to hardware structure
+ *
+ * This function returns true if the device supports flow control
+ * autonegotiation, and false if it does not.
+ *
+ **/
+bool txgbe_device_supports_autoneg_fc(struct txgbe_hw *hw)
+{
+	bool supported = false;
+	u32 speed;
+	bool link_up;
+	u8 device_type = hw->subsystem_device_id & 0xF0;
+
+	switch (hw->phy.media_type) {
+	case txgbe_media_type_fiber:
+		TCALL(hw, mac.ops.check_link, &speed, &link_up, false);
+		/* if link is down, assume supported */
+		if (link_up)
+			supported = speed == TXGBE_LINK_SPEED_1GB_FULL ?
+				true : false;
+		else
+			supported = true;
+		break;
+	case txgbe_media_type_backplane:
+		supported = (device_type != TXGBE_ID_MAC_XAUI &&
+					device_type != TXGBE_ID_MAC_SGMII);
+		break;
+	case txgbe_media_type_copper:
+		/* only some copper devices support flow control autoneg */
+		supported = true;
+		break;
+	default:
+		break;
+	}
+
+	ERROR_REPORT2(TXGBE_ERROR_UNSUPPORTED,
+		      "Device %x does not support flow control autoneg",
+		      hw->device_id);
+	return supported;
+}
+
+/**
+ *  txgbe_setup_fc - Set up flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Called at init time to set up flow control.
+ **/
+s32 txgbe_setup_fc(struct txgbe_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 pcap = 0;
+	u32 value = 0;
+	u32 pcap_backplane = 0;
+
+	/* Validate the requested mode */
+	if (hw->fc.strict_ieee && hw->fc.requested_mode == txgbe_fc_rx_pause) {
+		ERROR_REPORT1(TXGBE_ERROR_UNSUPPORTED,
+			   "txgbe_fc_rx_pause not valid in strict IEEE mode\n");
+		ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS;
+		goto out;
+	}
+
+	/*
+	 * 10gig parts do not have a word in the EEPROM to determine the
+	 * default flow control setting, so we explicitly set it to full.
+	 */
+	if (hw->fc.requested_mode == txgbe_fc_default)
+		hw->fc.requested_mode = txgbe_fc_full;
+
+	/*
+	 * Set up the 1G and 10G flow control advertisement registers so the
+	 * HW will be able to do fc autoneg once the cable is plugged in.  If
+	 * we link at 10G, the 1G advertisement is harmless and vice versa.
+	 */
+
+	/*
+	 * The possible values of fc.requested_mode are:
+	 * 0: Flow control is completely disabled
+	 * 1: Rx flow control is enabled (we can receive pause frames,
+	 *    but not send pause frames).
+	 * 2: Tx flow control is enabled (we can send pause frames but
+	 *    we do not support receiving pause frames).
+	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
+	 * other: Invalid.
+	 */
+	switch (hw->fc.requested_mode) {
+	case txgbe_fc_none:
+		/* Flow control completely disabled by software override. */
+		break;
+	case txgbe_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled by software override.
+		 */
+		pcap |= TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM;
+		pcap_backplane |= TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM;
+		break;
+	case txgbe_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is
+		 * disabled by software override. Since there really
+		 * isn't a way to advertise that we are capable of RX
+		 * Pause ONLY, we will advertise that we support both
+		 * symmetric and asymmetric Rx PAUSE, as such we fall
+		 * through to the fc_full statement.  Later, we will
+		 * disable the adapter's ability to send PAUSE frames.
+		 */
+	case txgbe_fc_full:
+		/* Flow control (both Rx and Tx) is enabled by SW override. */
+		pcap |= TXGBE_SR_MII_MMD_AN_ADV_PAUSE_SYM |
+			TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM;
+		pcap_backplane |= TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_SYM |
+			TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM;
+		break;
+	default:
+		ERROR_REPORT1(TXGBE_ERROR_ARGUMENT,
+			     "Flow control param set incorrectly\n");
+		ret_val = TXGBE_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	/*
+	 * Enable auto-negotiation between the MAC & PHY;
+	 * the MAC will advertise clause 37 flow control.
+	 */
+	value = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_AN_ADV);
+	value = (value & ~(TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM |
+		TXGBE_SR_MII_MMD_AN_ADV_PAUSE_SYM)) | pcap;
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_AN_ADV, value);
+
+	/*
+	 * AUTOC restart handles negotiation of 1G and 10G on backplane
+	 * and copper.
+	 */
+	if (hw->phy.media_type == txgbe_media_type_backplane) {
+		value = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG1);
+		value = (value & ~(TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM |
+			TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_SYM)) |
+			pcap_backplane;
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG1, value);
+
+	} else if ((hw->phy.media_type == txgbe_media_type_copper) &&
+		   (txgbe_device_supports_autoneg_fc(hw))) {
+		ret_val = txgbe_set_phy_pause_advertisement(hw, pcap_backplane);
+	}
+out:
+	return ret_val;
+}
+
+/**
+ *  txgbe_read_pba_string - Reads part number string from EEPROM
+ *  @hw: pointer to hardware structure
+ *  @pba_num: stores the part number string from the EEPROM
+ *  @pba_num_size: part number string buffer length
+ *
+ *  Reads the part number string from the EEPROM.
+ **/
+s32 txgbe_read_pba_string(struct txgbe_hw *hw, u8 *pba_num,
+				  u32 pba_num_size)
+{
+	s32 ret_val;
+	u16 data;
+	u16 pba_ptr;
+	u16 offset;
+	u16 length;
+
+	if (pba_num == NULL) {
+		DEBUGOUT("PBA string buffer was null\n");
+		return TXGBE_ERR_INVALID_ARGUMENT;
+	}
+
+	ret_val = TCALL(hw, eeprom.ops.read,
+			hw->eeprom.sw_region_offset + TXGBE_PBANUM0_PTR,
+			&data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		return ret_val;
+	}
+
+	ret_val = TCALL(hw, eeprom.ops.read,
+			hw->eeprom.sw_region_offset + TXGBE_PBANUM1_PTR,
+			&pba_ptr);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		return ret_val;
+	}
+
+	/*
+	 * if data is not ptr guard the PBA must be in legacy format which
+	 * means pba_ptr is actually our second data word for the PBA number
+	 * and we can decode it into an ascii string
+	 */
+	if (data != TXGBE_PBANUM_PTR_GUARD) {
+		DEBUGOUT("NVM PBA number is not stored as string\n");
+
+		/* we will need 11 characters to store the PBA */
+		if (pba_num_size < 11) {
+			DEBUGOUT("PBA string buffer too small\n");
+			return TXGBE_ERR_NO_SPACE;
+		}
+
+		/* extract hex string from data and pba_ptr */
+		pba_num[0] = (data >> 12) & 0xF;
+		pba_num[1] = (data >> 8) & 0xF;
+		pba_num[2] = (data >> 4) & 0xF;
+		pba_num[3] = data & 0xF;
+		pba_num[4] = (pba_ptr >> 12) & 0xF;
+		pba_num[5] = (pba_ptr >> 8) & 0xF;
+		pba_num[6] = '-';
+		pba_num[7] = 0;
+		pba_num[8] = (pba_ptr >> 4) & 0xF;
+		pba_num[9] = pba_ptr & 0xF;
+
+		/* put a null character on the end of our string */
+		pba_num[10] = '\0';
+
+		/* switch all the data but the '-' to hex char */
+		for (offset = 0; offset < 10; offset++) {
+			if (pba_num[offset] < 0xA)
+				pba_num[offset] += '0';
+			else if (pba_num[offset] < 0x10)
+				pba_num[offset] += 'A' - 0xA;
+		}
+
+		return 0;
+	}
+
+	ret_val = TCALL(hw, eeprom.ops.read, pba_ptr, &length);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		return ret_val;
+	}
+
+	if (length == 0xFFFF || length == 0) {
+		DEBUGOUT("NVM PBA number section invalid length\n");
+		return TXGBE_ERR_PBA_SECTION;
+	}
+
+	/* check if pba_num buffer is big enough */
+	if (pba_num_size  < (((u32)length * 2) - 1)) {
+		DEBUGOUT("PBA string buffer too small\n");
+		return TXGBE_ERR_NO_SPACE;
+	}
+
+	/* trim pba length from start of string */
+	pba_ptr++;
+	length--;
+
+	for (offset = 0; offset < length; offset++) {
+		ret_val = TCALL(hw, eeprom.ops.read, pba_ptr + offset, &data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			return ret_val;
+		}
+		pba_num[offset * 2] = (u8)(data >> 8);
+		pba_num[(offset * 2) + 1] = (u8)(data & 0xFF);
+	}
+	pba_num[offset * 2] = '\0';
+
+	return 0;
+}
+
+/**
+ *  txgbe_get_mac_addr - Generic get MAC address
+ *  @hw: pointer to hardware structure
+ *  @mac_addr: Adapter MAC address
+ *
+ *  Reads the adapter's MAC address from first Receive Address Register (RAR0)
+ *  A reset of the adapter must be performed prior to calling this function
+ *  in order for the MAC address to have been loaded from the EEPROM into RAR0
+ **/
+s32 txgbe_get_mac_addr(struct txgbe_hw *hw, u8 *mac_addr)
+{
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_IDX, 0);
+	rar_high = rd32(hw, TXGBE_PSR_MAC_SWC_AD_H);
+	rar_low = rd32(hw, TXGBE_PSR_MAC_SWC_AD_L);
+
+	for (i = 0; i < 2; i++)
+		mac_addr[i] = (u8)(rar_high >> (1 - i) * 8);
+
+	for (i = 0; i < 4; i++)
+		mac_addr[i + 2] = (u8)(rar_low >> (3 - i) * 8);
+
+	return 0;
+}
+
+/**
+ *  txgbe_set_pci_config_data - Generic store PCI bus info
+ *  @hw: pointer to hardware structure
+ *  @link_status: the link status returned by the PCI config space
+ *
+ *  Stores the PCI bus info (speed, width, type) within the txgbe_hw structure
+ **/
+void txgbe_set_pci_config_data(struct txgbe_hw *hw, u16 link_status)
+{
+	if (hw->bus.type == txgbe_bus_type_unknown)
+		hw->bus.type = txgbe_bus_type_pci_express;
+
+	switch (link_status & TXGBE_PCI_LINK_WIDTH) {
+	case TXGBE_PCI_LINK_WIDTH_1:
+		hw->bus.width = txgbe_bus_width_pcie_x1;
+		break;
+	case TXGBE_PCI_LINK_WIDTH_2:
+		hw->bus.width = txgbe_bus_width_pcie_x2;
+		break;
+	case TXGBE_PCI_LINK_WIDTH_4:
+		hw->bus.width = txgbe_bus_width_pcie_x4;
+		break;
+	case TXGBE_PCI_LINK_WIDTH_8:
+		hw->bus.width = txgbe_bus_width_pcie_x8;
+		break;
+	default:
+		hw->bus.width = txgbe_bus_width_unknown;
+		break;
+	}
+
+	switch (link_status & TXGBE_PCI_LINK_SPEED) {
+	case TXGBE_PCI_LINK_SPEED_2500:
+		hw->bus.speed = txgbe_bus_speed_2500;
+		break;
+	case TXGBE_PCI_LINK_SPEED_5000:
+		hw->bus.speed = txgbe_bus_speed_5000;
+		break;
+	case TXGBE_PCI_LINK_SPEED_8000:
+		hw->bus.speed = txgbe_bus_speed_8000;
+		break;
+	default:
+		hw->bus.speed = txgbe_bus_speed_unknown;
+		break;
+	}
+
+}
+
+/**
+ *  txgbe_get_bus_info - Generic set PCI bus info
+ *  @hw: pointer to hardware structure
+ *
+ *  Gets the PCI bus info (speed, width, type) then calls helper function to
+ *  store this data within the txgbe_hw structure.
+ **/
+s32 txgbe_get_bus_info(struct txgbe_hw *hw)
+{
+	u16 link_status;
+
+	/* Get the negotiated link width and speed from PCI config space */
+	link_status = TXGBE_READ_PCIE_WORD(hw, TXGBE_PCI_LINK_STATUS);
+
+	txgbe_set_pci_config_data(hw, link_status);
+
+	return 0;
+}
+
+/**
+ *  txgbe_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+void txgbe_set_lan_id_multi_port_pcie(struct txgbe_hw *hw)
+{
+	struct txgbe_bus_info *bus = &hw->bus;
+	u32 reg;
+
+	reg = rd32(hw, TXGBE_CFG_PORT_ST);
+	bus->lan_id = TXGBE_CFG_PORT_ST_LAN_ID(reg);
+
+	/* check for a port swap */
+	reg = rd32(hw, TXGBE_MIS_PWR);
+	if (TXGBE_MIS_PWR_LAN_ID_1 == TXGBE_MIS_PWR_LAN_ID(reg))
+		bus->func = 0;
+	else
+		bus->func = bus->lan_id;
+}
+
+/**
+ *  txgbe_stop_adapter - Generic stop Tx/Rx units
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the adapter_stopped flag within txgbe_hw struct. Clears interrupts,
+ *  disables transmit and receive units. The adapter_stopped flag is used by
+ *  the shared code and drivers to determine if the adapter is in a stopped
+ *  state and should not touch the hardware.
+ **/
+s32 txgbe_stop_adapter(struct txgbe_hw *hw)
+{
+	u16 i;
+
+	/*
+	 * Set the adapter_stopped flag so other driver functions stop touching
+	 * the hardware
+	 */
+	hw->adapter_stopped = true;
+
+	/* Disable the receive unit */
+	TCALL(hw, mac.ops.disable_rx);
+
+	/* Set interrupt mask to stop interrupts from being generated */
+	txgbe_intr_disable(hw, TXGBE_INTR_ALL);
+
+	/* Clear any pending interrupts, flush previous writes */
+	wr32(hw, TXGBE_PX_MISC_IC, 0xffffffff);
+	wr32(hw, TXGBE_BME_CTL, 0x3);
+
+	/* Disable the transmit unit.  Each queue must be disabled. */
+	for (i = 0; i < hw->mac.max_tx_queues; i++) {
+		wr32m(hw, TXGBE_PX_TR_CFG(i),
+			TXGBE_PX_TR_CFG_SWFLSH | TXGBE_PX_TR_CFG_ENABLE,
+			TXGBE_PX_TR_CFG_SWFLSH);
+	}
+
+	/* Disable the receive unit by stopping each queue */
+	for (i = 0; i < hw->mac.max_rx_queues; i++) {
+		wr32m(hw, TXGBE_PX_RR_CFG(i),
+			TXGBE_PX_RR_CFG_RR_EN, 0);
+	}
+
+	/* flush all queues disables */
+	TXGBE_WRITE_FLUSH(hw);
+
+	/*
+	 * Prevent the PCI-E bus from hanging by disabling PCI-E master
+	 * access and verify no pending requests
+	 */
+	return txgbe_disable_pcie_master(hw);
+}
+
+/**
+ *  txgbe_led_on - Turns on the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn on
+ **/
+s32 txgbe_led_on(struct txgbe_hw *hw, u32 index)
+{
+	u32 led_reg = rd32(hw, TXGBE_CFG_LED_CTL);
+	u16 value = 0;
+	
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) {
+		txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, &value);
+		txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, (value & 0xFFFC) | 0x0);
+	}
+	/* To turn on the LED, set mode to ON. */
+	led_reg |= index | (index << TXGBE_CFG_LED_CTL_LINK_OD_SHIFT);
+	wr32(hw, TXGBE_CFG_LED_CTL, led_reg);
+	TXGBE_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+/**
+ *  txgbe_led_off - Turns off the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn off
+ **/
+s32 txgbe_led_off(struct txgbe_hw *hw, u32 index)
+{
+	u32 led_reg = rd32(hw, TXGBE_CFG_LED_CTL);
+	u16 value = 0;
+
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) {
+		txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, &value);
+		txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xF021, (value & 0xFFFC) | 0x1);
+	}
+
+	/* To turn off the LED, set mode to OFF. */
+	led_reg &= ~(index << TXGBE_CFG_LED_CTL_LINK_OD_SHIFT);
+	led_reg |= index;
+	wr32(hw, TXGBE_CFG_LED_CTL, led_reg);
+	TXGBE_WRITE_FLUSH(hw);
+	return 0;
+}
+
+/**
+ *  txgbe_get_eeprom_semaphore - Get hardware semaphore
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the hardware semaphores so EEPROM access can occur for bit-bang method
+ **/
+STATIC s32 txgbe_get_eeprom_semaphore(struct txgbe_hw *hw)
+{
+	s32 status = TXGBE_ERR_EEPROM;
+	u32 timeout = 2000;
+	u32 i;
+	u32 swsm;
+
+	/* Get SMBI software semaphore between device drivers first */
+	for (i = 0; i < timeout; i++) {
+		/*
+		 * If the SMBI bit is 0 when we read it, then the bit will be
+		 * set and we have the semaphore
+		 */
+		swsm = rd32(hw, TXGBE_MIS_SWSM);
+		if (!(swsm & TXGBE_MIS_SWSM_SMBI)) {
+			status = 0;
+			break;
+		}
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access the Eeprom - SMBI Semaphore "
+			 "not granted.\n");
+		/*
+		 * this release is particularly important because our attempts
+		 * above to get the semaphore may have succeeded, and if there
+		 * was a timeout, we should unconditionally clear the semaphore
+		 * bits to free the driver to make progress
+		 */
+		txgbe_release_eeprom_semaphore(hw);
+
+		usec_delay(50);
+		/*
+		 * one last try
+		 * If the SMBI bit is 0 when we read it, then the bit will be
+		 * set and we have the semaphore
+		 */
+		swsm = rd32(hw, TXGBE_MIS_SWSM);
+		if (!(swsm & TXGBE_MIS_SWSM_SMBI))
+			status = 0;
+	}
+
+	/* Now get the semaphore between SW/FW through the SWESMBI bit */
+	if (status == 0) {
+		for (i = 0; i < timeout; i++) {
+			if (txgbe_check_mng_access(hw)) {
+			/* Set the SW EEPROM semaphore bit to request access */
+				wr32m(hw, TXGBE_MNG_SW_SM,
+					TXGBE_MNG_SW_SM_SM, TXGBE_MNG_SW_SM_SM);
+
+				/*
+				 * If we set the bit successfully then we got
+				 * semaphore.
+				 */
+				swsm = rd32(hw, TXGBE_MNG_SW_SM);
+				if (swsm & TXGBE_MNG_SW_SM_SM)
+					break;
+			}
+			usec_delay(50);
+		}
+
+		/*
+		 * Release semaphores and return error if SW EEPROM semaphore
+		 * was not granted because we don't have access to the EEPROM
+		 */
+		if (i >= timeout) {
+			ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			    "SWESMBI Software EEPROM semaphore not granted.\n");
+			txgbe_release_eeprom_semaphore(hw);
+			status = TXGBE_ERR_EEPROM;
+		}
+	} else {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			     "Software semaphore SMBI between device drivers "
+			     "not granted.\n");
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_release_eeprom_semaphore - Release hardware semaphore
+ *  @hw: pointer to hardware structure
+ *
+ *  This function clears hardware semaphore bits.
+ **/
+STATIC void txgbe_release_eeprom_semaphore(struct txgbe_hw *hw)
+{
+	if (txgbe_check_mng_access(hw)) {
+		wr32m(hw, TXGBE_MNG_SW_SM,
+			TXGBE_MNG_SW_SM_SM, 0);
+		wr32m(hw, TXGBE_MIS_SWSM,
+			TXGBE_MIS_SWSM_SMBI, 0);
+		TXGBE_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  txgbe_validate_mac_addr - Validate MAC address
+ *  @mac_addr: pointer to MAC address.
+ *
+ *  Tests a MAC address to ensure it is a valid Individual Address
+ **/
+s32 txgbe_validate_mac_addr(u8 *mac_addr)
+{
+	s32 status = 0;
+
+	/* Make sure it is not a multicast address */
+	if (TXGBE_IS_MULTICAST(mac_addr)) {
+		DEBUGOUT("MAC address is multicast\n");
+		status = TXGBE_ERR_INVALID_MAC_ADDR;
+	/* Not a broadcast address */
+	} else if (TXGBE_IS_BROADCAST(mac_addr)) {
+		DEBUGOUT("MAC address is broadcast\n");
+		status = TXGBE_ERR_INVALID_MAC_ADDR;
+	/* Reject the zero address */
+	} else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
+		   mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) {
+		DEBUGOUT("MAC address is all zeros\n");
+		status = TXGBE_ERR_INVALID_MAC_ADDR;
+	}
+	return status;
+}
+
+/**
+ *  txgbe_set_rar - Set Rx address register
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *  @addr: Address to put into receive address register
+ *  @vmdq: VMDq "set" or "pool" index
+ *  @enable_addr: set flag that address is active
+ *
+ *  Puts an ethernet address into a receive address register.
+ **/
+s32 txgbe_set_rar(struct txgbe_hw *hw, u32 index, u8 *addr, u64 pools,
+			  u32 enable_addr)
+{
+	u32 rar_low, rar_high;
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	/* Make sure we are using a valid rar index range */
+	if (index >= rar_entries) {
+		ERROR_REPORT2(TXGBE_ERROR_ARGUMENT,
+			     "RAR index %d is out of range.\n", index);
+		return TXGBE_ERR_INVALID_ARGUMENT;
+	}
+
+	/* select the MAC address */
+	wr32(hw, TXGBE_PSR_MAC_SWC_IDX, index);
+
+	/* setup VMDq pool mapping */
+	wr32(hw, TXGBE_PSR_MAC_SWC_VM_L, pools & 0xFFFFFFFF);
+	wr32(hw, TXGBE_PSR_MAC_SWC_VM_H, pools >> 32);
+
+	/*
+	 * HW expects these in little endian so we reverse the byte
+	 * order from network order (big endian) to little endian
+	 *
+	 * Some parts put the VMDq setting in the extra RAH bits,
+	 * so save everything except the lower 16 bits that hold part
+	 * of the address and the address valid bit.
+	 */
+	rar_low = ((u32)addr[5] |
+		  ((u32)addr[4] << 8) |
+		  ((u32)addr[3] << 16) |
+		  ((u32)addr[2] << 24));
+	rar_high = ((u32)addr[1] |
+		   ((u32)addr[0] << 8));
+	if (enable_addr != 0)
+		rar_high |= TXGBE_PSR_MAC_SWC_AD_H_AV;
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_AD_L, rar_low);
+	wr32m(hw, TXGBE_PSR_MAC_SWC_AD_H,
+		(TXGBE_PSR_MAC_SWC_AD_H_AD(~0) |
+		 TXGBE_PSR_MAC_SWC_AD_H_ADTYPE(~0) |
+		 TXGBE_PSR_MAC_SWC_AD_H_AV),
+		rar_high);
+
+	return 0;
+}
+
+/**
+ *  txgbe_clear_rar - Remove Rx address register
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *
+ *  Clears an ethernet address from a receive address register.
+ **/
+s32 txgbe_clear_rar(struct txgbe_hw *hw, u32 index)
+{
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	/* Make sure we are using a valid rar index range */
+	if (index >= rar_entries) {
+		ERROR_REPORT2(TXGBE_ERROR_ARGUMENT,
+			     "RAR index %d is out of range.\n", index);
+		return TXGBE_ERR_INVALID_ARGUMENT;
+	}
+
+	/*
+	 * Some parts put the VMDq setting in the extra RAH bits,
+	 * so save everything except the lower 16 bits that hold part
+	 * of the address and the address valid bit.
+	 */
+	wr32(hw, TXGBE_PSR_MAC_SWC_IDX, index);
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_VM_L, 0);
+	wr32(hw, TXGBE_PSR_MAC_SWC_VM_H, 0);
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_AD_L, 0);
+	wr32m(hw, TXGBE_PSR_MAC_SWC_AD_H,
+		(TXGBE_PSR_MAC_SWC_AD_H_AD(~0) |
+		 TXGBE_PSR_MAC_SWC_AD_H_ADTYPE(~0) |
+		 TXGBE_PSR_MAC_SWC_AD_H_AV),
+		0);
+
+	return 0;
+}
+
+/**
+ *  txgbe_init_rx_addrs - Initializes receive address filters.
+ *  @hw: pointer to hardware structure
+ *
+ *  Places the MAC address in receive address register 0 and clears the rest
+ *  of the receive address registers. Clears the multicast table. Assumes
+ *  the receiver is in reset when the routine is called.
+ **/
+s32 txgbe_init_rx_addrs(struct txgbe_hw *hw)
+{
+	u32 i;
+	u32 rar_entries = hw->mac.num_rar_entries;
+	u32 psrctl;
+
+	/*
+	 * If the current mac address is valid, assume it is a software override
+	 * to the permanent address.
+	 * Otherwise, use the permanent address from the eeprom.
+	 */
+	if (txgbe_validate_mac_addr(hw->mac.addr) ==
+		TXGBE_ERR_INVALID_MAC_ADDR) {
+		/* Get the MAC address from the RAR0 for later reference */
+		TCALL(hw, mac.ops.get_mac_addr, hw->mac.addr);
+
+		DEBUGOUT3(" Keeping Current RAR0 Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
+			hw->mac.addr[0], hw->mac.addr[1],
+			hw->mac.addr[2], hw->mac.addr[3],
+			hw->mac.addr[4], hw->mac.addr[5]);
+	} else {
+		/* Setup the receive address. */
+		DEBUGOUT("Overriding MAC Address in RAR[0]\n");
+		DEBUGOUT3(" New MAC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
+			hw->mac.addr[0], hw->mac.addr[1],
+			hw->mac.addr[2], hw->mac.addr[3],
+			hw->mac.addr[4], hw->mac.addr[5]);
+
+		TCALL(hw, mac.ops.set_rar, 0, hw->mac.addr, 0,
+			TXGBE_PSR_MAC_SWC_AD_H_AV);
+
+		/* clear VMDq pool/queue selection for RAR 0 */
+		TCALL(hw, mac.ops.clear_vmdq, 0, TXGBE_CLEAR_VMDQ_ALL);
+	}
+	hw->addr_ctrl.overflow_promisc = 0;
+
+	hw->addr_ctrl.rar_used_count = 1;
+
+	/* Zero out the other receive addresses. */
+	DEBUGOUT1("Clearing RAR[1-%d]\n", rar_entries - 1);
+	for (i = 1; i < rar_entries; i++) {
+		wr32(hw, TXGBE_PSR_MAC_SWC_IDX, i);
+		wr32(hw, TXGBE_PSR_MAC_SWC_AD_L, 0);
+		wr32(hw, TXGBE_PSR_MAC_SWC_AD_H, 0);
+	}
+
+	/* Clear the MTA */
+	hw->addr_ctrl.mta_in_use = 0;
+	psrctl = rd32(hw, TXGBE_PSR_CTL);
+	psrctl &= ~(TXGBE_PSR_CTL_MO | TXGBE_PSR_CTL_MFE);
+	psrctl |= hw->mac.mc_filter_type << TXGBE_PSR_CTL_MO_SHIFT;
+	wr32(hw, TXGBE_PSR_CTL, psrctl);
+	DEBUGOUT(" Clearing MTA\n");
+	for (i = 0; i < hw->mac.mcft_size; i++)
+		wr32(hw, TXGBE_PSR_MC_TBL(i), 0);
+
+	TCALL(hw, mac.ops.init_uta_tables);
+
+	return 0;
+}
+
+/**
+ *  txgbe_add_uc_addr - Adds a secondary unicast address.
+ *  @hw: pointer to hardware structure
+ *  @addr: new address
+ *
+ *  Adds it to unused receive address register or goes into promiscuous mode.
+ **/
+void txgbe_add_uc_addr(struct txgbe_hw *hw, u8 *addr, u32 vmdq)
+{
+	u32 rar_entries = hw->mac.num_rar_entries;
+	u32 rar;
+
+	DEBUGOUT6(" UC Addr = %.2X %.2X %.2X %.2X %.2X %.2X\n",
+		  addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+	/*
+	 * Place this address in the RAR if there is room,
+	 * else put the controller into promiscuous mode
+	 */
+	if (hw->addr_ctrl.rar_used_count < rar_entries) {
+		rar = hw->addr_ctrl.rar_used_count;
+		TCALL(hw, mac.ops.set_rar, rar, addr, vmdq,
+			TXGBE_PSR_MAC_SWC_AD_H_AV);
+		DEBUGOUT1("Added a secondary address to RAR[%d]\n", rar);
+		hw->addr_ctrl.rar_used_count++;
+	} else {
+		hw->addr_ctrl.overflow_promisc++;
+	}
+
+	DEBUGOUT("txgbe_add_uc_addr Complete\n");
+}
+
+/**
+ *  txgbe_update_uc_addr_list - Updates MAC list of secondary addresses
+ *  @hw: pointer to hardware structure
+ *  @addr_list: the list of new addresses
+ *  @addr_count: number of addresses
+ *  @next: iterator function to walk the address list
+ *
+ *  The given list replaces any existing list.  Clears the secondary addrs from
+ *  receive address registers.  Uses unused receive address registers for the
+ *  first secondary addresses, and falls back to promiscuous mode as needed.
+ *
+ *  Drivers using secondary unicast addresses must set user_set_promisc when
+ *  manually putting the device into promiscuous mode.
+ **/
+s32 txgbe_update_uc_addr_list(struct txgbe_hw *hw, u8 *addr_list,
+				      u32 addr_count, txgbe_mc_addr_itr next)
+{
+	u8 *addr;
+	u32 i;
+	u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc;
+	u32 uc_addr_in_use;
+	u32 vmdq;
+
+	/*
+	 * Clear accounting of old secondary address list,
+	 * don't count RAR[0]
+	 */
+	uc_addr_in_use = hw->addr_ctrl.rar_used_count - 1;
+	hw->addr_ctrl.rar_used_count -= uc_addr_in_use;
+	hw->addr_ctrl.overflow_promisc = 0;
+
+	/* Zero out the other receive addresses */
+	DEBUGOUT1("Clearing RAR[1-%d]\n", uc_addr_in_use+1);
+	for (i = 0; i < uc_addr_in_use; i++) {
+		wr32(hw, TXGBE_PSR_MAC_SWC_IDX, 1+i);
+		wr32(hw, TXGBE_PSR_MAC_SWC_AD_L, 0);
+		wr32(hw, TXGBE_PSR_MAC_SWC_AD_H, 0);
+	}
+
+	/* Add the new addresses */
+	for (i = 0; i < addr_count; i++) {
+		DEBUGOUT(" Adding the secondary addresses:\n");
+		addr = next(hw, &addr_list, &vmdq);
+		txgbe_add_uc_addr(hw, addr, vmdq);
+	}
+
+	if (hw->addr_ctrl.overflow_promisc) {
+		/* enable promisc if not already in overflow or set by user */
+		if (!old_promisc_setting && !hw->addr_ctrl.user_set_promisc) {
+			DEBUGOUT(" Entering address overflow promisc mode\n");
+			wr32m(hw, TXGBE_PSR_CTL,
+				TXGBE_PSR_CTL_UPE, TXGBE_PSR_CTL_UPE);
+		}
+	} else {
+		/* only disable if set by overflow, not by user */
+		if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) {
+			DEBUGOUT(" Leaving address overflow promisc mode\n");
+			wr32m(hw, TXGBE_PSR_CTL,
+				TXGBE_PSR_CTL_UPE, 0);
+		}
+	}
+
+	DEBUGOUT("txgbe_update_uc_addr_list Complete\n");
+	return 0;
+}
+
+/**
+ *  txgbe_mta_vector - Determines bit-vector in multicast table to set
+ *  @hw: pointer to hardware structure
+ *  @mc_addr: the multicast address
+ *
+ *  Extracts the 12 bits, from a multicast address, to determine which
+ *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ *  incoming rx multicast addresses, to determine the bit-vector to check in
+ *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ *  by the MO field of the MCSTCTRL. The MO field is set during initialization
+ *  to mc_filter_type.
+ **/
+STATIC s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr)
+{
+	u32 vector = 0;
+
+	switch (hw->mac.mc_filter_type) {
+	case 0:   /* use bits [47:36] of the address */
+		vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+		break;
+	case 1:   /* use bits [46:35] of the address */
+		vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+		break;
+	case 2:   /* use bits [45:34] of the address */
+		vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+		break;
+	case 3:   /* use bits [43:32] of the address */
+		vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+		break;
+	default:  /* Invalid mc_filter_type */
+		DEBUGOUT("MC filter type param set incorrectly\n");
+		ASSERT(0);
+		break;
+	}
+
+	/* vector can only be 12-bits or boundary will be exceeded */
+	vector &= 0xFFF;
+	return vector;
+}
+
+/**
+ *  txgbe_set_mta - Set bit-vector in multicast table
+ *  @hw: pointer to hardware structure
+ *  @hash_value: Multicast address hash value
+ *
+ *  Sets the bit-vector in the multicast table.
+ **/
+void txgbe_set_mta(struct txgbe_hw *hw, u8 *mc_addr)
+{
+	u32 vector;
+	u32 vector_bit;
+	u32 vector_reg;
+
+	hw->addr_ctrl.mta_in_use++;
+
+	vector = txgbe_mta_vector(hw, mc_addr);
+	DEBUGOUT1(" bit-vector = 0x%03X\n", vector);
+
+	/*
+	 * The MTA is a register array of 128 32-bit registers. It is treated
+	 * like an array of 4096 bits.  We want to set bit
+	 * BitArray[vector_value]. So we figure out what register the bit is
+	 * in, read it, OR in the new bit, then write back the new value.  The
+	 * register is determined by the upper 7 bits of the vector value and
+	 * the bit within that register are determined by the lower 5 bits of
+	 * the value.
+	 */
+	vector_reg = (vector >> 5) & 0x7F;
+	vector_bit = vector & 0x1F;
+	hw->mac.mta_shadow[vector_reg] |= (1 << vector_bit);
+}
+
+/**
+ *  txgbe_update_mc_addr_list - Updates MAC list of multicast addresses
+ *  @hw: pointer to hardware structure
+ *  @mc_addr_list: the list of new multicast addresses
+ *  @mc_addr_count: number of addresses
+ *  @next: iterator function to walk the multicast address list
+ *  @clear: flag, when set clears the table beforehand
+ *
+ *  When the clear flag is set, the given list replaces any existing list.
+ *  Hashes the given addresses into the multicast table.
+ **/
+s32 txgbe_update_mc_addr_list(struct txgbe_hw *hw, u8 *mc_addr_list,
+				      u32 mc_addr_count, txgbe_mc_addr_itr next,
+				      bool clear)
+{
+	u32 i;
+	u32 vmdq;
+	u32 psrctl;
+
+	/*
+	 * Set the new number of MC addresses that we are being requested to
+	 * use.
+	 */
+	hw->addr_ctrl.num_mc_addrs = mc_addr_count;
+	hw->addr_ctrl.mta_in_use = 0;
+
+	/* Clear mta_shadow */
+	if (clear) {
+		DEBUGOUT(" Clearing MTA\n");
+		memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+	}
+
+	/* Update mta_shadow */
+	for (i = 0; i < mc_addr_count; i++) {
+		DEBUGOUT(" Adding the multicast addresses:\n");
+		txgbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq));
+	}
+
+	/* Enable mta */
+	for (i = 0; i < hw->mac.mcft_size; i++)
+		wr32a(hw, TXGBE_PSR_MC_TBL(0), i,
+				      hw->mac.mta_shadow[i]);
+
+	if (hw->addr_ctrl.mta_in_use > 0) {
+		psrctl = rd32(hw, TXGBE_PSR_CTL);
+		psrctl &= ~(TXGBE_PSR_CTL_MO | TXGBE_PSR_CTL_MFE);
+		psrctl |= TXGBE_PSR_CTL_MFE |
+			(hw->mac.mc_filter_type << TXGBE_PSR_CTL_MO_SHIFT);
+		wr32(hw, TXGBE_PSR_CTL, psrctl);
+	}
+
+	DEBUGOUT("txgbe_update_mc_addr_list Complete\n");
+	return 0;
+}
+
+/**
+ *  txgbe_enable_mc - Enable multicast address in RAR
+ *  @hw: pointer to hardware structure
+ *
+ *  Enables multicast address in RAR and the use of the multicast hash table.
+ **/
+s32 txgbe_enable_mc(struct txgbe_hw *hw)
+{
+	struct txgbe_addr_filter_info *a = &hw->addr_ctrl;
+	u32 psrctl;
+
+	if (a->mta_in_use > 0) {
+		psrctl = rd32(hw, TXGBE_PSR_CTL);
+		psrctl &= ~(TXGBE_PSR_CTL_MO | TXGBE_PSR_CTL_MFE);
+		psrctl |= TXGBE_PSR_CTL_MFE |
+			(hw->mac.mc_filter_type << TXGBE_PSR_CTL_MO_SHIFT);
+		wr32(hw, TXGBE_PSR_CTL, psrctl);
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_disable_mc - Disable multicast address in RAR
+ *  @hw: pointer to hardware structure
+ *
+ *  Disables multicast address in RAR and the use of the multicast hash table.
+ **/
+s32 txgbe_disable_mc(struct txgbe_hw *hw)
+{
+	struct txgbe_addr_filter_info *a = &hw->addr_ctrl;
+	u32 psrctl;
+
+	if (a->mta_in_use > 0) {
+		psrctl = rd32(hw, TXGBE_PSR_CTL);
+		psrctl &= ~(TXGBE_PSR_CTL_MO | TXGBE_PSR_CTL_MFE);
+		psrctl |= hw->mac.mc_filter_type << TXGBE_PSR_CTL_MO_SHIFT;
+		wr32(hw, TXGBE_PSR_CTL, psrctl);
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_fc_enable - Enable flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to the current settings.
+ **/
+s32 txgbe_fc_enable(struct txgbe_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 mflcn_reg, fccfg_reg;
+	u32 reg;
+	u32 fcrtl, fcrth;
+	int i;
+
+	/* Validate the water mark configuration */
+	if (!hw->fc.pause_time) {
+		ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS;
+		goto out;
+	}
+
+	/* Low water mark of zero causes XOFF floods */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		if ((hw->fc.current_mode & txgbe_fc_tx_pause) &&
+		    hw->fc.high_water[i]) {
+			if (!hw->fc.low_water[i] ||
+			    hw->fc.low_water[i] >= hw->fc.high_water[i]) {
+				DEBUGOUT("Invalid water mark configuration\n");
+				ret_val = TXGBE_ERR_INVALID_LINK_SETTINGS;
+				goto out;
+			}
+		}
+	}
+
+	/* Negotiate the fc mode to use */
+	txgbe_fc_autoneg(hw);
+
+	/* Disable any previous flow control settings */
+	mflcn_reg = rd32(hw, TXGBE_MAC_RX_FLOW_CTRL);
+	mflcn_reg &= ~(TXGBE_MAC_RX_FLOW_CTRL_PFCE |
+		TXGBE_MAC_RX_FLOW_CTRL_RFE);
+
+	fccfg_reg = rd32(hw, TXGBE_RDB_RFCC);
+	fccfg_reg &= ~(TXGBE_RDB_RFCC_RFCE_802_3X |
+		TXGBE_RDB_RFCC_RFCE_PRIORITY);
+
+	/*
+	 * The possible values of fc.current_mode are:
+	 * 0: Flow control is completely disabled
+	 * 1: Rx flow control is enabled (we can receive pause frames,
+	 *    but not send pause frames).
+	 * 2: Tx flow control is enabled (we can send pause frames but
+	 *    we do not support receiving pause frames).
+	 * 3: Both Rx and Tx flow control (symmetric) are enabled.
+	 * other: Invalid.
+	 */
+	switch (hw->fc.current_mode) {
+	case txgbe_fc_none:
+		/*
+		 * Flow control is disabled by software override or autoneg.
+		 * The code below will actually disable it in the HW.
+		 */
+		break;
+	case txgbe_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is
+		 * disabled by software override. Since there really
+		 * isn't a way to advertise that we are capable of RX
+		 * Pause ONLY, we will advertise that we support both
+		 * symmetric and asymmetric Rx PAUSE.  Later, we will
+		 * disable the adapter's ability to send PAUSE frames.
+		 */
+		mflcn_reg |= TXGBE_MAC_RX_FLOW_CTRL_RFE;
+		break;
+	case txgbe_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled by software override.
+		 */
+		fccfg_reg |= TXGBE_RDB_RFCC_RFCE_802_3X;
+		break;
+	case txgbe_fc_full:
+		/* Flow control (both Rx and Tx) is enabled by SW override. */
+		mflcn_reg |= TXGBE_MAC_RX_FLOW_CTRL_RFE;
+		fccfg_reg |= TXGBE_RDB_RFCC_RFCE_802_3X;
+		break;
+	default:
+		ERROR_REPORT1(TXGBE_ERROR_ARGUMENT,
+			     "Flow control param set incorrectly\n");
+		ret_val = TXGBE_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	/* Set 802.3x based flow control settings. */
+	wr32(hw, TXGBE_MAC_RX_FLOW_CTRL, mflcn_reg);
+	wr32(hw, TXGBE_RDB_RFCC, fccfg_reg);
+
+
+	/* Set up and enable Rx high/low water mark thresholds, enable XON. */
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		if ((hw->fc.current_mode & txgbe_fc_tx_pause) &&
+		    hw->fc.high_water[i]) {
+			fcrtl = (hw->fc.low_water[i] << 10) |
+				TXGBE_RDB_RFCL_XONE;
+			wr32(hw, TXGBE_RDB_RFCL(i), fcrtl);
+			fcrth = (hw->fc.high_water[i] << 10) |
+				TXGBE_RDB_RFCH_XOFFE;
+		} else {
+			wr32(hw, TXGBE_RDB_RFCL(i), 0);
+			/*
+			 * In order to prevent Tx hangs when the internal Tx
+			 * switch is enabled we must set the high water mark
+			 * to the Rx packet buffer size - 24KB.  This allows
+			 * the Tx switch to function even under heavy Rx
+			 * workloads.
+			 */
+			fcrth = rd32(hw, TXGBE_RDB_PB_SZ(i)) - 24576;
+		}
+
+		wr32(hw, TXGBE_RDB_RFCH(i), fcrth);
+	}
+
+	/* Configure pause time (2 TCs per register) */
+	reg = hw->fc.pause_time * 0x00010001;
+	for (i = 0; i < (TXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++)
+		wr32(hw, TXGBE_RDB_RFCV(i), reg);
+
+	/* Configure flow control refresh threshold value */
+	wr32(hw, TXGBE_RDB_RFCRT, hw->fc.pause_time / 2);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  txgbe_negotiate_fc - Negotiate flow control
+ *  @hw: pointer to hardware structure
+ *  @adv_reg: flow control advertised settings
+ *  @lp_reg: link partner's flow control settings
+ *  @adv_sym: symmetric pause bit in advertisement
+ *  @adv_asm: asymmetric pause bit in advertisement
+ *  @lp_sym: symmetric pause bit in link partner advertisement
+ *  @lp_asm: asymmetric pause bit in link partner advertisement
+ *
+ *  Find the intersection between advertised settings and link partner's
+ *  advertised settings
+ **/
+STATIC s32 txgbe_negotiate_fc(struct txgbe_hw *hw, u32 adv_reg, u32 lp_reg,
+			      u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm)
+{
+	if ((!(adv_reg)) ||  (!(lp_reg))) {
+		ERROR_REPORT3(TXGBE_ERROR_UNSUPPORTED,
+			     "Local or link partner's advertised flow control "
+			     "settings are NULL. Local: %x, link partner: %x\n",
+			     adv_reg, lp_reg);
+		return TXGBE_ERR_FC_NOT_NEGOTIATED;
+	}
+
+	if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) {
+		/*
+		 * Now we need to check if the user selected Rx ONLY
+		 * of pause frames.  In this case, we had to advertise
+		 * FULL flow control because we could not advertise RX
+		 * ONLY. Hence, we must now check to see if we need to
+		 * turn OFF the TRANSMISSION of PAUSE frames.
+		 */
+		if (hw->fc.requested_mode == txgbe_fc_full) {
+			hw->fc.current_mode = txgbe_fc_full;
+			DEBUGOUT("Flow Control = FULL.\n");
+		} else {
+			hw->fc.current_mode = txgbe_fc_rx_pause;
+			DEBUGOUT("Flow Control=RX PAUSE frames only\n");
+		}
+	} else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) &&
+		   (lp_reg & lp_sym) && (lp_reg & lp_asm)) {
+		hw->fc.current_mode = txgbe_fc_tx_pause;
+		DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
+	} else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) &&
+		   !(lp_reg & lp_sym) && (lp_reg & lp_asm)) {
+		hw->fc.current_mode = txgbe_fc_rx_pause;
+		DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
+	} else {
+		hw->fc.current_mode = txgbe_fc_none;
+		DEBUGOUT("Flow Control = NONE.\n");
+	}
+	return 0;
+}
+
+/**
+ *  txgbe_fc_autoneg_fiber - Enable flow control on 1 gig fiber
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according on 1 gig fiber.
+ **/
+STATIC s32 txgbe_fc_autoneg_fiber(struct txgbe_hw *hw)
+{
+
+	u32 pcs_anadv_reg, pcs_lpab_reg;
+	s32 ret_val = TXGBE_ERR_FC_NOT_NEGOTIATED;
+
+
+	pcs_anadv_reg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_AN_ADV);
+	pcs_lpab_reg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_LP_BABL);
+
+	ret_val =  txgbe_negotiate_fc(hw, pcs_anadv_reg,
+				      pcs_lpab_reg,
+				      TXGBE_SR_MII_MMD_AN_ADV_PAUSE_SYM,
+				      TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM,
+				      TXGBE_SR_MII_MMD_AN_ADV_PAUSE_SYM,
+				      TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM);
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_fc_autoneg_backplane - Enable flow control IEEE clause 37
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to IEEE clause 37.
+ **/
+STATIC s32 txgbe_fc_autoneg_backplane(struct txgbe_hw *hw)
+{
+	u32 anlp1_reg, autoc_reg;
+	s32 ret_val = TXGBE_ERR_FC_NOT_NEGOTIATED;
+
+	/*
+	 * Read the 10g AN autoc and LP ability registers and resolve
+	 * local flow control settings accordingly
+	 */
+	autoc_reg = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG1);
+	anlp1_reg = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_LP_ABL1);
+
+	ret_val = txgbe_negotiate_fc(hw, autoc_reg,
+		anlp1_reg, TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_SYM,
+		TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM,
+		TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_SYM,
+		TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM);
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_fc_autoneg_copper - Enable flow control IEEE clause 37
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to IEEE clause 37.
+ **/
+STATIC s32 txgbe_fc_autoneg_copper(struct txgbe_hw *hw)
+{
+	u8 technology_ability_reg = 0;
+	u8 lp_technology_ability_reg = 0;
+
+	txgbe_get_phy_advertised_pause(hw, &technology_ability_reg);
+	txgbe_get_lp_advertised_pause(hw, &lp_technology_ability_reg);
+
+	return txgbe_negotiate_fc(hw, (u32)technology_ability_reg,
+				  (u32)lp_technology_ability_reg,
+				  TXGBE_TAF_SYM_PAUSE, TXGBE_TAF_ASM_PAUSE,
+				  TXGBE_TAF_SYM_PAUSE, TXGBE_TAF_ASM_PAUSE);
+}
+
+/**
+ *  txgbe_fc_autoneg - Configure flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Compares our advertised flow control capabilities to those advertised by
+ *  our link partner, and determines the proper flow control mode to use.
+ **/
+void txgbe_fc_autoneg(struct txgbe_hw *hw)
+{
+	s32 ret_val = TXGBE_ERR_FC_NOT_NEGOTIATED;
+	u32 speed;
+	bool link_up;
+
+	/*
+	 * AN should have completed when the cable was plugged in.
+	 * Look for reasons to bail out.  Bail out if:
+	 * - FC autoneg is disabled, or if
+	 * - link is not up.
+	 */
+	if (hw->fc.disable_fc_autoneg) {
+		ERROR_REPORT1(TXGBE_ERROR_UNSUPPORTED,
+			     "Flow control autoneg is disabled");
+		goto out;
+	}
+
+	TCALL(hw, mac.ops.check_link, &speed, &link_up, false);
+	if (!link_up) {
+		ERROR_REPORT1(TXGBE_ERROR_SOFTWARE, "The link is down");
+		goto out;
+	}
+
+	switch (hw->phy.media_type) {
+	/* Autoneg flow control on fiber adapters */
+	case txgbe_media_type_fiber:
+		if (speed == TXGBE_LINK_SPEED_1GB_FULL)
+			ret_val = txgbe_fc_autoneg_fiber(hw);
+		break;
+
+	/* Autoneg flow control on backplane adapters */
+	case txgbe_media_type_backplane:
+		ret_val = txgbe_fc_autoneg_backplane(hw);
+		break;
+
+	/* Autoneg flow control on copper adapters */
+	case txgbe_media_type_copper:
+		if (txgbe_device_supports_autoneg_fc(hw))
+			ret_val = txgbe_fc_autoneg_copper(hw);
+		break;
+
+	default:
+		break;
+	}
+
+out:
+	if (ret_val == 0) {
+		hw->fc.fc_was_autonegged = true;
+	} else {
+		hw->fc.fc_was_autonegged = false;
+		hw->fc.current_mode = hw->fc.requested_mode;
+	}
+}
+
+/**
+ *  txgbe_disable_pcie_master - Disable PCI-express master access
+ *  @hw: pointer to hardware structure
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests. TXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
+ *  bit hasn't caused the master requests to be disabled, else 0
+ *  is returned signifying master requests disabled.
+ **/
+s32 txgbe_disable_pcie_master(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+	u32 i;
+	struct txgbe_adapter *adapter = hw->back;
+	unsigned int num_vfs = adapter->num_vfs;
+	u16 dev_ctl;
+	u32 vf_bme_clear = 0;
+	u16 vid = 0;
+	u16 cmd = 0;
+	u32 reg32 = 0;
+
+	/* Always set this bit to ensure any future transactions are blocked */
+	pci_clear_master(((struct txgbe_adapter *)hw->back)->pdev);
+
+	/* Exit if master requests are blocked */
+	if (!(rd32(hw, TXGBE_PX_TRANSACTION_PENDING)) ||
+			TXGBE_REMOVED(hw->hw_addr))
+		goto out;
+
+	/* BME disable handshake will not be finished if any VF BME is 0 */
+	for (i = 0; i < num_vfs; i++) {
+		struct pci_dev *vfdev = adapter->vfinfo[i].vfdev;
+		if (!vfdev) continue;
+		pci_read_config_word(vfdev, 0x4, &dev_ctl);
+		if ((dev_ctl & 0x4) == 0) {
+			vf_bme_clear = 1;
+		break;
+		}
+	}
+
+	/* Poll for master request bit to clear */
+	for (i = 0; i < TXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+		usec_delay(100);
+		if (!(rd32(hw, TXGBE_PX_TRANSACTION_PENDING)))
+			goto out;
+	}
+
+	if(!vf_bme_clear) {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+				 "PCIe transaction pending bit did not clear.\n");
+		status = TXGBE_ERR_MASTER_REQUESTS_PENDING;
+
+		/* print out PCI configuration space value */
+		txgbe_print_tx_hang_status(adapter);
+		pci_read_config_word(adapter->pdev, PCI_VENDOR_ID, &vid);
+		ERROR_REPORT1(TXGBE_ERROR_POLLING, "PCI VID is 0x%x\n", vid);
+
+		pci_read_config_word(adapter->pdev, PCI_COMMAND, &cmd);
+		ERROR_REPORT1(TXGBE_ERROR_POLLING, "PCI COMMAND value is 0x%x.\n", cmd);
+
+		reg32 = rd32(hw, 0x10000);
+		ERROR_REPORT1(TXGBE_ERROR_POLLING, "read 0x10000 value is 0x%08x\n", reg32);
+	}
+
+out:
+	return status;
+}
+
+
+/**
+ *  txgbe_acquire_swfw_sync - Acquire SWFW semaphore
+ *  @hw: pointer to hardware structure
+ *  @mask: Mask to specify which semaphore to acquire
+ *
+ *  Acquires the SWFW semaphore through the GSSR register for the specified
+ *  function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+s32 txgbe_acquire_swfw_sync(struct txgbe_hw *hw, u32 mask)
+{
+	u32 gssr = 0;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	u32 timeout = 200;
+	u32 i;
+
+	for (i = 0; i < timeout; i++) {
+		/*
+		 * SW NVM semaphore bit is used for access to all
+		 * SW_FW_SYNC bits (not just NVM)
+		 */
+		if (txgbe_get_eeprom_semaphore(hw))
+			return TXGBE_ERR_SWFW_SYNC;
+
+		if (txgbe_check_mng_access(hw)) {
+			gssr = rd32(hw, TXGBE_MNG_SWFW_SYNC);
+			if (!(gssr & (fwmask | swmask))) {
+				gssr |= swmask;
+				wr32(hw, TXGBE_MNG_SWFW_SYNC, gssr);
+				txgbe_release_eeprom_semaphore(hw);
+				return 0;
+			} else {
+				/* Resource is currently in use by FW or SW */
+				txgbe_release_eeprom_semaphore(hw);
+				msec_delay(5);
+			}
+		}
+	}
+
+	/* If time expired clear the bits holding the lock and retry */
+	if (gssr & (fwmask | swmask))
+		txgbe_release_swfw_sync(hw, gssr & (fwmask | swmask));
+
+	msec_delay(5);
+	return TXGBE_ERR_SWFW_SYNC;
+}
+
+/**
+ *  txgbe_release_swfw_sync - Release SWFW semaphore
+ *  @hw: pointer to hardware structure
+ *  @mask: Mask to specify which semaphore to release
+ *
+ *  Releases the SWFW semaphore through the GSSR register for the specified
+ *  function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+void txgbe_release_swfw_sync(struct txgbe_hw *hw, u32 mask)
+{
+	txgbe_get_eeprom_semaphore(hw);
+	if (txgbe_check_mng_access(hw))
+		wr32m(hw, TXGBE_MNG_SWFW_SYNC, mask, 0);
+
+	txgbe_release_eeprom_semaphore(hw);
+}
+
+/**
+ *  txgbe_disable_sec_rx_path - Stops the receive data path
+ *  @hw: pointer to hardware structure
+ *
+ *  Stops the receive data path and waits for the HW to internally empty
+ *  the Rx security block
+ **/
+s32 txgbe_disable_sec_rx_path(struct txgbe_hw *hw)
+{
+#define TXGBE_MAX_SECRX_POLL 40
+
+	int i;
+	int secrxreg;
+
+	wr32m(hw, TXGBE_RSC_CTL,
+		TXGBE_RSC_CTL_RX_DIS, TXGBE_RSC_CTL_RX_DIS);
+	for (i = 0; i < TXGBE_MAX_SECRX_POLL; i++) {
+		secrxreg = rd32(hw, TXGBE_RSC_ST);
+		if (secrxreg & TXGBE_RSC_ST_RSEC_RDY)
+			break;
+		else
+			/* Use interrupt-safe sleep just in case */
+			usec_delay(1000);
+	}
+
+	/* For informational purposes only */
+	if (i >= TXGBE_MAX_SECRX_POLL)
+		DEBUGOUT("Rx unit being enabled before security "
+			 "path fully disabled.  Continuing with init.\n");
+
+	return 0;
+}
+
+/**
+ *  txgbe_enable_sec_rx_path - Enables the receive data path
+ *  @hw: pointer to hardware structure
+ *
+ *  Enables the receive data path.
+ **/
+s32 txgbe_enable_sec_rx_path(struct txgbe_hw *hw)
+{
+	wr32m(hw, TXGBE_RSC_CTL,
+		TXGBE_RSC_CTL_RX_DIS, 0);
+	TXGBE_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+/**
+ *  txgbe_get_san_mac_addr_offset - Get SAN MAC address offset from the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @san_mac_offset: SAN MAC address offset
+ *
+ *  This function will read the EEPROM location for the SAN MAC address
+ *  pointer, and returns the value at that location.  This is used in both
+ *  get and set mac_addr routines.
+ **/
+STATIC s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw,
+					 u16 *san_mac_offset)
+{
+	s32 ret_val;
+
+	/*
+	 * First read the EEPROM pointer to see if the MAC addresses are
+	 * available.
+	 */
+	ret_val = TCALL(hw, eeprom.ops.read,
+			hw->eeprom.sw_region_offset + TXGBE_SAN_MAC_ADDR_PTR,
+			san_mac_offset);
+	if (ret_val) {
+		ERROR_REPORT2(TXGBE_ERROR_INVALID_STATE,
+			      "eeprom at offset %d failed",
+			      TXGBE_SAN_MAC_ADDR_PTR);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_get_san_mac_addr - SAN MAC address retrieval from the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @san_mac_addr: SAN MAC address
+ *
+ *  Reads the SAN MAC address from the EEPROM, if it's available.  This is
+ *  per-port, so set_lan_id() must be called before reading the addresses.
+ *  set_lan_id() is called by identify_sfp(), but this cannot be relied
+ *  upon for non-SFP connections, so we must call it here.
+ **/
+s32 txgbe_get_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr)
+{
+	u16 san_mac_data, san_mac_offset;
+	u8 i;
+	s32 ret_val;
+
+	/*
+	 * First read the EEPROM pointer to see if the MAC addresses are
+	 * available.  If they're not, no point in calling set_lan_id() here.
+	 */
+	ret_val = txgbe_get_san_mac_addr_offset(hw, &san_mac_offset);
+	if (ret_val || san_mac_offset == 0 || san_mac_offset == 0xFFFF)
+		goto san_mac_addr_out;
+
+	/* apply the port offset to the address offset */
+	(hw->bus.func) ? (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT1_OFFSET) :
+			 (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT0_OFFSET);
+	for (i = 0; i < 3; i++) {
+		ret_val = TCALL(hw, eeprom.ops.read, san_mac_offset,
+					      &san_mac_data);
+		if (ret_val) {
+			ERROR_REPORT2(TXGBE_ERROR_INVALID_STATE,
+				      "eeprom read at offset %d failed",
+				      san_mac_offset);
+			goto san_mac_addr_out;
+		}
+		san_mac_addr[i * 2] = (u8)(san_mac_data);
+		san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8);
+		san_mac_offset++;
+	}
+	return 0;
+
+san_mac_addr_out:
+	/*
+	 * No addresses available in this EEPROM.  It's not an
+	 * error though, so just wipe the local address and return.
+	 */
+	for (i = 0; i < 6; i++)
+		san_mac_addr[i] = 0xFF;
+	return 0;
+}
+
+/**
+ *  txgbe_set_san_mac_addr - Write the SAN MAC address to the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @san_mac_addr: SAN MAC address
+ *
+ *  Write a SAN MAC address to the EEPROM.
+ **/
+s32 txgbe_set_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr)
+{
+	s32 ret_val;
+	u16 san_mac_data, san_mac_offset;
+	u8 i;
+
+	/* Look for SAN mac address pointer.  If not defined, return */
+	ret_val = txgbe_get_san_mac_addr_offset(hw, &san_mac_offset);
+	if (ret_val || san_mac_offset == 0 || san_mac_offset == 0xFFFF)
+		return TXGBE_ERR_NO_SAN_ADDR_PTR;
+
+	/* Apply the port offset to the address offset */
+	(hw->bus.func) ? (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT1_OFFSET) :
+			 (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT0_OFFSET);
+
+	for (i = 0; i < 3; i++) {
+		san_mac_data = (u16)((u16)(san_mac_addr[i * 2 + 1]) << 8);
+		san_mac_data |= (u16)(san_mac_addr[i * 2]);
+		TCALL(hw, eeprom.ops.write, san_mac_offset, san_mac_data);
+		san_mac_offset++;
+	}
+
+	return 0;
+}
+
+
+/**
+ *  txgbe_insert_mac_addr - Find a RAR for this mac address
+ *  @hw: pointer to hardware structure
+ *  @addr: Address to put into receive address register
+ *  @vmdq: VMDq pool to assign
+ *
+ *  Puts an ethernet address into a receive address register, or
+ *  finds the rar that it is aleady in; adds to the pool list
+ **/
+s32 txgbe_insert_mac_addr(struct txgbe_hw *hw, u8 *addr, u32 vmdq)
+{
+	static const u32 NO_EMPTY_RAR_FOUND = 0xFFFFFFFF;
+	u32 first_empty_rar = NO_EMPTY_RAR_FOUND;
+	u32 rar;
+	u32 rar_low, rar_high;
+	u32 addr_low, addr_high;
+
+	/* swap bytes for HW little endian */
+	addr_low  = addr[5] | (addr[4] << 8)
+			    | (addr[3] << 16)
+			    | (addr[2] << 24);
+	addr_high = addr[1] | (addr[0] << 8);
+
+	/*
+	 * Either find the mac_id in rar or find the first empty space.
+	 * rar_highwater points to just after the highest currently used
+	 * rar in order to shorten the search.  It grows when we add a new
+	 * rar to the top.
+	 */
+	for (rar = 0; rar < hw->mac.rar_highwater; rar++) {
+		wr32(hw, TXGBE_PSR_MAC_SWC_IDX, rar);
+		rar_high = rd32(hw, TXGBE_PSR_MAC_SWC_AD_H);
+
+		if (((TXGBE_PSR_MAC_SWC_AD_H_AV & rar_high) == 0)
+		    && first_empty_rar == NO_EMPTY_RAR_FOUND) {
+			first_empty_rar = rar;
+		} else if ((rar_high & 0xFFFF) == addr_high) {
+			rar_low = rd32(hw, TXGBE_PSR_MAC_SWC_AD_L);
+			if (rar_low == addr_low)
+				break;    /* found it already in the rars */
+		}
+	}
+
+	if (rar < hw->mac.rar_highwater) {
+		/* already there so just add to the pool bits */
+		TCALL(hw, mac.ops.set_vmdq, rar, vmdq);
+	} else if (first_empty_rar != NO_EMPTY_RAR_FOUND) {
+		/* stick it into first empty RAR slot we found */
+		rar = first_empty_rar;
+		TCALL(hw, mac.ops.set_rar, rar, addr, vmdq,
+			       TXGBE_PSR_MAC_SWC_AD_H_AV);
+	} else if (rar == hw->mac.rar_highwater) {
+		/* add it to the top of the list and inc the highwater mark */
+		TCALL(hw, mac.ops.set_rar, rar, addr, vmdq,
+			       TXGBE_PSR_MAC_SWC_AD_H_AV);
+		hw->mac.rar_highwater++;
+	} else if (rar >= hw->mac.num_rar_entries) {
+		return TXGBE_ERR_INVALID_MAC_ADDR;
+	}
+
+	/*
+	 * If we found rar[0], make sure the default pool bit (we use pool 0)
+	 * remains cleared to be sure default pool packets will get delivered
+	 */
+	if (rar == 0)
+		TCALL(hw, mac.ops.clear_vmdq, rar, 0);
+
+	return rar;
+}
+
+/**
+ *  txgbe_clear_vmdq - Disassociate a VMDq pool index from a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to disassociate
+ *  @vmdq: VMDq pool index to remove from the rar
+ **/
+s32 txgbe_clear_vmdq(struct txgbe_hw *hw, u32 rar, u32 vmdq)
+{
+	u32 mpsar_lo, mpsar_hi;
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	/* Make sure we are using a valid rar index range */
+	if (rar >= rar_entries) {
+		ERROR_REPORT2(TXGBE_ERROR_ARGUMENT,
+			     "RAR index %d is out of range.\n", rar);
+		return TXGBE_ERR_INVALID_ARGUMENT;
+	}
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_IDX, rar);
+	mpsar_lo = rd32(hw, TXGBE_PSR_MAC_SWC_VM_L);
+	mpsar_hi = rd32(hw, TXGBE_PSR_MAC_SWC_VM_H);
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		goto done;
+
+	if (!mpsar_lo && !mpsar_hi)
+		goto done;
+
+	/* was that the last pool using this rar? */
+	if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
+		TCALL(hw, mac.ops.clear_rar, rar);
+done:
+	return 0;
+}
+
+/**
+ *  txgbe_set_vmdq - Associate a VMDq pool index with a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to associate with a VMDq index
+ *  @vmdq: VMDq pool index
+ **/
+s32 txgbe_set_vmdq(struct txgbe_hw *hw, u32 rar, u32 pool)
+{
+	u32 rar_entries = hw->mac.num_rar_entries;
+
+	/* Make sure we are using a valid rar index range */
+	if (rar >= rar_entries) {
+		ERROR_REPORT2(TXGBE_ERROR_ARGUMENT,
+			     "RAR index %d is out of range.\n", rar);
+		return TXGBE_ERR_INVALID_ARGUMENT;
+	}
+
+	return 0;
+}
+
+/**
+ *  This function should only be involved in the IOV mode.
+ *  In IOV mode, Default pool is next pool after the number of
+ *  VFs advertized and not 0.
+ *  MPSAR table needs to be updated for SAN_MAC RAR [hw->mac.san_mac_rar_index]
+ *
+ *  txgbe_set_vmdq_san_mac - Associate default VMDq pool index with a rx address
+ *  @hw: pointer to hardware struct
+ *  @vmdq: VMDq pool index
+ **/
+s32 txgbe_set_vmdq_san_mac(struct txgbe_hw *hw, u32 vmdq)
+{
+	u32 rar = hw->mac.san_mac_rar_index;
+
+	wr32(hw, TXGBE_PSR_MAC_SWC_IDX, rar);
+	if (vmdq < 32) {
+		wr32(hw, TXGBE_PSR_MAC_SWC_VM_L, 1 << vmdq);
+		wr32(hw, TXGBE_PSR_MAC_SWC_VM_H, 0);
+	} else {
+		wr32(hw, TXGBE_PSR_MAC_SWC_VM_L, 0);
+		wr32(hw, TXGBE_PSR_MAC_SWC_VM_H, 1 << (vmdq - 32));
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_init_uta_tables - Initialize the Unicast Table Array
+ *  @hw: pointer to hardware structure
+ **/
+s32 txgbe_init_uta_tables(struct txgbe_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < 128; i++)
+		wr32(hw, TXGBE_PSR_UC_TBL(i), 0);
+
+	return 0;
+}
+
+/**
+ *  txgbe_find_vlvf_slot - find the vlanid or the first empty slot
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *
+ *  return the VLVF index where this VLAN id should be placed
+ *
+ **/
+s32 txgbe_find_vlvf_slot(struct txgbe_hw *hw, u32 vlan)
+{
+	u32 bits = 0;
+	u32 first_empty_slot = 0;
+	s32 regindex;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
+
+	/*
+	 * Search for the vlan id in the VLVF entries. Save off the first empty
+	 * slot found along the way
+	 */
+	for (regindex = 1; regindex < TXGBE_PSR_VLAN_SWC_ENTRIES; regindex++) {
+		wr32(hw, TXGBE_PSR_VLAN_SWC_IDX, regindex);
+		bits = rd32(hw, TXGBE_PSR_VLAN_SWC);
+		if (!bits && !(first_empty_slot))
+			first_empty_slot = regindex;
+		else if ((bits & 0x0FFF) == vlan)
+			break;
+	}
+
+	/*
+	 * If regindex is less than TXGBE_VLVF_ENTRIES, then we found the vlan
+	 * in the VLVF. Else use the first empty VLVF register for this
+	 * vlan id.
+	 */
+	if (regindex >= TXGBE_PSR_VLAN_SWC_ENTRIES) {
+		if (first_empty_slot)
+			regindex = first_empty_slot;
+		else {
+			ERROR_REPORT1(TXGBE_ERROR_SOFTWARE,
+				     "No space in VLVF.\n");
+			regindex = TXGBE_ERR_NO_SPACE;
+		}
+	}
+
+	return regindex;
+}
+
+/**
+ *  txgbe_set_vfta - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 txgbe_set_vfta(struct txgbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on)
+{
+	s32 regindex;
+	u32 bitindex;
+	u32 vfta;
+	u32 targetbit;
+	s32 ret_val = 0;
+	bool vfta_changed = false;
+
+	if (vlan > 4095)
+		return TXGBE_ERR_PARAM;
+
+	/*
+	 * this is a 2 part operation - first the VFTA, then the
+	 * VLVF and VLVFB if VT Mode is set
+	 * We don't write the VFTA until we know the VLVF part succeeded.
+	 */
+
+	/* Part 1
+	 * The VFTA is a bitstring made up of 128 32-bit registers
+	 * that enable the particular VLAN id, much like the MTA:
+	 *    bits[11-5]: which register
+	 *    bits[4-0]:  which bit in the register
+	 */
+	regindex = (vlan >> 5) & 0x7F;
+	bitindex = vlan & 0x1F;
+	targetbit = (1 << bitindex);
+	/* errata 5 */
+	vfta = hw->mac.vft_shadow[regindex];
+	if (vlan_on) {
+		if (!(vfta & targetbit)) {
+			vfta |= targetbit;
+			vfta_changed = true;
+		}
+	} else {
+		if ((vfta & targetbit)) {
+			vfta &= ~targetbit;
+			vfta_changed = true;
+		}
+	}
+
+	/* Part 2
+	 * Call txgbe_set_vlvf to set VLVFB and VLVF
+	 */
+	ret_val = txgbe_set_vlvf(hw, vlan, vind, vlan_on,
+					 &vfta_changed);
+	if (ret_val != 0)
+		return ret_val;
+
+	if (vfta_changed)
+		wr32(hw, TXGBE_PSR_VLAN_TBL(regindex), vfta);
+	/* errata 5 */
+	hw->mac.vft_shadow[regindex] = vfta;
+	return 0;
+}
+
+/**
+ *  txgbe_set_vlvf - Set VLAN Pool Filter
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *  @vfta_changed: pointer to boolean flag which indicates whether VFTA
+ *                 should be changed
+ *
+ *  Turn on/off specified bit in VLVF table.
+ **/
+s32 txgbe_set_vlvf(struct txgbe_hw *hw, u32 vlan, u32 vind,
+			    bool vlan_on, bool *vfta_changed)
+{
+	u32 vt;
+
+	if (vlan > 4095)
+		return TXGBE_ERR_PARAM;
+
+	/* If VT Mode is set
+	 *   Either vlan_on
+	 *     make sure the vlan is in VLVF
+	 *     set the vind bit in the matching VLVFB
+	 *   Or !vlan_on
+	 *     clear the pool bit and possibly the vind
+	 */
+	vt = rd32(hw, TXGBE_CFG_PORT_CTL);
+	if (vt & TXGBE_CFG_PORT_CTL_NUM_VT_MASK) {
+		s32 vlvf_index;
+		u32 bits;
+
+		vlvf_index = txgbe_find_vlvf_slot(hw, vlan);
+		if (vlvf_index < 0)
+			return vlvf_index;
+
+		wr32(hw, TXGBE_PSR_VLAN_SWC_IDX, vlvf_index);
+		if (vlan_on) {
+			/* set the pool bit */
+			if (vind < 32) {
+				bits = rd32(hw,
+						TXGBE_PSR_VLAN_SWC_VM_L);
+				bits |= (1 << vind);
+				wr32(hw,
+						TXGBE_PSR_VLAN_SWC_VM_L,
+						bits);
+			} else {
+				bits = rd32(hw,
+					TXGBE_PSR_VLAN_SWC_VM_H);
+				bits |= (1 << (vind - 32));
+				wr32(hw,
+					TXGBE_PSR_VLAN_SWC_VM_H,
+					bits);
+			}
+		} else {
+			/* clear the pool bit */
+			if (vind < 32) {
+				bits = rd32(hw,
+						TXGBE_PSR_VLAN_SWC_VM_L);
+				bits &= ~(1 << vind);
+				wr32(hw,
+						TXGBE_PSR_VLAN_SWC_VM_L,
+						bits);
+				bits |= rd32(hw,
+					TXGBE_PSR_VLAN_SWC_VM_H);
+			} else {
+				bits = rd32(hw,
+					TXGBE_PSR_VLAN_SWC_VM_H);
+				bits &= ~(1 << (vind - 32));
+				wr32(hw,
+					TXGBE_PSR_VLAN_SWC_VM_H,
+					bits);
+				bits |= rd32(hw,
+						TXGBE_PSR_VLAN_SWC_VM_L);
+			}
+		}
+
+		/*
+		 * If there are still bits set in the VLVFB registers
+		 * for the VLAN ID indicated we need to see if the
+		 * caller is requesting that we clear the VFTA entry bit.
+		 * If the caller has requested that we clear the VFTA
+		 * entry bit but there are still pools/VFs using this VLAN
+		 * ID entry then ignore the request.  We're not worried
+		 * about the case where we're turning the VFTA VLAN ID
+		 * entry bit on, only when requested to turn it off as
+		 * there may be multiple pools and/or VFs using the
+		 * VLAN ID entry.  In that case we cannot clear the
+		 * VFTA bit until all pools/VFs using that VLAN ID have also
+		 * been cleared.  This will be indicated by "bits" being
+		 * zero.
+		 */
+		if (bits) {
+			wr32(hw, TXGBE_PSR_VLAN_SWC,
+					(TXGBE_PSR_VLAN_SWC_VIEN | vlan));
+			if ((!vlan_on) && (vfta_changed != NULL)) {
+				/* someone wants to clear the vfta entry
+				 * but some pools/VFs are still using it.
+				 * Ignore it. */
+				*vfta_changed = false;
+			}
+		} else
+			wr32(hw, TXGBE_PSR_VLAN_SWC, 0);
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+s32 txgbe_clear_vfta(struct txgbe_hw *hw)
+{
+	u32 offset;
+
+	for (offset = 0; offset < hw->mac.vft_size; offset++) {
+		wr32(hw, TXGBE_PSR_VLAN_TBL(offset), 0);
+		/* errata 5 */
+		hw->mac.vft_shadow[offset] = 0;
+	}
+
+	for (offset = 0; offset < TXGBE_PSR_VLAN_SWC_ENTRIES; offset++) {
+		wr32(hw, TXGBE_PSR_VLAN_SWC_IDX, offset);
+		wr32(hw, TXGBE_PSR_VLAN_SWC, 0);
+		wr32(hw, TXGBE_PSR_VLAN_SWC_VM_L, 0);
+		wr32(hw, TXGBE_PSR_VLAN_SWC_VM_H, 0);
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_get_wwn_prefix - Get alternative WWNN/WWPN prefix from
+ *  the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @wwnn_prefix: the alternative WWNN prefix
+ *  @wwpn_prefix: the alternative WWPN prefix
+ *
+ *  This function will read the EEPROM from the alternative SAN MAC address
+ *  block to check the support for the alternative WWNN/WWPN prefix support.
+ **/
+s32 txgbe_get_wwn_prefix(struct txgbe_hw *hw, u16 *wwnn_prefix,
+				 u16 *wwpn_prefix)
+{
+	u16 offset, caps;
+	u16 alt_san_mac_blk_offset;
+
+	/* clear output first */
+	*wwnn_prefix = 0xFFFF;
+	*wwpn_prefix = 0xFFFF;
+
+	/* check if alternative SAN MAC is supported */
+	offset = hw->eeprom.sw_region_offset + TXGBE_ALT_SAN_MAC_ADDR_BLK_PTR;
+	if (TCALL(hw, eeprom.ops.read, offset, &alt_san_mac_blk_offset))
+		goto wwn_prefix_err;
+
+	if ((alt_san_mac_blk_offset == 0) ||
+	    (alt_san_mac_blk_offset == 0xFFFF))
+		goto wwn_prefix_out;
+
+	/* check capability in alternative san mac address block */
+	offset = alt_san_mac_blk_offset + TXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET;
+	if (TCALL(hw, eeprom.ops.read, offset, &caps))
+		goto wwn_prefix_err;
+	if (!(caps & TXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN))
+		goto wwn_prefix_out;
+
+	/* get the corresponding prefix for WWNN/WWPN */
+	offset = alt_san_mac_blk_offset + TXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET;
+	if (TCALL(hw, eeprom.ops.read, offset, wwnn_prefix)) {
+		ERROR_REPORT2(TXGBE_ERROR_INVALID_STATE,
+			      "eeprom read at offset %d failed", offset);
+	}
+
+	offset = alt_san_mac_blk_offset + TXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET;
+	if (TCALL(hw, eeprom.ops.read, offset, wwpn_prefix))
+		goto wwn_prefix_err;
+
+wwn_prefix_out:
+	return 0;
+
+wwn_prefix_err:
+	ERROR_REPORT2(TXGBE_ERROR_INVALID_STATE,
+		      "eeprom read at offset %d failed", offset);
+	return 0;
+}
+
+
+/**
+ *  txgbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing
+ *  @hw: pointer to hardware structure
+ *  @enable: enable or disable switch for anti-spoofing
+ *  @pf: Physical Function pool - do not enable anti-spoofing for the PF
+ *
+ **/
+void txgbe_set_mac_anti_spoofing(struct txgbe_hw *hw, bool enable, int pf)
+{
+	u64 pfvfspoof = 0;
+
+	if (enable) {
+		/*
+		 * The PF should be allowed to spoof so that it can support
+		 * emulation mode NICs.  Do not set the bits assigned to the PF
+		 * Remaining pools belong to the PF so they do not need to have
+		 * anti-spoofing enabled.
+		 */
+		pfvfspoof = (1 << pf) - 1;
+		wr32(hw, TXGBE_TDM_MAC_AS_L,
+				pfvfspoof & 0xffffffff);
+		wr32(hw, TXGBE_TDM_MAC_AS_H, pfvfspoof >> 32);
+	} else {
+		wr32(hw, TXGBE_TDM_MAC_AS_L, 0);
+		wr32(hw, TXGBE_TDM_MAC_AS_H, 0);
+	}
+}
+
+/**
+ *  txgbe_set_vlan_anti_spoofing - Enable/Disable VLAN anti-spoofing
+ *  @hw: pointer to hardware structure
+ *  @enable: enable or disable switch for VLAN anti-spoofing
+ *  @vf: Virtual Function pool - VF Pool to set for VLAN anti-spoofing
+ *
+ **/
+void txgbe_set_vlan_anti_spoofing(struct txgbe_hw *hw, bool enable, int vf)
+{
+	u32 pfvfspoof;
+
+	if (vf < 32) {
+		pfvfspoof = rd32(hw, TXGBE_TDM_VLAN_AS_L);
+		if (enable)
+			pfvfspoof |= (1 << vf);
+		else
+			pfvfspoof &= ~(1 << vf);
+		wr32(hw, TXGBE_TDM_VLAN_AS_L, pfvfspoof);
+	} else {
+		pfvfspoof = rd32(hw, TXGBE_TDM_VLAN_AS_H);
+		if (enable)
+			pfvfspoof |= (1 << (vf - 32));
+		else
+			pfvfspoof &= ~(1 << (vf - 32));
+		wr32(hw, TXGBE_TDM_VLAN_AS_H, pfvfspoof);
+	}
+}
+
+/**
+ *  txgbe_set_ethertype_anti_spoofing - Enable/Disable Ethertype anti-spoofing
+ *  @hw: pointer to hardware structure
+ *  @enable: enable or disable switch for Ethertype anti-spoofing
+ *  @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
+ *
+ **/
+void txgbe_set_ethertype_anti_spoofing(struct txgbe_hw *hw,
+		bool enable, int vf)
+{
+	u32 pfvfspoof;
+
+	if (vf < 32) {
+		pfvfspoof = rd32(hw, TXGBE_TDM_ETYPE_AS_L);
+		if (enable)
+			pfvfspoof |= (1 << vf);
+		else
+			pfvfspoof &= ~(1 << vf);
+		wr32(hw, TXGBE_TDM_ETYPE_AS_L, pfvfspoof);
+	} else {
+		pfvfspoof = rd32(hw, TXGBE_TDM_ETYPE_AS_H);
+		if (enable)
+			pfvfspoof |= (1 << (vf - 32));
+		else
+			pfvfspoof &= ~(1 << (vf - 32));
+		wr32(hw, TXGBE_TDM_ETYPE_AS_H, pfvfspoof);
+	}
+}
+
+/**
+ *  txgbe_get_device_caps - Get additional device capabilities
+ *  @hw: pointer to hardware structure
+ *  @device_caps: the EEPROM word with the extra device capabilities
+ *
+ *  This function will read the EEPROM location for the device capabilities,
+ *  and return the word through device_caps.
+ **/
+s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps)
+{
+	TCALL(hw, eeprom.ops.read,
+		hw->eeprom.sw_region_offset + TXGBE_DEVICE_CAPS, device_caps);
+
+	return 0;
+}
+
+/**
+ *  txgbe_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+u8 txgbe_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8 sum = 0;
+
+	if (!buffer)
+		return 0;
+
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  txgbe_host_interface_command - Issue command to manageability block
+ *  @hw: pointer to the HW structure
+ *  @buffer: contains the command to write and where the return status will
+ *   be placed
+ *  @length: length of buffer, must be multiple of 4 bytes
+ *  @timeout: time in ms to wait for command completion
+ *  @return_data: read and return data from the buffer (true) or not (false)
+ *   Needed because FW structures are big endian and decoding of
+ *   these fields can be 8 bit or 16 bit based on command. Decoding
+ *   is not easily understood without making a table of commands.
+ *   So we will leave this up to the caller to read back the data
+ *   in these cases.
+ *
+ *  Communicates with the manageability block.  On success return 0
+ *  else return TXGBE_ERR_HOST_INTERFACE_COMMAND.
+ **/
+s32 txgbe_host_interface_command(struct txgbe_hw *hw, u32 *buffer,
+				 u32 length, u32 timeout, bool return_data)
+{
+	u32 hicr, i, bi;
+	u32 hdr_size = sizeof(struct txgbe_hic_hdr);
+	u16 buf_len;
+	u32 dword_len;
+	s32 status = 0;
+	u32 buf[64] = {};
+
+	if (length == 0 || length > TXGBE_HI_MAX_BLOCK_BYTE_LENGTH) {
+		DEBUGOUT1("Buffer length failure buffersize=%d.\n", length);
+		return TXGBE_ERR_HOST_INTERFACE_COMMAND;
+	}
+
+	if (TCALL(hw, mac.ops.acquire_swfw_sync, TXGBE_MNG_SWFW_SYNC_SW_MB)
+	    != 0) {
+		return TXGBE_ERR_SWFW_SYNC;
+	}
+
+
+	/* Calculate length in DWORDs. We must be DWORD aligned */
+	if ((length % (sizeof(u32))) != 0) {
+		DEBUGOUT("Buffer length failure, not aligned to dword");
+		status = TXGBE_ERR_INVALID_ARGUMENT;
+		goto rel_out;
+	}
+
+	dword_len = length >> 2;
+
+	/* The device driver writes the relevant command block
+	 * into the ram area.
+	 */
+	for (i = 0; i < dword_len; i++) {
+		if (txgbe_check_mng_access(hw)) {
+			wr32a(hw, TXGBE_MNG_MBOX,
+						i, TXGBE_CPU_TO_LE32(buffer[i]));
+			/* write flush */
+			buf[i] = rd32a(hw, TXGBE_MNG_MBOX, i);
+		}
+		else {
+			status = TXGBE_ERR_MNG_ACCESS_FAILED;
+			goto rel_out;
+		}
+	}
+	/* Setting this bit tells the ARC that a new command is pending. */
+	if (txgbe_check_mng_access(hw))
+		wr32m(hw, TXGBE_MNG_MBOX_CTL,
+			TXGBE_MNG_MBOX_CTL_SWRDY, TXGBE_MNG_MBOX_CTL_SWRDY);
+	else {
+		status = TXGBE_ERR_MNG_ACCESS_FAILED;
+		goto rel_out;
+	}
+
+	for (i = 0; i < timeout; i++) {
+		if (txgbe_check_mng_access(hw)) {
+			hicr = rd32(hw, TXGBE_MNG_MBOX_CTL);
+			if ((hicr & TXGBE_MNG_MBOX_CTL_FWRDY))
+				break;
+		}
+		msec_delay(1);
+	}
+
+	buf[0] = rd32(hw, TXGBE_MNG_MBOX);
+
+	if ((buf[0] & 0xff0000) >> 16 == 0x80) {
+		DEBUGOUT("It's unknown cmd.\n");
+		status = TXGBE_ERR_MNG_ACCESS_FAILED;
+		goto rel_out;
+	}
+	/* Check command completion */
+	if (timeout != 0 && i == timeout) {
+		ERROR_REPORT1(TXGBE_ERROR_CAUTION,
+						"Command has failed with no status valid.\n");
+
+		ERROR_REPORT1(TXGBE_ERROR_CAUTION, "write value:\n");
+		for (i = 0; i < dword_len; i++) {
+			ERROR_REPORT1(TXGBE_ERROR_CAUTION, "%x ", buffer[i]);
+		}
+		ERROR_REPORT1(TXGBE_ERROR_CAUTION, "read value:\n");
+		for (i = 0; i < dword_len; i++) {
+			ERROR_REPORT1(TXGBE_ERROR_CAUTION, "%x ", buf[i]);
+		}
+		printk("===%x= %x=\n", buffer[0] & 0xff, (~buf[0] >> 24));
+		if( (buffer[0] & 0xff) != (~buf[0] >> 24)) {
+			status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+			goto rel_out;
+		}
+	}
+
+	if (!return_data)
+		goto rel_out;
+
+	/* Calculate length in DWORDs */
+	dword_len = hdr_size >> 2;
+
+	/* first pull in the header so we know the buffer length */
+	for (bi = 0; bi < dword_len; bi++) {
+		if (txgbe_check_mng_access(hw)) {
+			buffer[bi] = rd32a(hw, TXGBE_MNG_MBOX,
+							bi);
+			TXGBE_LE32_TO_CPUS(&buffer[bi]);
+		} else {
+			status = TXGBE_ERR_MNG_ACCESS_FAILED;
+			goto rel_out;
+		}
+	}
+
+	/* If there is any thing in data position pull it in */
+	buf_len = ((struct txgbe_hic_hdr *)buffer)->buf_len;
+	if (buf_len == 0)
+		goto rel_out;
+
+	if (length < buf_len + hdr_size) {
+		DEBUGOUT("Buffer not large enough for reply message.\n");
+		status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+		goto rel_out;
+	}
+
+	/* Calculate length in DWORDs, add 3 for odd lengths */
+	dword_len = (buf_len + 3) >> 2;
+
+	/* Pull in the rest of the buffer (bi is where we left off) */
+	for (; bi <= dword_len; bi++) {
+		if (txgbe_check_mng_access(hw)) {
+			buffer[bi] = rd32a(hw, TXGBE_MNG_MBOX,
+							bi);
+			TXGBE_LE32_TO_CPUS(&buffer[bi]);
+		} else {
+			status = TXGBE_ERR_MNG_ACCESS_FAILED;
+			goto rel_out;
+		}
+	}
+
+rel_out:
+	TCALL(hw, mac.ops.release_swfw_sync, TXGBE_MNG_SWFW_SYNC_SW_MB);
+	return status;
+}
+
+/**
+ *  txgbe_set_fw_drv_ver - Sends driver version to firmware
+ *  @hw: pointer to the HW structure
+ *  @maj: driver version major number
+ *  @min: driver version minor number
+ *  @build: driver version build number
+ *  @sub: driver version sub build number
+ *
+ *  Sends driver version number to firmware through the manageability
+ *  block.  On success return 0
+ *  else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring
+ *  semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ **/
+s32 txgbe_set_fw_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min,
+				 u8 build, u8 sub)
+{
+	struct txgbe_hic_drv_info fw_cmd;
+	int i;
+	s32 ret_val = 0;
+
+	fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
+	fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN;
+	fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	fw_cmd.port_num = (u8)hw->bus.func;
+	fw_cmd.ver_maj = maj;
+	fw_cmd.ver_min = min;
+	fw_cmd.ver_build = build;
+	fw_cmd.ver_sub = sub;
+	fw_cmd.hdr.checksum = 0;
+	fw_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&fw_cmd,
+				(FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len));
+	fw_cmd.pad = 0;
+	fw_cmd.pad2 = 0;
+
+	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
+		ret_val = txgbe_host_interface_command(hw, (u32 *)&fw_cmd,
+						       sizeof(fw_cmd),
+						       TXGBE_HI_COMMAND_TIMEOUT,
+						       true);
+		if (ret_val != 0)
+			continue;
+
+		if (fw_cmd.hdr.cmd_or_resp.ret_status ==
+		    FW_CEM_RESP_STATUS_SUCCESS)
+			ret_val = 0;
+		else
+			ret_val = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_reset_hostif - send reset cmd to fw
+ *  @hw: pointer to hardware structure
+ *
+ *  Sends reset cmd to firmware through the manageability
+ *  block.  On success return 0
+ *  else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring
+ *  semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ **/
+s32 txgbe_reset_hostif(struct txgbe_hw *hw)
+{
+	struct txgbe_hic_reset reset_cmd;
+	int i;
+	s32 status = 0;
+
+	reset_cmd.hdr.cmd = FW_RESET_CMD;
+	reset_cmd.hdr.buf_len = FW_RESET_LEN;
+	reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	reset_cmd.lan_id = hw->bus.lan_id;
+	reset_cmd.reset_type = (u16)hw->reset_type;
+	reset_cmd.hdr.checksum = 0;
+	reset_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&reset_cmd,
+				(FW_CEM_HDR_LEN + reset_cmd.hdr.buf_len));
+
+	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
+		status = txgbe_host_interface_command(hw, (u32 *)&reset_cmd,
+						       sizeof(reset_cmd),
+						       TXGBE_HI_COMMAND_TIMEOUT,
+						       true);
+		if (status != 0)
+			continue;
+
+		if (reset_cmd.hdr.cmd_or_resp.ret_status ==
+			FW_CEM_RESP_STATUS_SUCCESS) {
+			status = 0;
+			hw->link_status = TXGBE_LINK_STATUS_NONE;
+		}
+		else
+			status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+
+		break;
+	}
+
+	return status;
+}
+
+
+s32 txgbe_setup_mac_link_hostif(struct txgbe_hw *hw, u32 speed)
+{
+	struct txgbe_hic_phy_cfg cmd;
+	int i;
+	s32 status = 0;
+
+	cmd.hdr.cmd = FW_SETUP_MAC_LINK_CMD;
+	cmd.hdr.buf_len = FW_SETUP_MAC_LINK_LEN;
+	cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	cmd.lan_id = hw->bus.lan_id;
+	cmd.phy_mode = 0;
+	cmd.phy_speed = (u16)speed;
+	cmd.hdr.checksum = 0;
+	cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&cmd,
+				(FW_CEM_HDR_LEN + cmd.hdr.buf_len));
+
+	for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
+		status = txgbe_host_interface_command(hw, (u32 *)&cmd,
+						       sizeof(cmd),
+						       TXGBE_HI_COMMAND_TIMEOUT,
+						       true);
+		if (status != 0)
+			continue;
+
+		if (cmd.hdr.cmd_or_resp.ret_status ==
+		    FW_CEM_RESP_STATUS_SUCCESS)
+			status = 0;
+		else
+			status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+
+		break;
+	}
+
+	return status;
+
+}
+
+u16 txgbe_crc16_ccitt(const u8 *buf, int size)
+{
+	u16 crc = 0;
+	int i;
+	while (--size >= 0) {
+		crc ^= (u16)*buf++ << 8;
+		for (i = 0; i < 8; i++) {
+			if (crc & 0x8000)
+				crc = crc << 1 ^ 0x1021;
+			else
+				crc <<= 1;
+		}
+	}
+	return crc;
+}
+
+s32 txgbe_upgrade_flash_hostif(struct txgbe_hw *hw, u32 region,
+				const u8 *data, u32 size)
+{
+	struct txgbe_hic_upg_start start_cmd;
+	struct txgbe_hic_upg_write write_cmd;
+	struct txgbe_hic_upg_verify verify_cmd;
+	u32 offset;
+	s32 status = 0;
+
+	start_cmd.hdr.cmd = FW_FLASH_UPGRADE_START_CMD;
+	start_cmd.hdr.buf_len = FW_FLASH_UPGRADE_START_LEN;
+	start_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	start_cmd.module_id = (u8)region;
+	start_cmd.hdr.checksum = 0;
+	start_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&start_cmd,
+				(FW_CEM_HDR_LEN + start_cmd.hdr.buf_len));
+	start_cmd.pad2 = 0;
+	start_cmd.pad3 = 0;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&start_cmd,
+					       sizeof(start_cmd),
+					       TXGBE_HI_FLASH_ERASE_TIMEOUT,
+					       true);
+
+	if (start_cmd.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS)
+		status = 0;
+	else {
+		status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+		return status;
+	}
+
+	for (offset = 0; offset < size;) {
+		write_cmd.hdr.cmd = FW_FLASH_UPGRADE_WRITE_CMD;
+		if (size - offset > 248) {
+			write_cmd.data_len = 248 / 4;
+			write_cmd.eof_flag = 0;
+		} else {
+			write_cmd.data_len = (u8)((size - offset) / 4);
+			write_cmd.eof_flag = 1;
+		}
+		memcpy((u8 *)write_cmd.data, &data[offset], write_cmd.data_len * 4);
+		write_cmd.hdr.buf_len = (write_cmd.data_len + 1) * 4;
+		write_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+		write_cmd.check_sum = txgbe_crc16_ccitt((u8 *)write_cmd.data,
+							write_cmd.data_len * 4);
+
+		status = txgbe_host_interface_command(hw, (u32 *)&write_cmd,
+						sizeof(write_cmd),
+						TXGBE_HI_FLASH_UPDATE_TIMEOUT,
+						true);
+		if (start_cmd.hdr.cmd_or_resp.ret_status ==
+						FW_CEM_RESP_STATUS_SUCCESS)
+			status = 0;
+		else {
+			status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+			return status;
+		}
+		offset += write_cmd.data_len * 4;
+	}
+
+	verify_cmd.hdr.cmd = FW_FLASH_UPGRADE_VERIFY_CMD;
+	verify_cmd.hdr.buf_len = FW_FLASH_UPGRADE_VERIFY_LEN;
+	verify_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	switch (region) {
+	case TXGBE_MODULE_EEPROM:
+		verify_cmd.action_flag = TXGBE_RELOAD_EEPROM;
+		break;
+	case TXGBE_MODULE_FIRMWARE:
+		verify_cmd.action_flag = TXGBE_RESET_FIRMWARE;
+		break;
+	case TXGBE_MODULE_HARDWARE:
+		verify_cmd.action_flag = TXGBE_RESET_LAN;
+		break;
+	default:
+		return status;
+	}
+
+	verify_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&verify_cmd,
+				(FW_CEM_HDR_LEN + verify_cmd.hdr.buf_len));
+
+	status = txgbe_host_interface_command(hw, (u32 *)&verify_cmd,
+					       sizeof(verify_cmd),
+					       TXGBE_HI_FLASH_VERIFY_TIMEOUT,
+					       true);
+
+	if (verify_cmd.hdr.cmd_or_resp.ret_status == FW_CEM_RESP_STATUS_SUCCESS)
+		status = 0;
+	else {
+		status = TXGBE_ERR_HOST_INTERFACE_COMMAND;
+	}
+	return status;
+}
+
+/* cmd_addr is used for some special command:
+**	 1. to be sector address, when implemented erase sector command
+**	 2. to be flash address when implemented read, write flash address
+*/
+u8 fmgr_cmd_op(struct txgbe_hw *hw, u32 cmd, u32 cmd_addr)
+{
+	u32 cmd_val = 0;
+	u32 time_out = 0;
+
+	cmd_val = (cmd << SPI_CLK_CMD_OFFSET) | (SPI_CLK_DIV << SPI_CLK_DIV_OFFSET) | cmd_addr;
+	wr32(hw, SPI_H_CMD_REG_ADDR, cmd_val);
+	while (1) {
+		if (rd32(hw, SPI_H_STA_REG_ADDR) & 0x1)
+			break;
+
+		if (time_out == SPI_TIME_OUT_VALUE)
+			return 1;
+
+		time_out = time_out + 1;
+		udelay(10);
+	}
+
+	return 0;
+}
+u8 fmgr_usr_cmd_op(struct txgbe_hw *hw, u32 usr_cmd)
+{
+	u8 status = 0;
+
+	wr32(hw, SPI_H_USR_CMD_REG_ADDR, usr_cmd);
+	status = fmgr_cmd_op(hw, SPI_CMD_USER_CMD, 0);
+
+	return status;
+}
+
+u8 txgbe_flash_erase_chip(struct txgbe_hw *hw)
+{
+	u8 status = fmgr_cmd_op(hw, SPI_CMD_ERASE_CHIP, 0);
+	return status;
+}
+
+u8 txgbe_flash_erase_sector(struct txgbe_hw *hw, u32 sec_addr)
+{
+	u8 status = fmgr_cmd_op(hw, SPI_CMD_ERASE_SECTOR, sec_addr);
+	return status;
+}
+u32 txgbe_flash_read_dword(struct txgbe_hw *hw, u32 addr)
+{
+	u8 status = fmgr_cmd_op(hw, SPI_CMD_READ_DWORD, addr);
+	if (status)
+		return (u32)status;
+	
+	return rd32(hw, SPI_H_DAT_REG_ADDR);
+}
+u8 txgbe_flash_write_dword(struct txgbe_hw *hw, u32 addr, u32 dword)
+{
+	u8 status = 0;
+		
+	wr32(hw, SPI_H_DAT_REG_ADDR, dword);
+	status = fmgr_cmd_op(hw, SPI_CMD_WRITE_DWORD, addr);
+	if (status)
+		return status;
+
+	if (dword != txgbe_flash_read_dword(hw, addr)) {
+		return 1;
+	}
+	return 0;
+}
+
+int txgbe_flash_write_cab(struct txgbe_hw *hw,u32 addr, u32 value,u16 lan_id)
+{
+	int status;
+	struct txgbe_hic_read_cab buffer;
+	
+	buffer.hdr.req.cmd = 0xE2;
+	buffer.hdr.req.buf_lenh = 0x6;
+	buffer.hdr.req.buf_lenl = 0x0;
+	buffer.hdr.req.checksum = 0xFF;
+
+	/* convert offset from words to bytes */
+	buffer.dbuf.d16[0] = cpu_to_le16(lan_id);
+	/* one word */
+	buffer.dbuf.d32[0] = htonl(addr);
+	buffer.dbuf.d32[1] = htonl(value);
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+						sizeof(buffer), 5000, true);
+	printk("0x1e100 :%08x\n",rd32(hw,0x1e100));
+	printk("0x1e104 :%08x\n",rd32(hw,0x1e104));
+	printk("0x1e108 :%08x\n",rd32(hw,0x1e108));
+	printk("0x1e10c :%08x\n",rd32(hw,0x1e10c));
+
+	return status;
+}
+
+int txgbe_flash_read_cab(struct txgbe_hw *hw, u32 addr ,u16 lan_id )
+{
+	int status;
+	struct txgbe_hic_read_cab buffer;
+	u16 *data = NULL;
+
+	buffer.hdr.req.cmd = 0xE1;
+	buffer.hdr.req.buf_lenh = 0xaa;
+	buffer.hdr.req.buf_lenl = 0;
+	buffer.hdr.req.checksum = 0xFF;
+
+	/* convert offset from words to bytes */
+	buffer.dbuf.d16[0] = cpu_to_le16(lan_id);
+	/* one word */
+	buffer.dbuf.d32[0] = htonl(addr);
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+										sizeof(buffer), 5000, true);
+
+	if (status)
+		return status;
+	if (txgbe_check_mng_access(hw)) {
+		*data = (u16)rd32a(hw, 0x1e100,3);
+		printk("0x1e100 :%08x\n",rd32(hw,0x1e100));
+		printk("0x1e104 :%08x\n",rd32(hw,0x1e104));
+		printk("0x1e108 :%08x\n",rd32(hw,0x1e108));
+		printk("0x1e10c :%08x\n",rd32(hw,0x1e10c));
+	} else {
+		status = -147;
+		return status;
+	}
+
+	return rd32(hw,0x1e108);
+}
+int txgbe_flash_write_unlock(struct txgbe_hw *hw)
+{
+	int status;
+	struct txgbe_hic_read_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = 0x40;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = 0;
+	buffer.hdr.req.checksum = 0xFF;
+
+	/* convert offset from words to bytes */
+	buffer.address = 0;
+	/* one word */
+	buffer.length = 0;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+										sizeof(buffer), 5000,false);
+	if (status)
+		return status;
+
+	return status;
+}
+
+int txgbe_flash_write_lock(struct txgbe_hw *hw)
+{
+	int status;
+	struct txgbe_hic_read_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = 0x39;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = 0;
+	buffer.hdr.req.checksum = 0xFF;
+
+	/* convert offset from words to bytes */
+	buffer.address = 0;
+	/* one word */
+	buffer.length = 0;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+										sizeof(buffer), 5000, false);
+	if (status)
+		return status;
+
+	return status;
+}
+
+int txgbe_upgrade_flash(struct txgbe_hw *hw, u32 region,
+								const u8 *data, u32 size)
+{
+	u32 sector_num = 0;
+	u32 read_data = 0;
+	u8 status = 0;
+	u8 skip = 0;
+	u32 i = 0;
+	u8 flash_vendor = 0;
+	u32 mac_addr0_dword0_t;
+	u32 mac_addr0_dword1_t;
+	u32 mac_addr1_dword0_t;
+	u32 mac_addr1_dword1_t;
+	u32 serial_num_dword0_t;
+	u32 serial_num_dword1_t;
+	u32 serial_num_dword2_t;
+
+	read_data = rd32(hw, 0x10200);
+	if (read_data & 0x80000000) {
+		printk("The flash has been successfully upgraded once, please reboot to make it work.\n");
+		return -EOPNOTSUPP;
+	}
+
+	/*check sub_id*/;
+	printk("Checking sub_id .......\n");
+	printk("The card's sub_id : %04x\n", hw->subsystem_device_id);
+	printk("The image's sub_id : %04x\n", data[0xfffdc] << 8  | data[0xfffdd]);
+	if ((hw->subsystem_device_id & 0xfff) == 
+		((data[0xfffdc] << 8  | data[0xfffdd]) & 0xfff)){
+		printk("It is a right image\n");
+	} else if (hw->subsystem_device_id == 0xffff){
+		printk("update anyway\n");
+	} else {
+		printk("====The Gigabit image is not match the Gigabit card====\n");
+		printk("====Please check your image====\n");
+		return -EOPNOTSUPP;
+	}
+	
+	/*check dev_id*/
+	printk("Checking dev_id .......\n");
+	printk("The image's dev_id : %04x\n", data[0xfffde] << 8  | data[0xfffdf]);
+	printk("The card's dev_id : %04x\n", hw->device_id);
+	if (!((hw->device_id & 0xfff0)== ((data[0xfffde] << 8 | data[0xfffdf]) & 0xfff0))
+		&& !(hw->device_id == 0xffff))
+	{
+		printk("====The Gigabit image is not match the Gigabit card====\n");
+		printk("====Please check your image====\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* unlock flash write protect*/
+	wr32(hw,TXGBE_SPI_CMDCFG0,0x9f050206);
+	wr32(hw,0x10194,0x9f050206);
+
+	msleep(1000);
+
+	mac_addr0_dword0_t = txgbe_flash_read_dword(hw, MAC_ADDR0_WORD0_OFFSET_1G);
+	mac_addr0_dword1_t = txgbe_flash_read_dword(hw, MAC_ADDR0_WORD1_OFFSET_1G) & 0xffff;
+	mac_addr1_dword0_t = txgbe_flash_read_dword(hw, MAC_ADDR1_WORD0_OFFSET_1G);
+	mac_addr1_dword1_t = txgbe_flash_read_dword(hw, MAC_ADDR1_WORD1_OFFSET_1G) & 0xffff;
+
+	serial_num_dword0_t = txgbe_flash_read_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G);
+	serial_num_dword1_t = txgbe_flash_read_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G+4);
+	serial_num_dword2_t = txgbe_flash_read_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G+8);
+	printk("Old: MAC Address0 is: 0x%04x%08x\n", mac_addr0_dword1_t, mac_addr0_dword0_t);
+	printk("	 MAC Address1 is: 0x%04x%08x\n", mac_addr1_dword1_t, mac_addr1_dword0_t);
+
+	
+	status = fmgr_usr_cmd_op(hw, 0x6);	/* write enable*/
+	status = fmgr_usr_cmd_op(hw, 0x98); /* global protection un-lock*/
+	txgbe_flash_write_unlock(hw);
+	msleep(1000);
+	
+	/*Note: for Spanish FLASH, first 8 sectors (4KB) in sector0 (64KB) 
+	need to use a special erase command (4K sector erase)*/
+	if (flash_vendor == 1) {
+		wr32(hw, SPI_CMD_CFG1_ADDR, 0x0103c720);			
+		for (i=0; i<8; i++) {
+			txgbe_flash_erase_sector(hw, i*128);
+			msleep(20); // 20 ms
+		}
+		wr32(hw, SPI_CMD_CFG1_ADDR, 0x0103c7d8);
+	}
+
+	sector_num = size / SPI_SECTOR_SIZE;
+	/* Winbond Flash, erase chip command is okay, but erase sector doestn't work*/
+	if (flash_vendor == 2) {
+		status = txgbe_flash_erase_chip(hw);
+		printk("Erase chip command, return status = %0d\n", status);
+		msleep(1000);
+	} else {
+		wr32(hw, SPI_CMD_CFG1_ADDR, 0x0103c720);
+		for (i=0; i<sector_num; i++) {
+			status = txgbe_flash_erase_sector(hw, i * SPI_SECTOR_SIZE);
+			printk("Erase sector[%2d] command, return status = %0d\n", i, status);
+			msleep(50);
+		}
+		wr32(hw, SPI_CMD_CFG1_ADDR, 0x0103c7d8);
+	}
+
+	/* Program Image file in dword*/
+	for (i=0; i<size/4; i++) {
+		read_data = data[4*i+3]<<24 | data[4*i+2]<<16 | data[4*i+1]<<8 | data[4*i];
+		read_data = __le32_to_cpu(read_data);
+		skip = ((i*4 == MAC_ADDR0_WORD0_OFFSET_1G) || (i*4 == MAC_ADDR0_WORD1_OFFSET_1G) ||
+				(i*4 == MAC_ADDR1_WORD0_OFFSET_1G) || (i*4 == MAC_ADDR1_WORD1_OFFSET_1G) ||
+				(i*4 >= PRODUCT_SERIAL_NUM_OFFSET_1G && i*4 <= PRODUCT_SERIAL_NUM_OFFSET_1G+8));
+		if (read_data != 0xffffffff && !skip) {
+			status = txgbe_flash_write_dword(hw, i*4, read_data);
+			if (status) {
+				printk("ERROR: Program 0x%08x @addr: 0x%08x is failed !!\n", read_data, i*4);
+				read_data = txgbe_flash_read_dword(hw, i*4);
+				printk("		 Read data from Flash is: 0x%08x\n", read_data);
+				return 1;
+			}
+		}
+		if (i%1024 == 0) {
+			printk("\b\b\b\b%3d%%", (int)(i*4 * 100 / size));
+		}
+	}
+
+	txgbe_flash_write_dword(hw, MAC_ADDR0_WORD0_OFFSET_1G, mac_addr0_dword0_t);
+	txgbe_flash_write_dword(hw, MAC_ADDR0_WORD1_OFFSET_1G, (mac_addr0_dword1_t | 0x80000000));//lan0
+	txgbe_flash_write_dword(hw, MAC_ADDR1_WORD0_OFFSET_1G, mac_addr1_dword0_t);
+	txgbe_flash_write_dword(hw, MAC_ADDR1_WORD1_OFFSET_1G, (mac_addr1_dword1_t | 0x80000000));//lan1
+	txgbe_flash_write_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G, serial_num_dword0_t);
+	txgbe_flash_write_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G+4, serial_num_dword1_t);
+	txgbe_flash_write_dword(hw, PRODUCT_SERIAL_NUM_OFFSET_1G+8, serial_num_dword2_t);
+
+	wr32(hw, 0x10200, rd32(hw, 0x10200) | 0x80000000);
+
+	return 0;
+}
+
+
+/**
+ * txgbe_set_rxpba - Initialize Rx packet buffer
+ * @hw: pointer to hardware structure
+ * @num_pb: number of packet buffers to allocate
+ * @headroom: reserve n KB of headroom
+ * @strategy: packet buffer allocation strategy
+ **/
+void txgbe_set_rxpba(struct txgbe_hw *hw, int num_pb, u32 headroom,
+			     int strategy)
+{
+	u32 pbsize = hw->mac.rx_pb_size;
+	int i = 0;
+	u32 rxpktsize, txpktsize, txpbthresh;
+
+	/* Reserve headroom */
+	pbsize -= headroom;
+
+	if (!num_pb)
+		num_pb = 1;
+
+	/* Divide remaining packet buffer space amongst the number of packet
+	 * buffers requested using supplied strategy.
+	 */
+	switch (strategy) {
+	case PBA_STRATEGY_WEIGHTED:
+		/* txgbe_dcb_pba_80_48 strategy weight first half of packet
+		 * buffer with 5/8 of the packet buffer space.
+		 */
+		rxpktsize = (pbsize * 5) / (num_pb * 4);
+		pbsize -= rxpktsize * (num_pb / 2);
+		rxpktsize <<= TXGBE_RDB_PB_SZ_SHIFT;
+		for (; i < (num_pb / 2); i++)
+			wr32(hw, TXGBE_RDB_PB_SZ(i), rxpktsize);
+		fallthrough;
+		/* Fall through to configure remaining packet buffers */
+	case PBA_STRATEGY_EQUAL:
+		rxpktsize = (pbsize / (num_pb - i)) << TXGBE_RDB_PB_SZ_SHIFT;
+		for (; i < num_pb; i++)
+			wr32(hw, TXGBE_RDB_PB_SZ(i), rxpktsize);
+		break;
+	default:
+		break;
+	}
+
+	/* Only support an equally distributed Tx packet buffer strategy. */
+	txpktsize = TXGBE_TDB_PB_SZ_MAX / num_pb;
+	txpbthresh = (txpktsize / 1024) - TXGBE_TXPKT_SIZE_MAX;
+	for (i = 0; i < num_pb; i++) {
+		wr32(hw, TXGBE_TDB_PB_SZ(i), txpktsize);
+		wr32(hw, TXGBE_TDM_PB_THRE(i), txpbthresh);
+	}
+
+	/* Clear unused TCs, if any, to zero buffer size*/
+	for (; i < TXGBE_MAX_PB; i++) {
+		wr32(hw, TXGBE_RDB_PB_SZ(i), 0);
+		wr32(hw, TXGBE_TDB_PB_SZ(i), 0);
+		wr32(hw, TXGBE_TDM_PB_THRE(i), 0);
+	}
+}
+
+
+/*STATIC const u8 txgbe_emc_temp_data[4] = {
+	TXGBE_EMC_INTERNAL_DATA,
+	TXGBE_EMC_DIODE1_DATA,
+	TXGBE_EMC_DIODE2_DATA,
+	TXGBE_EMC_DIODE3_DATA
+};
+STATIC const u8 txgbe_emc_therm_limit[4] = {
+	TXGBE_EMC_INTERNAL_THERM_LIMIT,
+	TXGBE_EMC_DIODE1_THERM_LIMIT,
+	TXGBE_EMC_DIODE2_THERM_LIMIT,
+	TXGBE_EMC_DIODE3_THERM_LIMIT
+};*/
+
+/**
+ *  txgbe_get_thermal_sensor_data - Gathers thermal sensor data
+ *  @hw: pointer to hardware structure
+ *  @data: pointer to the thermal sensor data structure
+ *
+ * algorithm:
+ * T = (-4.8380E+01)N^0 + (3.1020E-01)N^1 + (-1.8201E-04)N^2 +
+		       (8.1542E-08)N^3 + (-1.6743E-11)N^4
+ * algorithm with 5% more deviation, easy for implementation
+ * T = (-50)N^0 + (0.31)N^1 + (-0.0002)N^2 + (0.0000001)N^3
+ *
+ *  Returns the thermal sensor data structure
+ **/
+s32 txgbe_get_thermal_sensor_data(struct txgbe_hw *hw)
+{
+	s64 tsv;
+	int i = 0;
+	struct txgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	/* Only support thermal sensors attached to physical port 0 */
+	if (hw->bus.lan_id)
+		return TXGBE_NOT_IMPLEMENTED;
+
+	tsv = (s64)(rd32(hw, TXGBE_TS_ST) &
+		TXGBE_TS_ST_DATA_OUT_MASK);
+
+	tsv = tsv < 1200 ? tsv : 1200;
+	tsv = -(48380 << 8) / 1000
+		+ tsv * (31020 << 8) / 100000
+		- tsv * tsv * (18201 << 8) / 100000000
+		+ tsv * tsv * tsv * (81542 << 8) / 1000000000000
+		- tsv * tsv * tsv * tsv * (16743 << 8) / 1000000000000000;
+	tsv >>= 8;
+
+	data->sensor.temp = (s16)tsv;
+
+	for (i = 0; i < 100 ; i++){
+			tsv = (s64)rd32(hw, TXGBE_TS_ST);
+			if( tsv >> 16 == 0x1 ){
+				tsv = tsv & TXGBE_TS_ST_DATA_OUT_MASK;
+				tsv = tsv < 1200 ? tsv : 1200;
+				tsv = -(48380 << 8) / 1000
+						+ tsv * (31020 << 8) / 100000
+						- tsv * tsv * (18201 << 8) / 100000000
+						+ tsv * tsv * tsv * (81542 << 8) / 1000000000000
+						- tsv * tsv * tsv * tsv * (16743 << 8) / 1000000000000000;
+				tsv >>= 8;
+	
+				data->sensor.temp = (s16)tsv;
+				break;
+			}else{
+				msleep(1);
+				continue;
+			}
+	}
+	
+	return 0;
+}
+
+/**
+ *  txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
+ *  @hw: pointer to hardware structure
+ *
+ *  Inits the thermal sensor thresholds according to the NVM map
+ *  and save off the threshold and location values into mac.thermal_sensor_data
+ **/
+s32 txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+
+	struct txgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	memset(data, 0, sizeof(struct txgbe_thermal_sensor_data));
+
+	/* Only support thermal sensors attached to SP physical port 0 */
+	if (hw->bus.lan_id)
+		return TXGBE_NOT_IMPLEMENTED;
+
+	wr32(hw, TXGBE_TS_CTL, TXGBE_TS_CTL_EVAL_MD);
+	wr32(hw, TXGBE_TS_INT_EN,
+		TXGBE_TS_INT_EN_ALARM_INT_EN | TXGBE_TS_INT_EN_DALARM_INT_EN);
+	wr32(hw, TXGBE_TS_EN, TXGBE_TS_EN_ENA);
+
+
+	data->sensor.alarm_thresh = 100;
+	wr32(hw, TXGBE_TS_ALARM_THRE, 677);
+	data->sensor.dalarm_thresh = 90;
+	wr32(hw, TXGBE_TS_DALARM_THRE, 614);
+
+	return status;
+}
+
+void txgbe_disable_rx(struct txgbe_hw *hw)
+{
+	u32 pfdtxgswc;
+	u32 rxctrl;
+
+	rxctrl = rd32(hw, TXGBE_RDB_PB_CTL);
+	if (rxctrl & TXGBE_RDB_PB_CTL_RXEN) {
+		pfdtxgswc = rd32(hw, TXGBE_PSR_CTL);
+		if (pfdtxgswc & TXGBE_PSR_CTL_SW_EN) {
+			pfdtxgswc &= ~TXGBE_PSR_CTL_SW_EN;
+			wr32(hw, TXGBE_PSR_CTL, pfdtxgswc);
+			hw->mac.set_lben = true;
+		} else {
+			hw->mac.set_lben = false;
+		}
+		rxctrl &= ~TXGBE_RDB_PB_CTL_RXEN;
+		wr32(hw, TXGBE_RDB_PB_CTL, rxctrl);
+		/* errata 14 */
+		if (hw->revision_id == TXGBE_SP_MPW) {
+			do {
+				do {
+					if (rd32m(hw,
+						TXGBE_RDB_PB_CTL,
+						TXGBE_RDB_PB_CTL_DISABLED) == 1)
+						break;
+					msleep(10);
+				} while (1);
+				if (rd32m(hw, TXGBE_RDB_TXSWERR,
+					TXGBE_RDB_TXSWERR_TB_FREE) == 0x143)
+					break;
+				else {
+					wr32m(hw,
+						TXGBE_RDB_PB_CTL,
+						TXGBE_RDB_PB_CTL_RXEN,
+						TXGBE_RDB_PB_CTL_RXEN);
+					wr32m(hw,
+						TXGBE_RDB_PB_CTL,
+						TXGBE_RDB_PB_CTL_RXEN,
+						~TXGBE_RDB_PB_CTL_RXEN);
+
+				}
+			} while (1);
+		}
+
+		if (!(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)||
+			((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP))){
+			/* disable mac receiver */
+			wr32m(hw, TXGBE_MAC_RX_CFG,
+				TXGBE_MAC_RX_CFG_RE, 0);
+		}
+	}
+}
+
+
+void txgbe_enable_rx(struct txgbe_hw *hw)
+{
+	u32 pfdtxgswc;
+
+	/* enable mac receiver */
+	wr32m(hw, TXGBE_MAC_RX_CFG,
+		TXGBE_MAC_RX_CFG_RE, TXGBE_MAC_RX_CFG_RE);
+
+	wr32m(hw, TXGBE_RDB_PB_CTL,
+		TXGBE_RDB_PB_CTL_RXEN, TXGBE_RDB_PB_CTL_RXEN);
+
+	if (hw->mac.set_lben) {
+		pfdtxgswc = rd32(hw, TXGBE_PSR_CTL);
+		pfdtxgswc |= TXGBE_PSR_CTL_SW_EN;
+		wr32(hw, TXGBE_PSR_CTL, pfdtxgswc);
+		hw->mac.set_lben = false;
+	}
+}
+
+/**
+ * txgbe_mng_present - returns true when management capability is present
+ * @hw: pointer to hardware structure
+ */
+bool txgbe_mng_present(struct txgbe_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = rd32(hw, TXGBE_MIS_ST);
+	return fwsm & TXGBE_MIS_ST_MNG_INIT_DN;
+}
+
+bool txgbe_check_mng_access(struct txgbe_hw *hw)
+{
+	bool ret = false;
+	u32 rst_delay;
+	u32 i;
+
+	struct txgbe_adapter *adapter = hw->back;
+	if (!txgbe_mng_present(hw))
+		return false;
+	if (adapter->hw.revision_id != TXGBE_SP_MPW)
+		return true;
+	if (!(adapter->flags2 & TXGBE_FLAG2_MNG_REG_ACCESS_DISABLED))
+		return true;
+
+	rst_delay = (rd32(&adapter->hw, TXGBE_MIS_RST_ST) &
+			TXGBE_MIS_RST_ST_RST_INIT) >>
+			TXGBE_MIS_RST_ST_RST_INI_SHIFT;
+	for (i = 0; i < rst_delay + 2; i++) {
+		if (!(adapter->flags2 & TXGBE_FLAG2_MNG_REG_ACCESS_DISABLED)) {
+			ret = true;
+			break;
+		}
+		msleep(100);
+	}
+	return ret;
+}
+
+/**
+ *  txgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ *  Set the link speed in the MAC and/or PHY register and restarts link.
+ **/
+s32 txgbe_setup_mac_link_multispeed_fiber(struct txgbe_hw *hw,
+					  u32 speed,
+					  bool autoneg_wait_to_complete)
+{
+	u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
+	u32 highest_link_speed = TXGBE_LINK_SPEED_UNKNOWN;
+	s32 status = 0;
+	u32 speedcnt = 0;
+	u32 i = 0;
+	bool autoneg, link_up = false;
+	struct txgbe_adapter *adapter = hw->back;
+
+	/* Mask off requested but non-supported speeds */
+	status = TCALL(hw, mac.ops.get_link_capabilities,
+				&link_speed, &autoneg);
+	if (status != 0)
+		return status;
+
+	speed &= link_speed;
+
+	/* Try each speed one by one, highest priority first.  We do this in
+	 * software because 10Gb fiber doesn't support speed autonegotiation.
+	 */
+	if (speed & TXGBE_LINK_SPEED_10GB_FULL) {
+		speedcnt++;
+		highest_link_speed = TXGBE_LINK_SPEED_10GB_FULL;
+
+		/* If we already have link at this speed, just jump out */
+		status = TCALL(hw, mac.ops.check_link,
+					&link_speed, &link_up, false);
+		if (status != 0)
+			return status;
+
+		if ((link_speed == TXGBE_LINK_SPEED_10GB_FULL) && link_up)
+			goto out;
+
+		/* Allow module to change analog characteristics (1G->10G) */
+		msec_delay(40);
+
+		status = TCALL(hw, mac.ops.setup_mac_link,
+				TXGBE_LINK_SPEED_10GB_FULL,
+				autoneg_wait_to_complete);
+		if (status != 0)
+			return status;
+
+		/* Flap the Tx laser if it has not already been done */
+		TCALL(hw, mac.ops.flap_tx_laser);
+
+		/* Wait for the controller to acquire link.  Per IEEE 802.3ap,
+		 * Section 73.10.2, we may have to wait up to 500ms if KR is
+		 * attempted.  sapphire uses the same timing for 10g SFI.
+		 */
+		for (i = 0; i < 5; i++) {
+			/* Wait for the link partner to also set speed */
+			msec_delay(100);
+
+			/* If we have link, just jump out */
+			status = TCALL(hw, mac.ops.check_link,
+						&link_speed, &link_up, false);
+			if (status != 0)
+				return status;
+
+			if (link_up)
+				goto out;
+		}
+	}
+
+	if (speed & TXGBE_LINK_SPEED_1GB_FULL) {
+		u32 curr_autoneg = 2;
+		speedcnt++;
+		if (highest_link_speed == TXGBE_LINK_SPEED_UNKNOWN)
+			highest_link_speed = TXGBE_LINK_SPEED_1GB_FULL;
+
+		/* If we already have link at this speed, just jump out */
+		status = TCALL(hw, mac.ops.check_link,
+					&link_speed, &link_up, false);
+		if (status != 0)
+			return status;
+
+		if (link_speed == TXGBE_LINK_SPEED_1GB_FULL){
+		curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+		curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+		}
+
+		if ((link_speed == TXGBE_LINK_SPEED_1GB_FULL) && link_up
+		&&(adapter->an37 == curr_autoneg))
+			goto out;
+
+		/* Allow module to change analog characteristics (10G->1G) */
+		msec_delay(40);
+
+		status = TCALL(hw, mac.ops.setup_mac_link,
+				TXGBE_LINK_SPEED_1GB_FULL,
+				autoneg_wait_to_complete);
+		if (status != 0)
+			return status;
+
+		/* Flap the Tx laser if it has not already been done */
+		TCALL(hw, mac.ops.flap_tx_laser);
+
+		/* Wait for the link partner to also set speed */
+		msec_delay(100);
+
+		/* If we have link, just jump out */
+		status = TCALL(hw, mac.ops.check_link,
+					&link_speed, &link_up, false);
+		if (status != 0)
+			return status;
+
+		if (link_up)
+			goto out;
+	}
+
+	/* We didn't get link.  Configure back to the highest speed we tried,
+	 * (if there was more than one).  We call ourselves back with just the
+	 * single highest speed that the user requested.
+	 */
+	if (speedcnt > 1)
+		status = txgbe_setup_mac_link_multispeed_fiber(hw,
+						      highest_link_speed,
+						      autoneg_wait_to_complete);
+
+out:
+	/* Set autoneg_advertised value based on input link speed */
+	hw->phy.autoneg_advertised = 0;
+
+	if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+
+	if (speed & TXGBE_LINK_SPEED_1GB_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+	return status;
+}
+
+int txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit)
+{
+	u32 i = 0;
+	u32 reg = 0;
+	int err = 0;
+	/* if there's flash existing */
+	if (!(rd32(hw, TXGBE_SPI_STATUS) &
+		TXGBE_SPI_STATUS_FLASH_BYPASS)) {
+		/* wait hw load flash done */
+		for (i = 0; i < TXGBE_MAX_FLASH_LOAD_POLL_TIME; i++) {
+			reg = rd32(hw, TXGBE_SPI_ILDR_STATUS);
+			if (!(reg & check_bit)) {
+				/* done */
+				break;
+			}
+			msleep(200);
+		}
+		if (i == TXGBE_MAX_FLASH_LOAD_POLL_TIME) {
+			err = TXGBE_ERR_FLASH_LOADING_FAILED;
+		}
+	}
+	return err;
+}
+
+/* The txgbe_ptype_lookup is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT txgbe_ptype_lookup[ptype].known
+ * THEN
+ *      Packet is unknown
+ * ELSE IF txgbe_ptype_lookup[ptype].mac == TXGBE_DEC_PTYPE_MAC_IP
+ *      Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ *      Use the enum txgbe_l2_ptypes to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define TXGBE_PTT(ptype, mac, ip, etype, eip, proto, layer)\
+	{       ptype, \
+		1, \
+		/* mac     */ TXGBE_DEC_PTYPE_MAC_##mac, \
+		/* ip      */ TXGBE_DEC_PTYPE_IP_##ip, \
+		/* etype   */ TXGBE_DEC_PTYPE_ETYPE_##etype, \
+		/* eip     */ TXGBE_DEC_PTYPE_IP_##eip, \
+		/* proto   */ TXGBE_DEC_PTYPE_PROT_##proto, \
+		/* layer   */ TXGBE_DEC_PTYPE_LAYER_##layer }
+
+#define TXGBE_UKN(ptype) \
+		{ ptype, 0, 0, 0, 0, 0, 0, 0 }
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+/* for ((pt=0;pt<256;pt++)); do printf "macro(0x%02X),\n" $pt; done */
+txgbe_dptype txgbe_ptype_lookup[256] = {
+	TXGBE_UKN(0x00),
+	TXGBE_UKN(0x01),
+	TXGBE_UKN(0x02),
+	TXGBE_UKN(0x03),
+	TXGBE_UKN(0x04),
+	TXGBE_UKN(0x05),
+	TXGBE_UKN(0x06),
+	TXGBE_UKN(0x07),
+	TXGBE_UKN(0x08),
+	TXGBE_UKN(0x09),
+	TXGBE_UKN(0x0A),
+	TXGBE_UKN(0x0B),
+	TXGBE_UKN(0x0C),
+	TXGBE_UKN(0x0D),
+	TXGBE_UKN(0x0E),
+	TXGBE_UKN(0x0F),
+
+	/* L2: mac */
+	TXGBE_UKN(0x10),
+	TXGBE_PTT(0x11, L2, NONE, NONE, NONE, NONE, PAY2),
+	TXGBE_PTT(0x12, L2, NONE, NONE, NONE, TS,   PAY2),
+	TXGBE_PTT(0x13, L2, NONE, NONE, NONE, NONE, PAY2),
+	TXGBE_PTT(0x14, L2, NONE, NONE, NONE, NONE, PAY2),
+	TXGBE_PTT(0x15, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x16, L2, NONE, NONE, NONE, NONE, PAY2),
+	TXGBE_PTT(0x17, L2, NONE, NONE, NONE, NONE, NONE),
+
+	/* L2: ethertype filter */
+	TXGBE_PTT(0x18, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x19, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1A, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1B, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1C, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1D, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1E, L2, NONE, NONE, NONE, NONE, NONE),
+	TXGBE_PTT(0x1F, L2, NONE, NONE, NONE, NONE, NONE),
+
+	/* L3: ip non-tunnel */
+	TXGBE_UKN(0x20),
+	TXGBE_PTT(0x21, IP, FGV4, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x22, IP, IPV4, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x23, IP, IPV4, NONE, NONE, UDP,  PAY4),
+	TXGBE_PTT(0x24, IP, IPV4, NONE, NONE, TCP,  PAY4),
+	TXGBE_PTT(0x25, IP, IPV4, NONE, NONE, SCTP, PAY4),
+	TXGBE_UKN(0x26),
+	TXGBE_UKN(0x27),
+	TXGBE_UKN(0x28),
+	TXGBE_PTT(0x29, IP, FGV6, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x2A, IP, IPV6, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x2B, IP, IPV6, NONE, NONE, UDP,  PAY3),
+	TXGBE_PTT(0x2C, IP, IPV6, NONE, NONE, TCP,  PAY4),
+	TXGBE_PTT(0x2D, IP, IPV6, NONE, NONE, SCTP, PAY4),
+	TXGBE_UKN(0x2E),
+	TXGBE_UKN(0x2F),
+
+	/* L2: fcoe */
+	TXGBE_PTT(0x30, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x31, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x32, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x33, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x34, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_UKN(0x35),
+	TXGBE_UKN(0x36),
+	TXGBE_UKN(0x37),
+	TXGBE_PTT(0x38, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x39, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x3A, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x3B, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_PTT(0x3C, FCOE, NONE, NONE, NONE, NONE, PAY3),
+	TXGBE_UKN(0x3D),
+	TXGBE_UKN(0x3E),
+	TXGBE_UKN(0x3F),
+
+	TXGBE_UKN(0x40),
+	TXGBE_UKN(0x41),
+	TXGBE_UKN(0x42),
+	TXGBE_UKN(0x43),
+	TXGBE_UKN(0x44),
+	TXGBE_UKN(0x45),
+	TXGBE_UKN(0x46),
+	TXGBE_UKN(0x47),
+	TXGBE_UKN(0x48),
+	TXGBE_UKN(0x49),
+	TXGBE_UKN(0x4A),
+	TXGBE_UKN(0x4B),
+	TXGBE_UKN(0x4C),
+	TXGBE_UKN(0x4D),
+	TXGBE_UKN(0x4E),
+	TXGBE_UKN(0x4F),
+	TXGBE_UKN(0x50),
+	TXGBE_UKN(0x51),
+	TXGBE_UKN(0x52),
+	TXGBE_UKN(0x53),
+	TXGBE_UKN(0x54),
+	TXGBE_UKN(0x55),
+	TXGBE_UKN(0x56),
+	TXGBE_UKN(0x57),
+	TXGBE_UKN(0x58),
+	TXGBE_UKN(0x59),
+	TXGBE_UKN(0x5A),
+	TXGBE_UKN(0x5B),
+	TXGBE_UKN(0x5C),
+	TXGBE_UKN(0x5D),
+	TXGBE_UKN(0x5E),
+	TXGBE_UKN(0x5F),
+	TXGBE_UKN(0x60),
+	TXGBE_UKN(0x61),
+	TXGBE_UKN(0x62),
+	TXGBE_UKN(0x63),
+	TXGBE_UKN(0x64),
+	TXGBE_UKN(0x65),
+	TXGBE_UKN(0x66),
+	TXGBE_UKN(0x67),
+	TXGBE_UKN(0x68),
+	TXGBE_UKN(0x69),
+	TXGBE_UKN(0x6A),
+	TXGBE_UKN(0x6B),
+	TXGBE_UKN(0x6C),
+	TXGBE_UKN(0x6D),
+	TXGBE_UKN(0x6E),
+	TXGBE_UKN(0x6F),
+	TXGBE_UKN(0x70),
+	TXGBE_UKN(0x71),
+	TXGBE_UKN(0x72),
+	TXGBE_UKN(0x73),
+	TXGBE_UKN(0x74),
+	TXGBE_UKN(0x75),
+	TXGBE_UKN(0x76),
+	TXGBE_UKN(0x77),
+	TXGBE_UKN(0x78),
+	TXGBE_UKN(0x79),
+	TXGBE_UKN(0x7A),
+	TXGBE_UKN(0x7B),
+	TXGBE_UKN(0x7C),
+	TXGBE_UKN(0x7D),
+	TXGBE_UKN(0x7E),
+	TXGBE_UKN(0x7F),
+
+	/* IPv4 --> IPv4/IPv6 */
+	TXGBE_UKN(0x80),
+	TXGBE_PTT(0x81, IP, IPV4, IPIP, FGV4, NONE, PAY3),
+	TXGBE_PTT(0x82, IP, IPV4, IPIP, IPV4, NONE, PAY3),
+	TXGBE_PTT(0x83, IP, IPV4, IPIP, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0x84, IP, IPV4, IPIP, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0x85, IP, IPV4, IPIP, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0x86),
+	TXGBE_UKN(0x87),
+	TXGBE_UKN(0x88),
+	TXGBE_PTT(0x89, IP, IPV4, IPIP, FGV6, NONE, PAY3),
+	TXGBE_PTT(0x8A, IP, IPV4, IPIP, IPV6, NONE, PAY3),
+	TXGBE_PTT(0x8B, IP, IPV4, IPIP, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0x8C, IP, IPV4, IPIP, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0x8D, IP, IPV4, IPIP, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0x8E),
+	TXGBE_UKN(0x8F),
+
+	/* IPv4 --> GRE/NAT --> NONE/IPv4/IPv6 */
+	TXGBE_PTT(0x90, IP, IPV4, IG, NONE, NONE, PAY3),
+	TXGBE_PTT(0x91, IP, IPV4, IG, FGV4, NONE, PAY3),
+	TXGBE_PTT(0x92, IP, IPV4, IG, IPV4, NONE, PAY3),
+	TXGBE_PTT(0x93, IP, IPV4, IG, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0x94, IP, IPV4, IG, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0x95, IP, IPV4, IG, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0x96),
+	TXGBE_UKN(0x97),
+	TXGBE_UKN(0x98),
+	TXGBE_PTT(0x99, IP, IPV4, IG, FGV6, NONE, PAY3),
+	TXGBE_PTT(0x9A, IP, IPV4, IG, IPV6, NONE, PAY3),
+	TXGBE_PTT(0x9B, IP, IPV4, IG, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0x9C, IP, IPV4, IG, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0x9D, IP, IPV4, IG, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0x9E),
+	TXGBE_UKN(0x9F),
+
+	/* IPv4 --> GRE/NAT --> MAC --> NONE/IPv4/IPv6 */
+	TXGBE_PTT(0xA0, IP, IPV4, IGM, NONE, NONE, PAY3),
+	TXGBE_PTT(0xA1, IP, IPV4, IGM, FGV4, NONE, PAY3),
+	TXGBE_PTT(0xA2, IP, IPV4, IGM, IPV4, NONE, PAY3),
+	TXGBE_PTT(0xA3, IP, IPV4, IGM, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xA4, IP, IPV4, IGM, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xA5, IP, IPV4, IGM, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xA6),
+	TXGBE_UKN(0xA7),
+	TXGBE_UKN(0xA8),
+	TXGBE_PTT(0xA9, IP, IPV4, IGM, FGV6, NONE, PAY3),
+	TXGBE_PTT(0xAA, IP, IPV4, IGM, IPV6, NONE, PAY3),
+	TXGBE_PTT(0xAB, IP, IPV4, IGM, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xAC, IP, IPV4, IGM, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xAD, IP, IPV4, IGM, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xAE),
+	TXGBE_UKN(0xAF),
+
+	/* IPv4 --> GRE/NAT --> MAC+VLAN --> NONE/IPv4/IPv6 */
+	TXGBE_PTT(0xB0, IP, IPV4, IGMV, NONE, NONE, PAY3),
+	TXGBE_PTT(0xB1, IP, IPV4, IGMV, FGV4, NONE, PAY3),
+	TXGBE_PTT(0xB2, IP, IPV4, IGMV, IPV4, NONE, PAY3),
+	TXGBE_PTT(0xB3, IP, IPV4, IGMV, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xB4, IP, IPV4, IGMV, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xB5, IP, IPV4, IGMV, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xB6),
+	TXGBE_UKN(0xB7),
+	TXGBE_UKN(0xB8),
+	TXGBE_PTT(0xB9, IP, IPV4, IGMV, FGV6, NONE, PAY3),
+	TXGBE_PTT(0xBA, IP, IPV4, IGMV, IPV6, NONE, PAY3),
+	TXGBE_PTT(0xBB, IP, IPV4, IGMV, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xBC, IP, IPV4, IGMV, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xBD, IP, IPV4, IGMV, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xBE),
+	TXGBE_UKN(0xBF),
+
+	/* IPv6 --> IPv4/IPv6 */
+	TXGBE_UKN(0xC0),
+	TXGBE_PTT(0xC1, IP, IPV6, IPIP, FGV4, NONE, PAY3),
+	TXGBE_PTT(0xC2, IP, IPV6, IPIP, IPV4, NONE, PAY3),
+	TXGBE_PTT(0xC3, IP, IPV6, IPIP, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xC4, IP, IPV6, IPIP, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xC5, IP, IPV6, IPIP, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xC6),
+	TXGBE_UKN(0xC7),
+	TXGBE_UKN(0xC8),
+	TXGBE_PTT(0xC9, IP, IPV6, IPIP, FGV6, NONE, PAY3),
+	TXGBE_PTT(0xCA, IP, IPV6, IPIP, IPV6, NONE, PAY3),
+	TXGBE_PTT(0xCB, IP, IPV6, IPIP, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xCC, IP, IPV6, IPIP, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xCD, IP, IPV6, IPIP, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xCE),
+	TXGBE_UKN(0xCF),
+
+	/* IPv6 --> GRE/NAT -> NONE/IPv4/IPv6 */
+	TXGBE_PTT(0xD0, IP, IPV6, IG,   NONE, NONE, PAY3),
+	TXGBE_PTT(0xD1, IP, IPV6, IG,   FGV4, NONE, PAY3),
+	TXGBE_PTT(0xD2, IP, IPV6, IG,   IPV4, NONE, PAY3),
+	TXGBE_PTT(0xD3, IP, IPV6, IG,   IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xD4, IP, IPV6, IG,   IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xD5, IP, IPV6, IG,   IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xD6),
+	TXGBE_UKN(0xD7),
+	TXGBE_UKN(0xD8),
+	TXGBE_PTT(0xD9, IP, IPV6, IG,   FGV6, NONE, PAY3),
+	TXGBE_PTT(0xDA, IP, IPV6, IG,   IPV6, NONE, PAY3),
+	TXGBE_PTT(0xDB, IP, IPV6, IG,   IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xDC, IP, IPV6, IG,   IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xDD, IP, IPV6, IG,   IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xDE),
+	TXGBE_UKN(0xDF),
+
+	/* IPv6 --> GRE/NAT -> MAC -> NONE/IPv4/IPv6 */
+	TXGBE_PTT(0xE0, IP, IPV6, IGM,  NONE, NONE, PAY3),
+	TXGBE_PTT(0xE1, IP, IPV6, IGM,  FGV4, NONE, PAY3),
+	TXGBE_PTT(0xE2, IP, IPV6, IGM,  IPV4, NONE, PAY3),
+	TXGBE_PTT(0xE3, IP, IPV6, IGM,  IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xE4, IP, IPV6, IGM,  IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xE5, IP, IPV6, IGM,  IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xE6),
+	TXGBE_UKN(0xE7),
+	TXGBE_UKN(0xE8),
+	TXGBE_PTT(0xE9, IP, IPV6, IGM,  FGV6, NONE, PAY3),
+	TXGBE_PTT(0xEA, IP, IPV6, IGM,  IPV6, NONE, PAY3),
+	TXGBE_PTT(0xEB, IP, IPV6, IGM,  IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xEC, IP, IPV6, IGM,  IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xED, IP, IPV6, IGM,  IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xEE),
+	TXGBE_UKN(0xEF),
+
+	/* IPv6 --> GRE/NAT -> MAC--> NONE/IPv */
+	TXGBE_PTT(0xF0, IP, IPV6, IGMV, NONE, NONE, PAY3),
+	TXGBE_PTT(0xF1, IP, IPV6, IGMV, FGV4, NONE, PAY3),
+	TXGBE_PTT(0xF2, IP, IPV6, IGMV, IPV4, NONE, PAY3),
+	TXGBE_PTT(0xF3, IP, IPV6, IGMV, IPV4, UDP,  PAY4),
+	TXGBE_PTT(0xF4, IP, IPV6, IGMV, IPV4, TCP,  PAY4),
+	TXGBE_PTT(0xF5, IP, IPV6, IGMV, IPV4, SCTP, PAY4),
+	TXGBE_UKN(0xF6),
+	TXGBE_UKN(0xF7),
+	TXGBE_UKN(0xF8),
+	TXGBE_PTT(0xF9, IP, IPV6, IGMV, FGV6, NONE, PAY3),
+	TXGBE_PTT(0xFA, IP, IPV6, IGMV, IPV6, NONE, PAY3),
+	TXGBE_PTT(0xFB, IP, IPV6, IGMV, IPV6, UDP,  PAY4),
+	TXGBE_PTT(0xFC, IP, IPV6, IGMV, IPV6, TCP,  PAY4),
+	TXGBE_PTT(0xFD, IP, IPV6, IGMV, IPV6, SCTP, PAY4),
+	TXGBE_UKN(0xFE),
+	TXGBE_UKN(0xFF),
+};
+
+
+void txgbe_init_mac_link_ops(struct txgbe_hw *hw)
+{
+	struct txgbe_mac_info *mac = &hw->mac;
+
+	/*
+	 * enable the laser control functions for SFP+ fiber
+	 * and MNG not enabled
+	 */
+	if ((TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_fiber) &&
+	    !txgbe_mng_present(hw)) {
+		mac->ops.disable_tx_laser =
+				       txgbe_disable_tx_laser_multispeed_fiber;
+		mac->ops.enable_tx_laser =
+					txgbe_enable_tx_laser_multispeed_fiber;
+		mac->ops.flap_tx_laser = txgbe_flap_tx_laser_multispeed_fiber;
+
+	} else {
+		mac->ops.disable_tx_laser =
+				       txgbe_disable_tx_laser_multispeed_fiber;
+		mac->ops.enable_tx_laser =
+					txgbe_enable_tx_laser_multispeed_fiber;
+		mac->ops.flap_tx_laser = txgbe_flap_tx_laser_multispeed_fiber;
+	}
+
+	if (hw->phy.multispeed_fiber) {
+		/* Set up dual speed SFP+ support */
+		mac->ops.setup_link = txgbe_setup_mac_link_multispeed_fiber;
+		mac->ops.setup_mac_link = txgbe_setup_mac_link;
+		mac->ops.set_rate_select_speed =
+					       txgbe_set_hard_rate_select_speed;
+	} else {
+		mac->ops.setup_link = txgbe_setup_mac_link;
+		mac->ops.set_rate_select_speed =
+					       txgbe_set_hard_rate_select_speed;
+	}
+}
+
+/**
+ *  txgbe_init_phy_ops - PHY/SFP specific init
+ *  @hw: pointer to hardware structure
+ *
+ *  Initialize any function pointers that were not able to be
+ *  set during init_shared_code because the PHY/SFP type was
+ *  not known.  Perform the SFP init if necessary.
+ *
+ **/
+s32 txgbe_init_phy_ops(struct txgbe_hw *hw)
+{
+	struct txgbe_mac_info *mac = &hw->mac;
+	s32 ret_val = 0;
+
+	txgbe_init_i2c(hw);
+	/* Identify the PHY or SFP module */
+	ret_val = TCALL(hw, phy.ops.identify);
+	if (ret_val == TXGBE_ERR_SFP_NOT_SUPPORTED)
+		goto init_phy_ops_out;
+
+	/* Setup function pointers based on detected SFP module and speeds */
+	txgbe_init_mac_link_ops(hw);
+	if (hw->phy.sfp_type != txgbe_sfp_type_unknown)
+		hw->phy.ops.reset = NULL;
+
+	/* If copper media, overwrite with copper function pointers */
+	if (TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_copper) {
+		hw->phy.type = txgbe_phy_xaui;
+		if ((hw->subsystem_device_id & 0xF0) != TXGBE_ID_SFI_XAUI) {
+			mac->ops.setup_link = txgbe_setup_copper_link;
+			mac->ops.get_link_capabilities =
+				  txgbe_get_copper_link_capabilities;
+		}
+	}
+
+init_phy_ops_out:
+	return ret_val;
+}
+
+
+/**
+ *  txgbe_init_ops - Inits func ptrs and MAC type
+ *  @hw: pointer to hardware structure
+ *
+ *  Initialize the function pointers and assign the MAC type for sapphire.
+ *  Does not touch the hardware.
+ **/
+
+s32 txgbe_init_ops(struct txgbe_hw *hw)
+{
+	struct txgbe_mac_info *mac = &hw->mac;
+	struct txgbe_phy_info *phy = &hw->phy;
+	struct txgbe_eeprom_info *eeprom = &hw->eeprom;
+	struct txgbe_flash_info *flash = &hw->flash;
+	s32 ret_val = 0;
+
+	/* PHY */
+	phy->ops.reset = txgbe_reset_phy;
+	phy->ops.read_reg = txgbe_read_phy_reg;
+	phy->ops.write_reg = txgbe_write_phy_reg;
+	phy->ops.read_reg_mdi = txgbe_read_phy_reg_mdi;
+	phy->ops.write_reg_mdi = txgbe_write_phy_reg_mdi;
+	phy->ops.setup_link = txgbe_setup_phy_link;
+	phy->ops.setup_link_speed = txgbe_setup_phy_link_speed;
+	phy->ops.get_firmware_version = txgbe_get_phy_firmware_version;
+	phy->ops.read_i2c_byte = txgbe_read_i2c_byte;
+	phy->ops.write_i2c_byte = txgbe_write_i2c_byte;
+	phy->ops.read_i2c_sff8472 = txgbe_read_i2c_sff8472;
+	phy->ops.read_i2c_eeprom = txgbe_read_i2c_eeprom;
+	phy->ops.read_i2c_sfp_phy = txgbe_read_i2c_sfp_phy;
+	phy->ops.write_i2c_eeprom = txgbe_write_i2c_eeprom;
+	phy->ops.identify_sfp = txgbe_identify_module;
+	phy->sfp_type = txgbe_sfp_type_unknown;
+	phy->ops.check_overtemp = txgbe_tn_check_overtemp;
+	phy->ops.identify = txgbe_identify_phy;
+	phy->ops.init = txgbe_init_phy_ops;
+
+	/* MAC */
+	mac->ops.init_hw = txgbe_init_hw;
+	mac->ops.clear_hw_cntrs = txgbe_clear_hw_cntrs;
+	mac->ops.get_mac_addr = txgbe_get_mac_addr;
+	mac->ops.stop_adapter = txgbe_stop_adapter;
+	mac->ops.get_bus_info = txgbe_get_bus_info;
+	mac->ops.set_lan_id = txgbe_set_lan_id_multi_port_pcie;
+	mac->ops.acquire_swfw_sync = txgbe_acquire_swfw_sync;
+	mac->ops.release_swfw_sync = txgbe_release_swfw_sync;
+	mac->ops.reset_hw = txgbe_reset_hw;
+	mac->ops.get_media_type = txgbe_get_media_type;
+	mac->ops.disable_sec_rx_path = txgbe_disable_sec_rx_path;
+	mac->ops.enable_sec_rx_path = txgbe_enable_sec_rx_path;
+	mac->ops.enable_rx_dma = txgbe_enable_rx_dma;
+	mac->ops.start_hw = txgbe_start_hw;
+	mac->ops.get_san_mac_addr = txgbe_get_san_mac_addr;
+	mac->ops.set_san_mac_addr = txgbe_set_san_mac_addr;
+	mac->ops.get_device_caps = txgbe_get_device_caps;
+	mac->ops.get_wwn_prefix = txgbe_get_wwn_prefix;
+	mac->ops.setup_eee = txgbe_setup_eee;
+
+	/* LEDs */
+	mac->ops.led_on = txgbe_led_on;
+	mac->ops.led_off = txgbe_led_off;
+
+	/* RAR, Multicast, VLAN */
+	mac->ops.set_rar = txgbe_set_rar;
+	mac->ops.clear_rar = txgbe_clear_rar;
+	mac->ops.init_rx_addrs = txgbe_init_rx_addrs;
+	mac->ops.update_uc_addr_list = txgbe_update_uc_addr_list;
+	mac->ops.update_mc_addr_list = txgbe_update_mc_addr_list;
+	mac->ops.enable_mc = txgbe_enable_mc;
+	mac->ops.disable_mc = txgbe_disable_mc;
+	mac->ops.enable_rx = txgbe_enable_rx;
+	mac->ops.disable_rx = txgbe_disable_rx;
+	mac->ops.set_vmdq_san_mac = txgbe_set_vmdq_san_mac;
+	mac->ops.insert_mac_addr = txgbe_insert_mac_addr;
+	mac->rar_highwater = 1;
+	mac->ops.set_vfta = txgbe_set_vfta;
+	mac->ops.set_vlvf = txgbe_set_vlvf;
+	mac->ops.clear_vfta = txgbe_clear_vfta;
+	mac->ops.init_uta_tables = txgbe_init_uta_tables;
+	mac->ops.set_mac_anti_spoofing = txgbe_set_mac_anti_spoofing;
+	mac->ops.set_vlan_anti_spoofing = txgbe_set_vlan_anti_spoofing;
+	mac->ops.set_ethertype_anti_spoofing =
+				txgbe_set_ethertype_anti_spoofing;
+
+	/* Flow Control */
+	mac->ops.fc_enable = txgbe_fc_enable;
+	mac->ops.setup_fc = txgbe_setup_fc;
+
+	/* Link */
+	mac->ops.get_link_capabilities = txgbe_get_link_capabilities;
+	mac->ops.check_link = txgbe_check_mac_link;
+	mac->ops.setup_rxpba = txgbe_set_rxpba;
+	mac->mcft_size          = TXGBE_SP_MC_TBL_SIZE;
+	mac->vft_size           = TXGBE_SP_VFT_TBL_SIZE;
+	mac->num_rar_entries    = TXGBE_SP_RAR_ENTRIES;
+	mac->rx_pb_size         = TXGBE_SP_RX_PB_SIZE;
+	mac->max_rx_queues      = TXGBE_SP_MAX_RX_QUEUES;
+	mac->max_tx_queues      = TXGBE_SP_MAX_TX_QUEUES;
+	mac->max_msix_vectors   = txgbe_get_pcie_msix_count(hw);
+
+	mac->arc_subsystem_valid = (rd32(hw, TXGBE_MIS_ST) &
+				   TXGBE_MIS_ST_MNG_INIT_DN) ? true : false;
+
+	hw->mbx.ops.init_params = txgbe_init_mbx_params_pf;
+
+	/* EEPROM */
+	eeprom->ops.init_params = txgbe_init_eeprom_params;
+	eeprom->ops.calc_checksum = txgbe_calc_eeprom_checksum;
+	eeprom->ops.read = txgbe_read_ee_hostif;
+	eeprom->ops.read_buffer = txgbe_read_ee_hostif_buffer;
+	eeprom->ops.write = txgbe_write_ee_hostif;
+	eeprom->ops.write_buffer = txgbe_write_ee_hostif_buffer;
+	eeprom->ops.update_checksum = txgbe_update_eeprom_checksum;
+	eeprom->ops.validate_checksum = txgbe_validate_eeprom_checksum;
+
+	/* FLASH */
+	flash->ops.init_params = txgbe_init_flash_params;
+	flash->ops.read_buffer = txgbe_read_flash_buffer;
+	flash->ops.write_buffer = txgbe_write_flash_buffer;
+
+	/* Manageability interface */
+	mac->ops.set_fw_drv_ver = txgbe_set_fw_drv_ver;
+
+	mac->ops.get_thermal_sensor_data =
+					 txgbe_get_thermal_sensor_data;
+	mac->ops.init_thermal_sensor_thresh =
+				      txgbe_init_thermal_sensor_thresh;
+
+	mac->ops.get_rtrup2tc = txgbe_dcb_get_rtrup2tc;
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_get_link_capabilities - Determines link capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: true when autoneg or autotry is enabled
+ *
+ *  Determines the link capabilities by reading the AUTOC register.
+ **/
+s32 txgbe_get_link_capabilities(struct txgbe_hw *hw,
+				      u32 *speed,
+				      bool *autoneg)
+{
+	s32 status = 0;
+	u32 sr_pcs_ctl, sr_pma_mmd_ctl1, sr_an_mmd_ctl;
+	u32 sr_an_mmd_adv_reg2;
+
+	/* Check if 1G SFP module. */
+	if (hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 ||
+	    hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1) {
+		*speed = TXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = true;
+	} else if (hw->phy.multispeed_fiber) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL |
+			  TXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = true;
+	}
+	/* SFP */
+	else if (txgbe_get_media_type(hw) == txgbe_media_type_fiber) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
+	}
+	/* XAUI */
+	else if ((txgbe_get_media_type(hw) == txgbe_media_type_copper) &&
+			 ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI ||
+			 (hw->subsystem_device_id & 0xF0) == TXGBE_ID_SFI_XAUI)) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
+		hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_10GBASE_T;
+	}
+	/* SGMII */
+	else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_SGMII) {
+		*speed = TXGBE_LINK_SPEED_1GB_FULL |
+			TXGBE_LINK_SPEED_100_FULL |
+			TXGBE_LINK_SPEED_10_FULL;
+		*autoneg = false;
+		hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_1000BASE_T |
+				TXGBE_PHYSICAL_LAYER_100BASE_TX;
+        /* MAC XAUI */
+	} else if((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_XAUI) {
+		*speed = TXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
+		hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_10GBASE_KX4;
+		/* MAC SGMII */
+    } else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII) {
+		*speed = TXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = false;
+		hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_1000BASE_KX;
+    }
+	/* KR KX KX4 */
+	else {
+		/*
+		 * Determine link capabilities based on the stored value,
+		 * which represents EEPROM defaults.  If value has not
+		 * been stored, use the current register values.
+		 */
+		if (hw->mac.orig_link_settings_stored) {
+			sr_pcs_ctl = hw->mac.orig_sr_pcs_ctl2;
+			sr_pma_mmd_ctl1 = hw->mac.orig_sr_pma_mmd_ctl1;
+			sr_an_mmd_ctl = hw->mac.orig_sr_an_mmd_ctl;
+			sr_an_mmd_adv_reg2 = hw->mac.orig_sr_an_mmd_adv_reg2;
+		} else {
+			sr_pcs_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+			sr_pma_mmd_ctl1 = txgbe_rd32_epcs(hw,
+						TXGBE_SR_PMA_MMD_CTL1);
+			sr_an_mmd_ctl = txgbe_rd32_epcs(hw,
+						TXGBE_SR_AN_MMD_CTL);
+			sr_an_mmd_adv_reg2 = txgbe_rd32_epcs(hw,
+						TXGBE_SR_AN_MMD_ADV_REG2);
+		}
+
+		if ((sr_pcs_ctl & TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_MASK) ==
+			TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X &&
+			(sr_pma_mmd_ctl1 & TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_MASK)
+			== TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_1G &&
+			(sr_an_mmd_ctl & TXGBE_SR_AN_MMD_CTL_ENABLE) == 0) {
+			/* 1G or KX - no backplane auto-negotiation */
+			*speed = TXGBE_LINK_SPEED_1GB_FULL;
+			*autoneg = false;
+			hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_1000BASE_KX;
+		} else if ((sr_pcs_ctl & TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_MASK) ==
+			TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X &&
+			(sr_pma_mmd_ctl1 & TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_MASK)
+			== TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_10G &&
+			(sr_an_mmd_ctl & TXGBE_SR_AN_MMD_CTL_ENABLE) == 0) {
+			*speed = TXGBE_LINK_SPEED_10GB_FULL;
+			*autoneg = false;
+			hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_10GBASE_KX4;
+		} else if ((sr_pcs_ctl & TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_MASK) ==
+			TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_R &&
+			(sr_an_mmd_ctl & TXGBE_SR_AN_MMD_CTL_ENABLE) == 0) {
+			/* 10 GbE serial link (KR -no backplane auto-negotiation) */
+			*speed = TXGBE_LINK_SPEED_10GB_FULL;
+			*autoneg = false;
+			hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_10GBASE_KR;
+		} else if ((sr_an_mmd_ctl & TXGBE_SR_AN_MMD_CTL_ENABLE)) {
+			/* KX/KX4/KR backplane auto-negotiation enable */
+			*speed = TXGBE_LINK_SPEED_UNKNOWN;
+			if (sr_an_mmd_adv_reg2 &
+				TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KR)
+				*speed |= TXGBE_LINK_SPEED_10GB_FULL;
+			if (sr_an_mmd_adv_reg2 &
+				TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KX4)
+				*speed |= TXGBE_LINK_SPEED_10GB_FULL;
+			if (sr_an_mmd_adv_reg2 &
+				TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KX)
+				*speed |= TXGBE_LINK_SPEED_1GB_FULL;
+			*autoneg = true;
+			hw->phy.link_mode = TXGBE_PHYSICAL_LAYER_10GBASE_KR |
+					TXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
+					TXGBE_PHYSICAL_LAYER_1000BASE_KX;
+		} else {
+			status = TXGBE_ERR_LINK_SETUP;
+			goto out;
+		}
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  txgbe_get_media_type - Get media type
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns the media type (fiber, copper, backplane)
+ **/
+enum txgbe_media_type txgbe_get_media_type(struct txgbe_hw *hw)
+{
+	enum txgbe_media_type media_type;
+	u8 device_type = hw->subsystem_device_id & 0xF0;
+
+	/* Detect if there is a copper PHY attached. */
+	switch (hw->phy.type) {
+	case txgbe_phy_cu_unknown:
+	case txgbe_phy_tn:
+		media_type = txgbe_media_type_copper;
+		goto out;
+	default:
+		break;
+	}
+
+	switch (device_type) {
+	case TXGBE_ID_MAC_XAUI:
+	case TXGBE_ID_MAC_SGMII:
+	case TXGBE_ID_KR_KX_KX4:
+		/* Default device ID is mezzanine card KX/KX4 */
+		media_type = txgbe_media_type_backplane;
+		break;
+	case TXGBE_ID_SFP:
+		media_type = txgbe_media_type_fiber;
+		break;
+	case TXGBE_ID_XAUI:
+	case TXGBE_ID_SGMII:
+		media_type = txgbe_media_type_copper;
+		break;
+	case TXGBE_ID_SFI_XAUI:
+		if (hw->bus.lan_id == 0)
+			media_type = txgbe_media_type_fiber;
+		else
+			media_type = txgbe_media_type_copper;
+		break;
+	default:
+		media_type = txgbe_media_type_unknown;
+		break;
+	}
+out:
+	return media_type;
+}
+
+/**
+ *  txgbe_stop_mac_link_on_d3 - Disables link on D3
+ *  @hw: pointer to hardware structure
+ *
+ *  Disables link during D3 power down sequence.
+ *
+ **/
+void txgbe_stop_mac_link_on_d3(struct txgbe_hw *hw)
+{
+	/* fix autoc2 */
+	UNREFERENCED_PARAMETER(hw);
+	return;
+}
+
+
+/**
+ *  txgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser
+ *  @hw: pointer to hardware structure
+ *
+ *  The base drivers may require better control over SFP+ module
+ *  PHY states.  This includes selectively shutting down the Tx
+ *  laser on the PHY, effectively halting physical link.
+ **/
+void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
+{
+	u32 esdp_reg = rd32(hw, TXGBE_GPIO_DR);
+
+	if (!(TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_fiber))
+		return;
+	/* Blocked by MNG FW so bail */
+	txgbe_check_reset_blocked(hw);
+
+	if (txgbe_close_notify(hw))
+		/* over write led when ifconfig down */
+		TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_UP | TXGBE_LED_LINK_10G | TXGBE_LED_LINK_1G | TXGBE_LED_LINK_ACTIVE);
+	
+	/* Disable Tx laser; allow 100us to go dark per spec */
+	esdp_reg |= TXGBE_GPIO_DR_1 | TXGBE_GPIO_DR_0;
+	wr32(hw, TXGBE_GPIO_DR, esdp_reg);
+	TXGBE_WRITE_FLUSH(hw);
+	usec_delay(100);
+}
+
+/**
+ *  txgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser
+ *  @hw: pointer to hardware structure
+ *
+ *  The base drivers may require better control over SFP+ module
+ *  PHY states.  This includes selectively turning on the Tx
+ *  laser on the PHY, effectively starting physical link.
+ **/
+void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
+{
+	if (!(TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_fiber))
+		return;
+	if (txgbe_open_notify(hw))
+		/* recover led configure when ifconfig up */
+		wr32(hw, TXGBE_CFG_LED_CTL, 0);
+	
+	/* Enable Tx laser; allow 100ms to light up */
+	wr32m(hw, TXGBE_GPIO_DR,
+		TXGBE_GPIO_DR_0 | TXGBE_GPIO_DR_1, 0);
+	TXGBE_WRITE_FLUSH(hw);
+	msec_delay(100);
+}
+
+/**
+ *  txgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser
+ *  @hw: pointer to hardware structure
+ *
+ *  When the driver changes the link speeds that it can support,
+ *  it sets autotry_restart to true to indicate that we need to
+ *  initiate a new autotry session with the link partner.  To do
+ *  so, we set the speed then disable and re-enable the Tx laser, to
+ *  alert the link partner that it also needs to restart autotry on its
+ *  end.  This is consistent with true clause 37 autoneg, which also
+ *  involves a loss of signal.
+ **/
+void txgbe_flap_tx_laser_multispeed_fiber(struct txgbe_hw *hw)
+{
+	if (!(TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_fiber))
+		return;
+
+	/* Blocked by MNG FW so bail */
+	txgbe_check_reset_blocked(hw);
+
+	if (hw->mac.autotry_restart) {
+		txgbe_disable_tx_laser_multispeed_fiber(hw);
+		txgbe_enable_tx_laser_multispeed_fiber(hw);
+		hw->mac.autotry_restart = false;
+	}
+}
+
+/**
+ *  txgbe_set_hard_rate_select_speed - Set module link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: link speed to set
+ *
+ *  Set module link speed via RS0/RS1 rate select pins.
+ */
+void txgbe_set_hard_rate_select_speed(struct txgbe_hw *hw,
+					u32 speed)
+{
+	u32 esdp_reg = rd32(hw, TXGBE_GPIO_DR);
+
+	switch (speed) {
+	case TXGBE_LINK_SPEED_10GB_FULL:
+		esdp_reg |= TXGBE_GPIO_DR_5 | TXGBE_GPIO_DR_4;
+		break;
+	case TXGBE_LINK_SPEED_1GB_FULL:
+		esdp_reg &= ~(TXGBE_GPIO_DR_5 | TXGBE_GPIO_DR_4);
+		break;
+	default:
+		DEBUGOUT("Invalid fixed module speed\n");
+		return;
+	}
+
+	wr32(hw, TXGBE_GPIO_DDR,
+		TXGBE_GPIO_DDR_5 | TXGBE_GPIO_DDR_4 |
+		TXGBE_GPIO_DDR_1 | TXGBE_GPIO_DDR_0);
+
+	wr32(hw, TXGBE_GPIO_DR, esdp_reg);
+
+	TXGBE_WRITE_FLUSH(hw);
+}
+
+s32 txgbe_enable_rx_adapter(struct txgbe_hw *hw)
+{
+	u32 value;
+
+	value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_CTL);
+	value |= 1 << 12;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL, value);
+
+	value = 0;
+	while (!(value >> 11)) {
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_AD_ACK);
+		msleep(1);
+	}
+
+	value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_CTL);
+	value &= ~(1 << 12);
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL, value);
+
+	return 0;
+}
+
+s32 txgbe_set_sgmii_an37_ability(struct txgbe_hw *hw)
+{
+	u32 value;
+	struct txgbe_adapter *adapter = hw->back;
+
+	txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1, 0x3002);
+	/* for sgmii + external phy, set to 0x0105 (phy sgmii mode) */
+	/* for sgmii direct link, set to 0x010c (mac sgmii mode) */
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_SGMII ||
+		txgbe_get_media_type(hw) == txgbe_media_type_fiber) {
+		txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_AN_CTL, 0x010c);
+	} else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_SGMII ||
+				(hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) {
+		txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_AN_CTL, 0x0105);
+	}
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_DIGI_CTL, 0x0200);
+	value = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+	value = (value & ~0x1200) | (0x1 << 9);
+	if(adapter->an37) value |= (0x1 << 12);
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_CTL, value);
+	return 0;
+}
+
+
+s32 txgbe_set_link_to_kr(struct txgbe_hw *hw, bool autoneg)
+{
+	u32 i;
+	s32 status = 0;
+	u32 value = 0;
+	struct txgbe_adapter *adapter = hw->back;
+
+	/* 1. Wait xpcs power-up good */
+	for (i = 0; i < TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_MASK) ==
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_POWER_GOOD)
+			break;
+		msleep(10);
+	}
+	if (i == TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME) {
+		status = TXGBE_ERR_XPCS_POWER_UP_FAILED;
+		goto out;
+	}
+	e_dev_info("It is set to kr.\n");
+
+	txgbe_wr32_epcs(hw, 0x78001, 0x7);
+
+	if (1) {
+		/* 2. Disable xpcs AN-73 */
+		
+		if (adapter->backplane_an == 1){
+			txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x3000);
+			txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x1);
+		} else {
+			txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0);
+			txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL, 0x0);
+		}
+		/*
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG2, 0x80);
+		txgbe_wr32_epcs(hw, 0x18037, 0x80);
+		txgbe_wr32_epcs(hw, 0x18006, 0xffff);
+		txgbe_wr32_epcs(hw, 0x18008, 0xA697);
+		*/
+		txgbe_wr32_epcs(hw, 0x70012, 0xc000 | txgbe_rd32_epcs(hw, 0x70012));
+		if (KR_AN73_PRESET == 1) {
+			txgbe_wr32_epcs(hw, 0x18037, 0x80 | txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1));
+		}
+
+		if (KR_POLLING == 1) {
+			txgbe_wr32_epcs(hw, 0x18006, 0xffff);
+			txgbe_wr32_epcs(hw, 0x18008, 0xA697);
+		}
+
+		/* 3. Set VR_XS_PMA_Gen5_12G_MPLLA_CTRL3 Register */
+		/* Bit[10:0](MPLLA_BANDWIDTH) = 11'd123 (default: 11'd16) */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL3,
+				TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_10GBASER_KR);
+
+		/* 4. Set VR_XS_PMA_Gen5_12G_MISC_CTRL0 Register */
+		/* Bit[12:8](RX_VREF_CTRL) = 5'hF (default: 5'h11) */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0,
+				0xCF00);
+
+		/* 5. Set VR_XS_PMA_Gen5_12G_RX_EQ_CTRL0 Register */
+		/* Bit[15:8](VGA1/2_GAIN_0) = 8'h77, Bit[7:5](CTLE_POLE_0) = 3'h2
+		 * Bit[4:0](CTLE_BOOST_0) = 4'hA 
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0,
+				0x774A);
+
+		/* 6. Set VR_MII_Gen5_12G_RX_GENCTRL3 Register */
+		/* Bit[2:0](LOS_TRSHLD_0) = 3'h4 (default: 3) */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL3,
+				0x0004);
+		/* 7. Initialize the mode by setting VR XS or PCS MMD Digital */
+		/* Control1 Register Bit[15](VR_RST) */
+		txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1,
+				0xA000);
+		/* wait phy initialization done */
+		for (i = 0; i < TXGBE_PHY_INIT_DONE_POLLING_TIME; i++) {
+			if ((txgbe_rd32_epcs(hw,
+				TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1) &
+				TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST) == 0)
+				break;
+			msleep(100);
+		}
+		if (i == TXGBE_PHY_INIT_DONE_POLLING_TIME) {
+			status = TXGBE_ERR_PHY_INIT_NOT_DONE;
+			goto out;
+		}
+	} else {
+		 txgbe_wr32_epcs(hw, TXGBE_VR_AN_KR_MODE_CL,
+				0x1);
+	}
+
+	if ((KR_SET == 1) || (adapter->ffe_set == TXGBE_BP_M_KR)) {
+		e_dev_info("Set KR TX_EQ MAIN:%d PRE:%d POST:%d\n",
+				adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		value = (0x1804 & ~0x3F3F);
+		value |= adapter->ffe_main << 8 | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+
+		value = (0x50 & ~0x7F) | (1 << 6)| adapter->ffe_post;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	}
+out:
+	return status;
+}
+
+s32 txgbe_set_link_to_kx4(struct txgbe_hw *hw, bool autoneg)
+{
+	u32 i;
+	s32 status = 0;
+	u32 value;
+	struct txgbe_adapter *adapter = hw->back;
+
+	/* check link status, if already set, skip setting it again */
+	if (hw->link_status == TXGBE_LINK_STATUS_KX4) {
+		goto out;
+	}
+	e_dev_info("It is set to kx4.\n");
+
+	/* 1. Wait xpcs power-up good */
+	for (i = 0; i < TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_MASK) ==
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_POWER_GOOD)
+			break;
+		msleep(10);
+	}
+	if (i == TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME) {
+		status = TXGBE_ERR_XPCS_POWER_UP_FAILED;
+		goto out;
+	}
+
+		wr32m(hw, TXGBE_MAC_TX_CFG, TXGBE_MAC_TX_CFG_TE,
+			~TXGBE_MAC_TX_CFG_TE);
+
+	/* 2. Disable xpcs AN-73 */
+	if (!autoneg)
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0);
+	else
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x3000);
+
+	if (hw->revision_id == TXGBE_SP_MPW) {
+		/* Disable PHY MPLLA */
+		txgbe_wr32_ephy(hw, 0x4, 0x2501);
+		/* Reset rx lane0-3 clock */
+		txgbe_wr32_ephy(hw, 0x1005, 0x4001);
+		txgbe_wr32_ephy(hw, 0x1105, 0x4001);
+		txgbe_wr32_ephy(hw, 0x1205, 0x4001);
+		txgbe_wr32_ephy(hw, 0x1305, 0x4001);
+	} else {
+		/* Disable PHY MPLLA for eth mode change(after ECO) */
+		txgbe_wr32_ephy(hw, 0x4, 0x250A);
+		TXGBE_WRITE_FLUSH(hw);
+		msleep(1);
+
+		/* Set the eth change_mode bit first in mis_rst register
+		 * for corresponding LAN port
+		 */
+		if (hw->bus.lan_id == 0)
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN0_CHG_ETH_MODE);
+		else
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN1_CHG_ETH_MODE);
+	}
+
+	/* Set SR PCS Control2 Register Bits[1:0] = 2'b01  PCS_TYPE_SEL: non KR */
+	txgbe_wr32_epcs(hw, TXGBE_SR_PCS_CTL2,
+			TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X);
+	/* Set SR PMA MMD Control1 Register Bit[13] = 1'b1  SS13: 10G speed */
+	txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1,
+			TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_10G);
+
+	value = (0xf5f0 & ~0x7F0) |  (0x5 << 8) | (0x7 << 5) | 0xF0;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GENCTRL1, value);
+
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_MAC_XAUI)
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0xCF00);
+	else 
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0x4F00);
+
+	for (i = 0; i < 4; i++) {
+		if (i == 0)
+			value = (0x45 & ~0xFFFF) | (0x7 << 12) | (0x7 << 8) | 0x6;
+		else
+			value = (0xff06 & ~0xFFFF) | (0x7 << 12) | (0x7 << 8) | 0x6;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0 + i, value);
+	}
+
+	value = 0x0 & ~0x7777;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0, value);
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_DFE_TAP_CTL0, 0x0);
+
+	value = (0x6db & ~0xFFF) | (0x1 << 9) | (0x1 << 6) | (0x1 << 3) | 0x1;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL3, value);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY MPLLA */
+	/* Control 0 Register Bit[7:0] = 8'd40  MPLLA_MULTIPLIER */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL0,
+			TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_OTHER);
+	/* Set VR XS, PMA or MII Synopsys Enterprise Gen5 12G PHY MPLLA */
+	/* Control 3 Register Bit[10:0] = 11'd86  MPLLA_BANDWIDTH */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL3,
+			TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_OTHER);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Load 0 Register  Bit[12:0] = 13'd1360 VCO_LD_VAL_0 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD0,
+			TXGBE_PHY_VCO_CAL_LD0_OTHER);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Load 1 Register  Bit[12:0] = 13'd1360 VCO_LD_VAL_1 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD1,
+			TXGBE_PHY_VCO_CAL_LD0_OTHER);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Load 2 Register  Bit[12:0] = 13'd1360 VCO_LD_VAL_2 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD2,
+			TXGBE_PHY_VCO_CAL_LD0_OTHER);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Load 3 Register  Bit[12:0] = 13'd1360 VCO_LD_VAL_3 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD3,
+			TXGBE_PHY_VCO_CAL_LD0_OTHER);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Reference 0 Register Bit[5:0] = 6'd34 VCO_REF_LD_0/1 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF0,
+			0x2222);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO */
+	/* Calibration Reference 1 Register Bit[5:0] = 6'd34 VCO_REF_LD_2/3 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF1,
+			0x2222);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY AFE-DFE */
+	/* Enable Register Bit[7:0] = 8'd0  AFE_EN_0/3_1, DFE_EN_0/3_1 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE,
+			0x0);
+
+
+	/* Set  VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx */
+	/* Equalization Control 4 Register Bit[3:0] = 4'd0 CONT_ADAPT_0/3_1 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL,
+			0x00F0);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx Rate */
+	/* Control Register Bit[14:12], Bit[10:8], Bit[6:4], Bit[2:0],
+	 * all rates to 3'b010  TX0/1/2/3_RATE
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_RATE_CTL,
+			0x2222);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx Rate */
+	/* Control Register Bit[13:12], Bit[9:8], Bit[5:4], Bit[1:0],
+	 * all rates to 2'b10  RX0/1/2/3_RATE
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_RATE_CTL,
+			0x2222);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx General */
+	/* Control 2 Register Bit[15:8] = 2'b01  TX0/1/2/3_WIDTH: 10bits */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GEN_CTL2,
+			0x5500);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx General */
+	/* Control 2 Register Bit[15:8] = 2'b01  RX0/1/2/3_WIDTH: 10bits */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL2,
+			0x5500);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY MPLLA Control
+	 * 2 Register Bit[10:8] = 3'b010
+	 * MPLLA_DIV16P5_CLK_EN=0, MPLLA_DIV10_CLK_EN=1, MPLLA_DIV8_CLK_EN=0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL2,
+			TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_10);
+
+	txgbe_wr32_epcs(hw, 0x1f0000, 0x0);
+	txgbe_wr32_epcs(hw, 0x1f8001, 0x0);
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_DIGI_CTL, 0x0);
+
+	if(KX4_TXRX_PIN == 1)
+		txgbe_wr32_epcs(hw, 0x38001, 0xff);
+	/* 10. Initialize the mode by setting VR XS or PCS MMD Digital Control1
+	 * Register Bit[15](VR_RST)
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1, 0xA000);
+	/* wait phy initialization done */
+	for (i = 0; i < TXGBE_PHY_INIT_DONE_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST) == 0)
+			break;
+		msleep(100);
+	}
+
+	/* if success, set link status */
+	hw->link_status = TXGBE_LINK_STATUS_KX4;
+
+	if (i == TXGBE_PHY_INIT_DONE_POLLING_TIME) {
+		status = TXGBE_ERR_PHY_INIT_NOT_DONE;
+		goto out;
+	}
+
+	if ((KX4_SET == 1) || (adapter->ffe_set == TXGBE_BP_M_KX4)) {
+		e_dev_info("Set KX4 TX_EQ MAIN:%d PRE:%d POST:%d\n",
+					adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		value = (0x1804 & ~0x3F3F);
+		value |= adapter->ffe_main << 8 | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+
+		value = (0x50 & ~0x7F) | (1 << 6)| adapter->ffe_post;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	}
+
+out:
+	return status;
+
+}
+
+
+s32 txgbe_set_link_to_kx(struct txgbe_hw *hw,
+			       u32 speed,
+			       bool autoneg)
+{
+	u32 i;
+	s32 status = 0;
+	u32 wdata = 0;
+	u32 value;
+	struct txgbe_adapter *adapter = hw->back;
+
+	/* check link status, if already set, skip setting it again */
+	if (hw->link_status == TXGBE_LINK_STATUS_KX) {
+		goto out;
+	}
+	e_dev_info("It is set to kx. speed =0x%x\n", speed);
+
+	/* 1. Wait xpcs power-up good */
+	for (i = 0; i < TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_MASK) ==
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_POWER_GOOD)
+			break;
+		msleep(10);
+	}
+	if (i == TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME) {
+		status = TXGBE_ERR_XPCS_POWER_UP_FAILED;
+		goto out;
+	}
+
+	wr32m(hw, TXGBE_MAC_TX_CFG, TXGBE_MAC_TX_CFG_TE,
+				~TXGBE_MAC_TX_CFG_TE);
+
+	/* 2. Disable xpcs AN-73 */
+	if (!autoneg)
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0);
+	else
+		txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x3000);
+
+	if (hw->revision_id == TXGBE_SP_MPW) {
+		/* Disable PHY MPLLA */
+		txgbe_wr32_ephy(hw, 0x4, 0x2401);
+		/* Reset rx lane0 clock */
+		txgbe_wr32_ephy(hw, 0x1005, 0x4001);
+	} else {
+		/* Disable PHY MPLLA for eth mode change(after ECO) */
+		txgbe_wr32_ephy(hw, 0x4, 0x240A);
+		TXGBE_WRITE_FLUSH(hw);
+		msleep(1);
+
+		/* Set the eth change_mode bit first in mis_rst register */
+		/* for corresponding LAN port */
+		if (hw->bus.lan_id == 0)
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN0_CHG_ETH_MODE);
+		else
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN1_CHG_ETH_MODE);
+	}
+
+	/* Set SR PCS Control2 Register Bits[1:0] = 2'b01  PCS_TYPE_SEL: non KR */
+	txgbe_wr32_epcs(hw, TXGBE_SR_PCS_CTL2,
+			TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X);
+
+	/* Set SR PMA MMD Control1 Register Bit[13] = 1'b0 SS13: 1G speed */
+	txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1,
+			TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_1G);
+
+	/* Set SR MII MMD Control Register to corresponding speed: {Bit[6],
+	 * Bit[13]}=[2'b00,2'b01,2'b10]->[10M,100M,1G]
+	 */
+	if (speed == TXGBE_LINK_SPEED_100_FULL)
+		wdata = 0x2100;
+	else if (speed == TXGBE_LINK_SPEED_1GB_FULL)
+		wdata = 0x0140;
+	else if (speed == TXGBE_LINK_SPEED_10_FULL)
+		wdata = 0x0100;
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_CTL,
+			wdata);
+
+	value = (0xf5f0 & ~0x710) |  (0x5 << 8)| 0x10;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GENCTRL1, value);
+
+	if (KX_SGMII == 1)
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0x4F00);
+	else
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0xCF00);
+
+	for (i = 0; i < 4; i++) {
+		if (i) {
+			value = 0xff06;
+		} else {
+			value = (0x45 & ~0xFFFF) | (0x7 << 12) | (0x7 << 8) | 0x6;
+		}
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0 + i, value);
+	}
+
+	value = 0x0 & ~0x7;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0, value);
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_DFE_TAP_CTL0, 0x0);
+
+	value = (0x6db & ~0x7) | 0x4;
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL3, value);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY MPLLA Control
+	 * 0 Register Bit[7:0] = 8'd32  MPLLA_MULTIPLIER
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL0,
+			TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_1GBASEX_KX);
+
+	/* Set VR XS, PMA or MII Synopsys Enterprise Gen5 12G PHY MPLLA Control 3
+	 * Register Bit[10:0] = 11'd70  MPLLA_BANDWIDTH
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL3,
+			TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_1GBASEX_KX);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO
+	 * Calibration Load 0 Register  Bit[12:0] = 13'd1344  VCO_LD_VAL_0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD0,
+			TXGBE_PHY_VCO_CAL_LD0_1GBASEX_KX);
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD1, 0x549);
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD2, 0x549);
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD3, 0x549);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO
+	 * Calibration Reference 0 Register Bit[5:0] = 6'd42  VCO_REF_LD_0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF0,
+			TXGBE_PHY_VCO_CAL_REF0_LD0_1GBASEX_KX);
+
+	txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF1, 0x2929);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY AFE-DFE Enable
+	 * Register Bit[4], Bit[0] = 1'b0  AFE_EN_0, DFE_EN_0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE,
+			0x0);
+	/* Set	VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx
+	 * Equalization Control 4 Register Bit[0] = 1'b0  CONT_ADAPT_0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL,
+			0x0010);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx Rate
+	 * Control Register Bit[2:0] = 3'b011  TX0_RATE
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_RATE_CTL,
+			TXGBE_PHY_TX_RATE_CTL_TX0_RATE_1GBASEX_KX);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx Rate
+	 * Control Register Bit[2:0] = 3'b011 RX0_RATE
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_RATE_CTL,
+			TXGBE_PHY_RX_RATE_CTL_RX0_RATE_1GBASEX_KX);
+
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx General
+	 * Control 2 Register Bit[9:8] = 2'b01  TX0_WIDTH: 10bits
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GEN_CTL2,
+			TXGBE_PHY_TX_GEN_CTL2_TX0_WIDTH_OTHER);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx General
+	 * Control 2 Register Bit[9:8] = 2'b01  RX0_WIDTH: 10bits
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL2,
+			TXGBE_PHY_RX_GEN_CTL2_RX0_WIDTH_OTHER);
+	/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY MPLLA Control
+	 * 2 Register Bit[10:8] = 3'b010	MPLLA_DIV16P5_CLK_EN=0,
+	 * MPLLA_DIV10_CLK_EN=1, MPLLA_DIV8_CLK_EN=0
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL2,
+			TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_10);
+	/* VR MII MMD AN Control Register Bit[8] = 1'b1 MII_CTRL */
+	/* Set to 8bit MII (required in 10M/100M SGMII) */
+	txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_AN_CTL,
+			0x0100);
+
+	/* 10. Initialize the mode by setting VR XS or PCS MMD Digital Control1
+	 * Register Bit[15](VR_RST)
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1, 0xA000);
+	/* wait phy initialization done */
+	for (i = 0; i < TXGBE_PHY_INIT_DONE_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST) == 0)
+			break;
+		msleep(100);
+	}
+
+	/* if success, set link status */
+	hw->link_status = TXGBE_LINK_STATUS_KX;
+
+	if (i == TXGBE_PHY_INIT_DONE_POLLING_TIME) {
+		status = TXGBE_ERR_PHY_INIT_NOT_DONE;
+		goto out;
+	}
+
+	if ((KX_SET == 1) || (adapter->ffe_set == TXGBE_BP_M_KX)) {
+		e_dev_info("Set KX TX_EQ MAIN:%d PRE:%d POST:%d\n",
+					adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		/* 5. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL0 Register Bit[13:8](TX_EQ_MAIN)
+		* = 6'd30, Bit[5:0](TX_EQ_PRE) = 6'd4
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0);
+		value = (value & ~0x3F3F) | (adapter->ffe_main << 8) | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+		/* 6. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL1 Register Bit[6](TX_EQ_OVR_RIDE)
+		* = 1'b1, Bit[5:0](TX_EQ_POST) = 6'd36
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1);
+		value = (value & ~0x7F) | adapter->ffe_post | (1 << 6);
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	} 
+
+out:
+	return status;
+}
+
+s32 txgbe_set_link_to_sfi(struct txgbe_hw *hw,
+			       u32 speed)
+{
+	u32 i;
+	s32 status = 0;
+	u32 value = 0;
+	struct txgbe_adapter *adapter = hw->back;
+
+	/* Set the module link speed */
+	TCALL(hw, mac.ops.set_rate_select_speed,
+		speed);
+	
+	/* 1. Wait xpcs power-up good */
+	for (i = 0; i < TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_MASK) ==
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_POWER_GOOD)
+			break;
+		msleep(10);
+	}
+	if (i == TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME) {
+		status = TXGBE_ERR_XPCS_POWER_UP_FAILED;
+		goto out;
+	}
+
+	wr32m(hw, TXGBE_MAC_TX_CFG, TXGBE_MAC_TX_CFG_TE,
+			~TXGBE_MAC_TX_CFG_TE);
+
+	/* 2. Disable xpcs AN-73 */
+	txgbe_wr32_epcs(hw, TXGBE_SR_AN_MMD_CTL, 0x0);
+
+	if (hw->revision_id != TXGBE_SP_MPW) {
+		/* Disable PHY MPLLA for eth mode change(after ECO) */
+		txgbe_wr32_ephy(hw, 0x4, 0x243A);
+		TXGBE_WRITE_FLUSH(hw);
+		msleep(1);
+		/* Set the eth change_mode bit first in mis_rst register
+		 * for corresponding LAN port
+		 */
+		if (hw->bus.lan_id == 0)
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN0_CHG_ETH_MODE);
+		else
+			wr32(hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_LAN1_CHG_ETH_MODE);
+	}
+	if (speed == TXGBE_LINK_SPEED_10GB_FULL) {
+		/* @. Set SR PCS Control2 Register Bits[1:0] = 2'b00 PCS_TYPE_SEL: KR */
+		txgbe_wr32_epcs(hw, TXGBE_SR_PCS_CTL2, 0);
+		value = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+		value = value | 0x2000;
+		txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1, value);
+		/* @. Set VR_XS_PMA_Gen5_12G_MPLLA_CTRL0 Register Bit[7:0] = 8'd33
+		 * MPLLA_MULTIPLIER
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL0, 0x0021);
+		/* 3. Set VR_XS_PMA_Gen5_12G_MPLLA_CTRL3 Register
+		 * Bit[10:0](MPLLA_BANDWIDTH) = 11'd0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL3, 0);
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_GENCTRL1);
+		value = (value & ~0x700) | 0x500;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GENCTRL1, value);
+		/* 4.Set VR_XS_PMA_Gen5_12G_MISC_CTRL0 Register Bit[12:8](RX_VREF_CTRL)
+		 * = 5'hF
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0xCF00);
+		/* @. Set VR_XS_PMA_Gen5_12G_VCO_CAL_LD0 Register  Bit[12:0] = 13'd1353
+		 * VCO_LD_VAL_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD0, 0x0549);
+		/* @. Set VR_XS_PMA_Gen5_12G_VCO_CAL_REF0 Register Bit[5:0] = 6'd41
+		 * VCO_REF_LD_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF0, 0x0029);
+		/* @. Set VR_XS_PMA_Gen5_12G_TX_RATE_CTRL Register Bit[2:0] = 3'b000
+		 * TX0_RATE
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_RATE_CTL, 0);
+		/* @. Set VR_XS_PMA_Gen5_12G_RX_RATE_CTRL Register Bit[2:0] = 3'b000
+		 * RX0_RATE
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_RATE_CTL, 0);
+		/* @. Set VR_XS_PMA_Gen5_12G_TX_GENCTRL2 Register Bit[9:8] = 2'b11
+		 * TX0_WIDTH: 20bits
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GEN_CTL2, 0x0300);
+		/* @. Set VR_XS_PMA_Gen5_12G_RX_GENCTRL2 Register Bit[9:8] = 2'b11
+		 * RX0_WIDTH: 20bits
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL2, 0x0300);
+		/* @. Set VR_XS_PMA_Gen5_12G_MPLLA_CTRL2 Register Bit[10:8] = 3'b110
+		 * MPLLA_DIV16P5_CLK_EN=1, MPLLA_DIV10_CLK_EN=1, MPLLA_DIV8_CLK_EN=0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL2, 0x0600);
+
+		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+			hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+			/* 7. Set VR_XS_PMA_Gen5_12G_RX_EQ_CTRL0 Register
+			 * Bit[15:8](VGA1/2_GAIN_0) = 8'h77, Bit[7:5]
+			 * (CTLE_POLE_0) = 3'h2, Bit[4:0](CTLE_BOOST_0) = 4'hF
+			 */
+			txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0, 0x774F);
+
+		} else {
+			/* 7. Set VR_XS_PMA_Gen5_12G_RX_EQ_CTRL0 Register Bit[15:8]
+			 * (VGA1/2_GAIN_0) = 8'h00, Bit[7:5](CTLE_POLE_0) = 3'h2,
+			 * Bit[4:0](CTLE_BOOST_0) = 4'hA
+			 */
+			value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0);
+			value = (value & ~0xFFFF) | (2 << 5) | 0x05;
+			txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0, value);
+		}
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0);
+		value = (value & ~0x7) | 0x0;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0, value);
+
+		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+			hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+			/* 8. Set VR_XS_PMA_Gen5_12G_DFE_TAP_CTRL0 Register Bit[7:0](DFE_TAP1_0)
+			 * = 8'd20
+			 */
+			txgbe_wr32_epcs(hw, TXGBE_PHY_DFE_TAP_CTL0, 0x0014);
+			value = txgbe_rd32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE);
+			value = (value & ~0x11) | 0x11;
+			txgbe_wr32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE, value);
+		} else {
+			/* 8. Set VR_XS_PMA_Gen5_12G_DFE_TAP_CTRL0 Register Bit[7:0](DFE_TAP1_0)
+			 * = 8'd20
+			 */
+			txgbe_wr32_epcs(hw, TXGBE_PHY_DFE_TAP_CTL0, 0xBE);
+			/* 9. Set VR_MII_Gen5_12G_AFE_DFE_EN_CTRL Register Bit[4](DFE_EN_0) =
+			 * 1'b0, Bit[0](AFE_EN_0) = 1'b0
+			 */
+			value = txgbe_rd32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE);
+			value = (value & ~0x11) | 0x0;
+			txgbe_wr32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE, value);
+		}
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_CTL);
+		value = value & ~0x1;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL, value);
+	} else {
+		if (hw->revision_id == TXGBE_SP_MPW) {
+			/* Disable PHY MPLLA */
+			txgbe_wr32_ephy(hw, 0x4, 0x2401);
+			/* Reset rx lane0 clock */
+			txgbe_wr32_ephy(hw, 0x1005, 0x4001);
+		}
+		/* @. Set SR PCS Control2 Register Bits[1:0] = 2'b00 PCS_TYPE_SEL: KR */
+		txgbe_wr32_epcs(hw, TXGBE_SR_PCS_CTL2, 0x1);
+		/* Set SR PMA MMD Control1 Register Bit[13] = 1'b0  SS13: 1G speed */
+		txgbe_wr32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1, 0x0000);
+		/* Set SR MII MMD Control Register to corresponding speed: */
+		txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_CTL, 0x0140);
+
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_GENCTRL1);
+		value = (value & ~0x710) | 0x500;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GENCTRL1, value);
+		/* 4. Set VR_XS_PMA_Gen5_12G_MISC_CTRL0 Register Bit[12:8](RX_VREF_CTRL)
+		 * = 5'hF
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MISC_CTL0, 0xCF00);
+		/* 5. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL0 Register Bit[13:8](TX_EQ_MAIN)
+		 * = 6'd30, Bit[5:0](TX_EQ_PRE) = 6'd4
+		 */
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0);
+		value = (value & ~0x3F3F) | (24 << 8) | 4;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+		/* 6. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL1 Register Bit[6](TX_EQ_OVR_RIDE)
+		 * = 1'b1, Bit[5:0](TX_EQ_POST) = 6'd36
+		 */
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1);
+		value = (value & ~0x7F) | 16 | (1 << 6);
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+		if (hw->phy.sfp_type == txgbe_sfp_type_da_cu_core0 ||
+			hw->phy.sfp_type == txgbe_sfp_type_da_cu_core1) {
+			txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0, 0x774F);
+		} else {
+			/* 7. Set VR_XS_PMA_Gen5_12G_RX_EQ_CTRL0 Register Bit[15:8]
+			 * (VGA1/2_GAIN_0) = 8'h00, Bit[7:5](CTLE_POLE_0) = 3'h2,
+			 * Bit[4:0](CTLE_BOOST_0) = 4'hA
+			 */
+			value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0);
+			value = (value & ~0xFFFF) | 0x7706;
+			txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL0, value);
+		}
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0);
+		value = (value & ~0x7) | 0x0;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_ATT_LVL0, value);
+		/* 8. Set VR_XS_PMA_Gen5_12G_DFE_TAP_CTRL0 Register Bit[7:0](DFE_TAP1_0)
+		 * = 8'd00
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_DFE_TAP_CTL0, 0x0);
+		/* Set VR_XS_PMA_Gen5_12G_RX_GENCTRL3 Register Bit[2:0] LOS_TRSHLD_0 = 4 */
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_RX_GEN_CTL3);
+		value = (value & ~0x7) | 0x4;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL3, value);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY
+		 * MPLLA Control 0 Register Bit[7:0] = 8'd32  MPLLA_MULTIPLIER
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL0, 0x0020);
+		/* Set VR XS, PMA or MII Synopsys Enterprise Gen5 12G PHY MPLLA Control
+		 * 3 Register Bit[10:0] = 11'd70  MPLLA_BANDWIDTH
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL3, 0x0046);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO 
+		 * Calibration Load 0 Register  Bit[12:0] = 13'd1344  VCO_LD_VAL_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_LD0, 0x0540);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY VCO 
+		 * Calibration Reference 0 Register Bit[5:0] = 6'd42  VCO_REF_LD_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_VCO_CAL_REF0, 0x002A);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY AFE-DFE 
+		 * Enable Register Bit[4], Bit[0] = 1'b0  AFE_EN_0, DFE_EN_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_AFE_DFE_ENABLE, 0x0);
+		/* Set  VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx 
+		 * Equalization Control 4 Register Bit[0] = 1'b0  CONT_ADAPT_0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_EQ_CTL, 0x0010);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx Rate 
+		 * Control Register Bit[2:0] = 3'b011  TX0_RATE
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_RATE_CTL, 0x0003);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx Rate 
+		 * Control Register Bit[2:0] = 3'b011 
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_RATE_CTL, 0x0003);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Tx General 
+		 * Control 2 Register Bit[9:8] = 2'b01  TX0_WIDTH: 10bits
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_GEN_CTL2, 0x0100);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY Rx General 
+		 * Control 2 Register Bit[9:8] = 2'b01  RX0_WIDTH: 10bits
+		 */ 
+		txgbe_wr32_epcs(hw, TXGBE_PHY_RX_GEN_CTL2, 0x0100);
+		/* Set VR XS, PMA, or MII Synopsys Enterprise Gen5 12G PHY MPLLA 
+		 * Control 2 Register Bit[10:8] = 3'b010  MPLLA_DIV16P5_CLK_EN=0, 
+		 * MPLLA_DIV10_CLK_EN=1, MPLLA_DIV8_CLK_EN=0
+		 */
+		txgbe_wr32_epcs(hw, TXGBE_PHY_MPLLA_CTL2, 0x0200);
+		/* VR MII MMD AN Control Register Bit[8] = 1'b1 MII_CTRL */
+		txgbe_wr32_epcs(hw, TXGBE_SR_MII_MMD_AN_CTL, 0x0100);
+	}
+	/* 10. Initialize the mode by setting VR XS or PCS MMD Digital Control1
+	 * Register Bit[15](VR_RST)
+	 */
+	txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1, 0xA000);
+	/* wait phy initialization done */
+	for (i = 0; i < TXGBE_PHY_INIT_DONE_POLLING_TIME; i++) {
+		if ((txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1) &
+			TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST) == 0)
+			break;
+		msleep(100);
+	}
+	if (i == TXGBE_PHY_INIT_DONE_POLLING_TIME) {
+		status = TXGBE_ERR_PHY_INIT_NOT_DONE;
+		goto out;
+	}
+
+	if ((SFI_SET == 1) || (adapter->ffe_set == TXGBE_BP_M_SFI)) {
+		e_dev_info("Set SFI TX_EQ MAIN:%d PRE:%d POST:%d\n",
+					adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		/* 5. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL0 Register Bit[13:8](TX_EQ_MAIN)
+		* = 6'd30, Bit[5:0](TX_EQ_PRE) = 6'd4
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0);
+		value = (value & ~0x3F3F) | (adapter->ffe_main << 8) | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+		/* 6. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL1 Register Bit[6](TX_EQ_OVR_RIDE)
+		* = 1'b1, Bit[5:0](TX_EQ_POST) = 6'd36
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1);
+		value = (value & ~0x7F) | adapter->ffe_post | (1 << 6);
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	}
+out:
+	return status;
+}
+
+
+/**
+ *  txgbe_setup_mac_link - Set MAC link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ *  Set the link speed in the AUTOC register and restarts link.
+ **/
+s32 txgbe_setup_mac_link(struct txgbe_hw *hw,
+			       u32 speed,
+			       bool autoneg_wait_to_complete)
+{
+	bool autoneg = false;
+	s32 status = 0;
+	u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN;
+	struct txgbe_adapter *adapter = hw->back;
+	u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
+	bool link_up = false;
+	u32 curr_autoneg = 2;
+
+	/* Check to see if speed passed in is supported. */
+	status = TCALL(hw, mac.ops.get_link_capabilities,
+			       &link_capabilities, &autoneg);
+	if (status)
+		goto out;
+
+	speed &= link_capabilities;
+
+	if (speed == TXGBE_LINK_SPEED_UNKNOWN) {
+		status = TXGBE_ERR_LINK_SETUP;
+		goto out;
+	}
+
+	if ( ! (((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_KR_KX_KX4) ||
+			((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_MAC_XAUI) ||
+			((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_MAC_SGMII))){
+		status = TCALL(hw, mac.ops.check_link,
+				&link_speed, &link_up, false);
+
+	if (link_speed == TXGBE_LINK_SPEED_1GB_FULL){
+		curr_autoneg = txgbe_rd32_epcs(hw, TXGBE_SR_MII_MMD_CTL);
+		curr_autoneg = !!(curr_autoneg & (0x1 << 12));
+		}
+
+		if (status != 0)
+			goto out;
+		if ((link_speed == speed) && link_up 
+			&& !(speed == TXGBE_LINK_SPEED_1GB_FULL &&
+			(adapter->an37 != curr_autoneg)))
+			goto out;
+	}
+
+	if ((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_KR_KX_KX4) {
+		txgbe_set_link_to_kr(hw, autoneg);
+#if 0
+		if (!autoneg) {
+			switch (hw->phy.link_mode) {
+			case TXGBE_PHYSICAL_LAYER_10GBASE_KR:
+				txgbe_set_link_to_kr(hw, autoneg);
+				break;
+			case TXGBE_PHYSICAL_LAYER_10GBASE_KX4:
+				txgbe_set_link_to_kx4(hw, autoneg);
+				break;
+			case TXGBE_PHYSICAL_LAYER_1000BASE_KX:
+				txgbe_set_link_to_kx(hw, speed, autoneg);
+				break;
+			default:
+				status = TXGBE_ERR_PHY;
+				goto out;
+			}
+		} else {
+			txgbe_set_link_to_kr(hw, autoneg);
+		}
+#endif
+	} else if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI ||
+		((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_MAC_XAUI) ||
+		(hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_SGMII || 
+		((hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_MAC_SGMII) ||
+		(txgbe_get_media_type(hw) == txgbe_media_type_copper && 
+		(hw->subsystem_device_id & TXGBE_DEV_MASK) == TXGBE_ID_SFI_XAUI)) {
+	if (speed == TXGBE_LINK_SPEED_10GB_FULL) {
+		txgbe_set_link_to_kx4(hw, 0);
+	} else {
+		txgbe_set_link_to_kx(hw, speed, 0);
+			txgbe_set_sgmii_an37_ability(hw);
+			hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+		}
+	} else if (txgbe_get_media_type(hw) == txgbe_media_type_fiber) {
+		txgbe_set_link_to_sfi(hw, speed);
+		if (speed == TXGBE_LINK_SPEED_1GB_FULL) {
+			txgbe_setup_fc(hw);
+			txgbe_set_sgmii_an37_ability(hw);
+			hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+		}
+
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  txgbe_setup_copper_link - Set the PHY autoneg advertised field
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ *  Restarts link on PHY and MAC based on settings passed in.
+ **/
+STATIC s32 txgbe_setup_copper_link(struct txgbe_hw *hw,
+					 u32 speed,
+					 bool autoneg_wait_to_complete)
+{
+	s32 status;
+	u32 link_speed;
+
+	/* Setup the PHY according to input speed */
+	link_speed = TCALL(hw, phy.ops.setup_link_speed, speed,
+						autoneg_wait_to_complete);
+	
+	if (link_speed != TXGBE_LINK_SPEED_UNKNOWN)
+		/* Set up MAC */
+		status = txgbe_setup_mac_link(hw, link_speed, autoneg_wait_to_complete);
+	else {
+		status = 0;
+	}
+	return status;
+}
+
+int txgbe_reset_misc(struct txgbe_hw *hw)
+{
+	int i;
+	u32 value;
+
+	txgbe_init_i2c(hw);
+
+	value = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+	if ((value & 0x3) != TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X) {
+		hw->link_status = TXGBE_LINK_STATUS_NONE;
+	}
+
+	/* receive packets that size > 2048 */
+	wr32m(hw, TXGBE_MAC_RX_CFG,
+		TXGBE_MAC_RX_CFG_JE, TXGBE_MAC_RX_CFG_JE);
+
+	/* clear counters on read */
+	wr32m(hw, TXGBE_MMC_CONTROL,
+		TXGBE_MMC_CONTROL_RSTONRD, TXGBE_MMC_CONTROL_RSTONRD);
+
+	wr32m(hw, TXGBE_MAC_RX_FLOW_CTRL,
+		TXGBE_MAC_RX_FLOW_CTRL_RFE, TXGBE_MAC_RX_FLOW_CTRL_RFE);
+
+	wr32(hw, TXGBE_MAC_PKT_FLT,
+		TXGBE_MAC_PKT_FLT_PR);
+
+	wr32m(hw, TXGBE_MIS_RST_ST,
+		TXGBE_MIS_RST_ST_RST_INIT, 0x1E00);
+
+	/* errata 4: initialize mng flex tbl and wakeup flex tbl*/
+	wr32(hw, TXGBE_PSR_MNG_FLEX_SEL, 0);
+	for (i = 0; i < 16; i++) {
+		wr32(hw, TXGBE_PSR_MNG_FLEX_DW_L(i), 0);
+		wr32(hw, TXGBE_PSR_MNG_FLEX_DW_H(i), 0);
+		wr32(hw, TXGBE_PSR_MNG_FLEX_MSK(i), 0);
+	}
+	wr32(hw, TXGBE_PSR_LAN_FLEX_SEL, 0);
+	for (i = 0; i < 16; i++) {
+		wr32(hw, TXGBE_PSR_LAN_FLEX_DW_L(i), 0);
+		wr32(hw, TXGBE_PSR_LAN_FLEX_DW_H(i), 0);
+		wr32(hw, TXGBE_PSR_LAN_FLEX_MSK(i), 0);
+	}
+
+	/* set pause frame dst mac addr */
+	wr32(hw, TXGBE_RDB_PFCMACDAL, 0xC2000001);
+	wr32(hw, TXGBE_RDB_PFCMACDAH, 0x0180);
+
+	txgbe_init_thermal_sensor_thresh(hw);
+
+	return 0;
+}
+
+/**
+ *  txgbe_reset_hw - Perform hardware reset
+ *  @hw: pointer to hardware structure
+ *
+ *  Resets the hardware by resetting the transmit and receive units, masks
+ *  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
+ *  reset.
+ **/
+s32 txgbe_reset_hw(struct txgbe_hw *hw)
+{
+	s32 status;
+	u32 reset = 0;
+	u32 i;
+	u32 sr_pcs_ctl, sr_pma_mmd_ctl1, sr_an_mmd_ctl, sr_an_mmd_adv_reg2;
+	u32 vr_xs_or_pcs_mmd_digi_ctl1, curr_vr_xs_or_pcs_mmd_digi_ctl1;
+	u32 curr_sr_pcs_ctl, curr_sr_pma_mmd_ctl1;
+	u32 curr_sr_an_mmd_ctl, curr_sr_an_mmd_adv_reg2;
+	u32 reset_status = 0;
+	u32 rst_delay = 0;
+	struct txgbe_adapter *adapter = hw->back;
+	u32 value;
+
+	/* Call adapter stop to disable tx/rx and clear interrupts */
+	status = TCALL(hw, mac.ops.stop_adapter);
+	if (status != 0)
+		goto reset_hw_out;
+
+	/* Identify PHY and related function pointers */
+	status = TCALL(hw, phy.ops.init);
+
+	if (status == TXGBE_ERR_SFP_NOT_SUPPORTED)
+		goto reset_hw_out;
+
+	/* Reset PHY */
+	if (txgbe_get_media_type(hw) == txgbe_media_type_copper)
+		TCALL(hw, phy.ops.reset);
+
+	/* remember internel phy regs from before we reset */
+	curr_sr_pcs_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+	curr_sr_pma_mmd_ctl1 = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	curr_sr_an_mmd_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_CTL);
+	curr_sr_an_mmd_adv_reg2 = txgbe_rd32_epcs(hw,
+						TXGBE_SR_AN_MMD_ADV_REG2);
+	curr_vr_xs_or_pcs_mmd_digi_ctl1 =
+		txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1);
+
+	/*
+	 * Issue global reset to the MAC.  Needs to be SW reset if link is up.
+	 * If link reset is used when link is up, it might reset the PHY when
+	 * mng is using it.  If link is down or the flag to force full link
+	 * reset is set, then perform link reset.
+	 */
+	if (hw->force_full_reset) {
+		rst_delay = (rd32(hw, TXGBE_MIS_RST_ST) &
+			TXGBE_MIS_RST_ST_RST_INIT) >>
+			TXGBE_MIS_RST_ST_RST_INI_SHIFT;
+		if (hw->reset_type == TXGBE_SW_RESET) {
+			for (i = 0; i < rst_delay + 20; i++) {
+				reset_status =
+					rd32(hw, TXGBE_MIS_RST_ST);
+				if (!(reset_status &
+				    TXGBE_MIS_RST_ST_DEV_RST_ST_MASK))
+					break;
+				msleep(100);
+			}
+
+			if (reset_status & TXGBE_MIS_RST_ST_DEV_RST_ST_MASK) {
+				status = TXGBE_ERR_RESET_FAILED;
+				DEBUGOUT("Global reset polling failed to "
+					"complete.\n");
+				goto reset_hw_out;
+			}
+			status = txgbe_check_flash_load(hw,
+						TXGBE_SPI_ILDR_STATUS_SW_RESET);
+			if (status != 0)
+				goto reset_hw_out;
+			/* errata 7 */
+			if (txgbe_mng_present(hw) &&
+				hw->revision_id == TXGBE_SP_MPW) {
+				struct txgbe_adapter *adapter =
+					(struct txgbe_adapter *)hw->back;
+				adapter->flags2 &=
+					~TXGBE_FLAG2_MNG_REG_ACCESS_DISABLED;
+			}
+		} else if (hw->reset_type == TXGBE_GLOBAL_RESET) {
+#ifndef _WIN32
+			struct txgbe_adapter *adapter =
+					(struct txgbe_adapter *)hw->back;
+			msleep(100 * rst_delay + 2000);
+			pci_restore_state(adapter->pdev);
+			pci_save_state(adapter->pdev);
+			pci_wake_from_d3(adapter->pdev, false);
+#endif /*_WIN32*/
+		}
+	} else {
+		if (txgbe_mng_present(hw)) {
+			if (!(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)||
+				((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP))){
+				txgbe_reset_hostif(hw);
+			}
+		} else {
+			if (hw->bus.lan_id == 0) {
+				reset = TXGBE_MIS_RST_LAN0_RST;
+			} else {
+				reset = TXGBE_MIS_RST_LAN1_RST;
+			}
+
+			wr32(hw, TXGBE_MIS_RST,
+				reset | rd32(hw, TXGBE_MIS_RST));
+			TXGBE_WRITE_FLUSH(hw);
+		}
+		usec_delay(10);
+
+		if (hw->bus.lan_id == 0) {
+			status = txgbe_check_flash_load(hw,
+					TXGBE_SPI_ILDR_STATUS_LAN0_SW_RST);
+		} else {
+			status = txgbe_check_flash_load(hw,
+					TXGBE_SPI_ILDR_STATUS_LAN1_SW_RST);
+		}
+		if (status != 0)
+			goto reset_hw_out;
+	}
+
+	status = txgbe_reset_misc(hw);
+	if (status != 0)
+		goto reset_hw_out;
+
+	/*
+	 * Store the original AUTOC/AUTOC2 values if they have not been
+	 * stored off yet.  Otherwise restore the stored original
+	 * values since the reset operation sets back to defaults.
+	 */
+	sr_pcs_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_PCS_CTL2);
+	sr_pma_mmd_ctl1 = txgbe_rd32_epcs(hw, TXGBE_SR_PMA_MMD_CTL1);
+	sr_an_mmd_ctl = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_CTL);
+	sr_an_mmd_adv_reg2 = txgbe_rd32_epcs(hw, TXGBE_SR_AN_MMD_ADV_REG2);
+	vr_xs_or_pcs_mmd_digi_ctl1 =
+		txgbe_rd32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1);
+
+	if (hw->mac.orig_link_settings_stored == false) {
+		hw->mac.orig_sr_pcs_ctl2 = sr_pcs_ctl;
+		hw->mac.orig_sr_pma_mmd_ctl1 = sr_pma_mmd_ctl1;
+		hw->mac.orig_sr_an_mmd_ctl = sr_an_mmd_ctl;
+		hw->mac.orig_sr_an_mmd_adv_reg2 = sr_an_mmd_adv_reg2;
+		hw->mac.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
+						vr_xs_or_pcs_mmd_digi_ctl1;
+		hw->mac.orig_link_settings_stored = true;
+	} else {
+
+		/* If MNG FW is running on a multi-speed device that
+		 * doesn't autoneg with out driver support we need to
+		 * leave LMS in the state it was before we MAC reset.
+		 * Likewise if we support WoL we don't want change the
+		 * LMS state.
+		 */
+
+		hw->mac.orig_sr_pcs_ctl2 = curr_sr_pcs_ctl;
+		hw->mac.orig_sr_pma_mmd_ctl1 = curr_sr_pma_mmd_ctl1;
+		hw->mac.orig_sr_an_mmd_ctl = curr_sr_an_mmd_ctl;
+		hw->mac.orig_sr_an_mmd_adv_reg2 =
+					curr_sr_an_mmd_adv_reg2;
+		hw->mac.orig_vr_xs_or_pcs_mmd_digi_ctl1 =
+					curr_vr_xs_or_pcs_mmd_digi_ctl1;
+
+	}
+
+	/*make sure phy power is up*/
+	msleep(100);
+	/*A temporary solution for set to sfi*/
+	if(SFI_SET == 1 || adapter->ffe_set == TXGBE_BP_M_SFI) {
+		e_dev_info("Set SFI TX_EQ MAIN:%d PRE:%d POST:%d\n",
+					adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		/* 5. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL0 Register Bit[13:8](TX_EQ_MAIN)
+		* = 6'd30, Bit[5:0](TX_EQ_PRE) = 6'd4
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0);
+		value = (value & ~0x3F3F) | (adapter->ffe_main << 8) | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+		/* 6. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL1 Register Bit[6](TX_EQ_OVR_RIDE)
+		* = 1'b1, Bit[5:0](TX_EQ_POST) = 6'd36
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1);
+		value = (value & ~0x7F) | adapter->ffe_post | (1 << 6);
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	}
+
+	if (KR_SET == 1 || adapter->ffe_set == TXGBE_BP_M_KR) {
+		e_dev_info("Set KR TX_EQ MAIN:%d PRE:%d POST:%d\n",
+				adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		value = (0x1804 & ~0x3F3F);
+		value |= adapter->ffe_main << 8 | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+
+		value = (0x50 & ~0x7F) | (1 << 6)| adapter->ffe_post;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+	}
+
+	if(KX_SET == 1 || adapter->ffe_set == TXGBE_BP_M_KX) {
+		e_dev_info("Set KX TX_EQ MAIN:%d PRE:%d POST:%d\n",
+					adapter->ffe_main,adapter->ffe_pre,adapter->ffe_post);
+		/* 5. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL0 Register Bit[13:8](TX_EQ_MAIN)
+		* = 6'd30, Bit[5:0](TX_EQ_PRE) = 6'd4
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0);
+		value = (value & ~0x3F3F) | (adapter->ffe_main << 8) | adapter->ffe_pre;
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL0, value);
+		/* 6. Set VR_XS_PMA_Gen5_12G_TX_EQ_CTRL1 Register Bit[6](TX_EQ_OVR_RIDE)
+		* = 1'b1, Bit[5:0](TX_EQ_POST) = 6'd36
+		*/
+		value = txgbe_rd32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1);
+		value = (value & ~0x7F) | adapter->ffe_post | (1 << 6);
+		txgbe_wr32_epcs(hw, TXGBE_PHY_TX_EQ_CTL1, value);
+		
+	}
+	
+	/* Store the permanent mac address */
+	TCALL(hw, mac.ops.get_mac_addr, hw->mac.perm_addr);
+
+	/*
+	 * Store MAC address from RAR0, clear receive address registers, and
+	 * clear the multicast table.  Also reset num_rar_entries to 128,
+	 * since we modify this value when programming the SAN MAC address.
+	 */
+	hw->mac.num_rar_entries = 128;
+	TCALL(hw, mac.ops.init_rx_addrs);
+
+	/* Store the permanent SAN mac address */
+	TCALL(hw, mac.ops.get_san_mac_addr, hw->mac.san_addr);
+
+	/* Add the SAN MAC address to the RAR only if it's a valid address */
+	if (txgbe_validate_mac_addr(hw->mac.san_addr) == 0) {
+		TCALL(hw, mac.ops.set_rar, hw->mac.num_rar_entries - 1,
+		      hw->mac.san_addr, 0, TXGBE_PSR_MAC_SWC_AD_H_AV);
+
+		/* Save the SAN MAC RAR index */
+		hw->mac.san_mac_rar_index = hw->mac.num_rar_entries - 1;
+
+		/* Reserve the last RAR for the SAN MAC address */
+		hw->mac.num_rar_entries--;
+	}
+
+	/* Store the alternative WWNN/WWPN prefix */
+	TCALL(hw, mac.ops.get_wwn_prefix, &hw->mac.wwnn_prefix,
+				   &hw->mac.wwpn_prefix);
+
+	pci_set_master(((struct txgbe_adapter *)hw->back)->pdev);
+
+reset_hw_out:
+	return status;
+}
+
+#if 0
+void txgbe_disable_fdir(struct txgbe_hw *hw)
+{
+	int val = 0;
+
+	if (!hw->Fdir_enabled) {
+		wr32(hw, TXGBE_RDB_FDIR_CTL, 0x4AF07F18);
+		TXGBE_WRITE_FLUSH(hw);
+	}
+	val = rd32(hw, TXGBE_RDB_FDIR_CTL);
+}
+#endif
+
+/**
+ * txgbe_fdir_check_cmd_complete - poll to check whether FDIRCMD is complete
+ * @hw: pointer to hardware structure
+ * @fdircmd: current value of FDIRCMD register
+ */
+STATIC s32 txgbe_fdir_check_cmd_complete(struct txgbe_hw *hw, u32 *fdircmd)
+{
+	int i;
+
+	for (i = 0; i < TXGBE_RDB_FDIR_CMD_CMD_POLL; i++) {
+		*fdircmd = rd32(hw, TXGBE_RDB_FDIR_CMD);
+		if (!(*fdircmd & TXGBE_RDB_FDIR_CMD_CMD_MASK))
+			return 0;
+		usec_delay(10);
+	}
+
+	return TXGBE_ERR_FDIR_CMD_INCOMPLETE;
+}
+
+/**
+ *  txgbe_reinit_fdir_tables - Reinitialize Flow Director tables.
+ *  @hw: pointer to hardware structure
+ **/
+s32 txgbe_reinit_fdir_tables(struct txgbe_hw *hw)
+{
+	s32 err;
+	int i;
+	u32 fdirctrl = rd32(hw, TXGBE_RDB_FDIR_CTL);
+	u32 fdircmd;
+	fdirctrl &= ~TXGBE_RDB_FDIR_CTL_INIT_DONE;
+
+	/*
+	 * Before starting reinitialization process,
+	 * FDIRCMD.CMD must be zero.
+	 */
+	err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
+	if (err) {
+		DEBUGOUT("Flow Director previous command did not complete, "
+			 "aborting table re-initialization.\n");
+		return err;
+	}
+
+	wr32(hw, TXGBE_RDB_FDIR_FREE, 0);
+	TXGBE_WRITE_FLUSH(hw);
+	/*
+	 * sapphire adapters flow director init flow cannot be restarted,
+	 * Workaround sapphire silicon errata by performing the following steps
+	 * before re-writing the FDIRCTRL control register with the same value.
+	 * - write 1 to bit 8 of FDIRCMD register &
+	 * - write 0 to bit 8 of FDIRCMD register
+	 */
+	wr32m(hw, TXGBE_RDB_FDIR_CMD,
+		TXGBE_RDB_FDIR_CMD_CLEARHT, TXGBE_RDB_FDIR_CMD_CLEARHT);
+	TXGBE_WRITE_FLUSH(hw);
+	wr32m(hw, TXGBE_RDB_FDIR_CMD,
+		TXGBE_RDB_FDIR_CMD_CLEARHT, 0);
+	TXGBE_WRITE_FLUSH(hw);
+	/*
+	 * Clear FDIR Hash register to clear any leftover hashes
+	 * waiting to be programmed.
+	 */
+	wr32(hw, TXGBE_RDB_FDIR_HASH, 0x00);
+	TXGBE_WRITE_FLUSH(hw);
+
+	wr32(hw, TXGBE_RDB_FDIR_CTL, fdirctrl);
+	TXGBE_WRITE_FLUSH(hw);
+
+	/* Poll init-done after we write FDIRCTRL register */
+	for (i = 0; i < TXGBE_FDIR_INIT_DONE_POLL; i++) {
+		if (rd32(hw, TXGBE_RDB_FDIR_CTL) &
+				   TXGBE_RDB_FDIR_CTL_INIT_DONE)
+			break;
+		msec_delay(1);
+	}
+	if (i >= TXGBE_FDIR_INIT_DONE_POLL) {
+		DEBUGOUT("Flow Director Signature poll time exceeded!\n");
+		return TXGBE_ERR_FDIR_REINIT_FAILED;
+	}
+
+	/* Clear FDIR statistics registers (read to clear) */
+	rd32(hw, TXGBE_RDB_FDIR_USE_ST);
+	rd32(hw, TXGBE_RDB_FDIR_FAIL_ST);
+	rd32(hw, TXGBE_RDB_FDIR_MATCH);
+	rd32(hw, TXGBE_RDB_FDIR_MISS);
+	rd32(hw, TXGBE_RDB_FDIR_LEN);
+
+	return 0;
+}
+
+/**
+ *  txgbe_fdir_enable - Initialize Flow Director control registers
+ *  @hw: pointer to hardware structure
+ *  @fdirctrl: value to write to flow director control register
+ **/
+STATIC void txgbe_fdir_enable(struct txgbe_hw *hw, u32 fdirctrl)
+{
+	int i;
+
+	/* Prime the keys for hashing */
+	wr32(hw, TXGBE_RDB_FDIR_HKEY, TXGBE_ATR_BUCKET_HASH_KEY);
+	wr32(hw, TXGBE_RDB_FDIR_SKEY, TXGBE_ATR_SIGNATURE_HASH_KEY);
+
+	/*
+	 * Poll init-done after we write the register.  Estimated times:
+	 *      10G: PBALLOC = 11b, timing is 60us
+	 *       1G: PBALLOC = 11b, timing is 600us
+	 *     100M: PBALLOC = 11b, timing is 6ms
+	 *
+	 *     Multiple these timings by 4 if under full Rx load
+	 *
+	 * So we'll poll for TXGBE_FDIR_INIT_DONE_POLL times, sleeping for
+	 * 1 msec per poll time.  If we're at line rate and drop to 100M, then
+	 * this might not finish in our poll time, but we can live with that
+	 * for now.
+	 */
+	wr32(hw, TXGBE_RDB_FDIR_CTL, fdirctrl);
+	TXGBE_WRITE_FLUSH(hw);
+	for (i = 0; i < TXGBE_RDB_FDIR_INIT_DONE_POLL; i++) {
+		if (rd32(hw, TXGBE_RDB_FDIR_CTL) &
+				   TXGBE_RDB_FDIR_CTL_INIT_DONE)
+			break;
+		msec_delay(1);
+	}
+
+	if (i >= TXGBE_RDB_FDIR_INIT_DONE_POLL)
+		DEBUGOUT("Flow Director poll time exceeded!\n");
+}
+
+/**
+ *  txgbe_init_fdir_signature -Initialize Flow Director sig filters
+ *  @hw: pointer to hardware structure
+ *  @fdirctrl: value to write to flow director control register, initially
+ *           contains just the value of the Rx packet buffer allocation
+ **/
+s32 txgbe_init_fdir_signature(struct txgbe_hw *hw, u32 fdirctrl)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)hw->back;
+	int i = VMDQ_P(0) / 4;
+	int j = VMDQ_P(0) % 4;
+	u32 flex = rd32m(hw, TXGBE_RDB_FDIR_FLEX_CFG(i),
+		~((TXGBE_RDB_FDIR_FLEX_CFG_BASE_MSK |
+		TXGBE_RDB_FDIR_FLEX_CFG_MSK |
+		TXGBE_RDB_FDIR_FLEX_CFG_OFST) <<
+		(TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT * j)));
+
+	UNREFERENCED_PARAMETER(adapter);
+
+	flex |= (TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC |
+		0x6 << TXGBE_RDB_FDIR_FLEX_CFG_OFST_SHIFT) <<
+		(TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT * j);
+	wr32(hw, TXGBE_RDB_FDIR_FLEX_CFG(i), flex);
+
+	/*
+	 * Continue setup of fdirctrl register bits:
+	 *  Move the flexible bytes to use the ethertype - shift 6 words
+	 *  Set the maximum length per hash bucket to 0xA filters
+	 *  Send interrupt when 64 filters are left
+	 */
+	fdirctrl |= (0xF << TXGBE_RDB_FDIR_CTL_HASH_BITS_SHIFT) |
+		    (0xA << TXGBE_RDB_FDIR_CTL_MAX_LENGTH_SHIFT) |
+		    (4 << TXGBE_RDB_FDIR_CTL_FULL_THRESH_SHIFT);
+
+	/* write hashes and fdirctrl register, poll for completion */
+	txgbe_fdir_enable(hw, fdirctrl);
+
+	if (hw->revision_id == TXGBE_SP_MPW) {
+		/* errata 1: disable RSC of drop ring 0 */
+		wr32m(hw, TXGBE_PX_RR_CFG(0),
+				TXGBE_PX_RR_CFG_RSC, ~TXGBE_PX_RR_CFG_RSC);
+	}
+	return 0;
+}
+
+/**
+ *  txgbe_init_fdir_perfect - Initialize Flow Director perfect filters
+ *  @hw: pointer to hardware structure
+ *  @fdirctrl: value to write to flow director control register, initially
+ *           contains just the value of the Rx packet buffer allocation
+ *  @cloud_mode: true - cloud mode, false - other mode
+ **/
+s32 txgbe_init_fdir_perfect(struct txgbe_hw *hw, u32 fdirctrl,
+			bool cloud_mode)
+{
+	/*
+	 * Continue setup of fdirctrl register bits:
+	 *  Turn perfect match filtering on
+	 *  Report hash in RSS field of Rx wb descriptor
+	 *  Initialize the drop queue
+	 *  Move the flexible bytes to use the ethertype - shift 6 words
+	 *  Set the maximum length per hash bucket to 0xA filters
+	 *  Send interrupt when 64 (0x4 * 16) filters are left
+	 */
+	fdirctrl |= TXGBE_RDB_FDIR_CTL_PERFECT_MATCH |
+		    (TXGBE_RDB_FDIR_DROP_QUEUE <<
+		    TXGBE_RDB_FDIR_CTL_DROP_Q_SHIFT) |
+		    (0xF << TXGBE_RDB_FDIR_CTL_HASH_BITS_SHIFT) |
+		    (0xA << TXGBE_RDB_FDIR_CTL_MAX_LENGTH_SHIFT) |
+		    (4 << TXGBE_RDB_FDIR_CTL_FULL_THRESH_SHIFT);
+
+	/* write hashes and fdirctrl register, poll for completion */
+	txgbe_fdir_enable(hw, fdirctrl);
+
+	if (hw->revision_id == TXGBE_SP_MPW) {
+		if (((struct txgbe_adapter *)hw->back)->num_rx_queues >
+			TXGBE_RDB_FDIR_DROP_QUEUE)
+			/* errata 1: disable RSC of drop ring */
+			wr32m(hw,
+					TXGBE_PX_RR_CFG(TXGBE_RDB_FDIR_DROP_QUEUE),
+					TXGBE_PX_RR_CFG_RSC, ~TXGBE_PX_RR_CFG_RSC);
+	}
+	return 0;
+}
+
+/*
+ * These defines allow us to quickly generate all of the necessary instructions
+ * in the function below by simply calling out TXGBE_COMPUTE_SIG_HASH_ITERATION
+ * for values 0 through 15
+ */
+#define TXGBE_ATR_COMMON_HASH_KEY \
+		(TXGBE_ATR_BUCKET_HASH_KEY & TXGBE_ATR_SIGNATURE_HASH_KEY)
+#define TXGBE_COMPUTE_SIG_HASH_ITERATION(_n) \
+do { \
+	u32 n = (_n); \
+	if (TXGBE_ATR_COMMON_HASH_KEY & (0x01 << n)) \
+		common_hash ^= lo_hash_dword >> n; \
+	else if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \
+		bucket_hash ^= lo_hash_dword >> n; \
+	else if (TXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << n)) \
+		sig_hash ^= lo_hash_dword << (16 - n); \
+	if (TXGBE_ATR_COMMON_HASH_KEY & (0x01 << (n + 16))) \
+		common_hash ^= hi_hash_dword >> n; \
+	else if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \
+		bucket_hash ^= hi_hash_dword >> n; \
+	else if (TXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << (n + 16))) \
+		sig_hash ^= hi_hash_dword << (16 - n); \
+} while (0)
+
+/**
+ *  txgbe_atr_compute_sig_hash - Compute the signature hash
+ *  @stream: input bitstream to compute the hash on
+ *
+ *  This function is almost identical to the function above but contains
+ *  several optimizations such as unwinding all of the loops, letting the
+ *  compiler work out all of the conditional ifs since the keys are static
+ *  defines, and computing two keys at once since the hashed dword stream
+ *  will be the same for both keys.
+ **/
+u32 txgbe_atr_compute_sig_hash(union txgbe_atr_hash_dword input,
+				     union txgbe_atr_hash_dword common)
+{
+	u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
+	u32 sig_hash = 0, bucket_hash = 0, common_hash = 0;
+
+	/* record the flow_vm_vlan bits as they are a key part to the hash */
+	flow_vm_vlan = TXGBE_NTOHL(input.dword);
+
+	/* generate common hash dword */
+	hi_hash_dword = TXGBE_NTOHL(common.dword);
+
+	/* low dword is word swapped version of common */
+	lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
+
+	/* apply flow ID/VM pool/VLAN ID bits to hash words */
+	hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
+
+	/* Process bits 0 and 16 */
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(0);
+
+	/*
+	 * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
+	 * delay this because bit 0 of the stream should not be processed
+	 * so we do not add the VLAN until after bit 0 was processed
+	 */
+	lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
+
+	/* Process remaining 30 bit of the key */
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(1);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(2);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(3);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(4);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(5);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(6);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(7);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(8);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(9);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(10);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(11);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(12);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(13);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(14);
+	TXGBE_COMPUTE_SIG_HASH_ITERATION(15);
+
+	/* combine common_hash result with signature and bucket hashes */
+	bucket_hash ^= common_hash;
+	bucket_hash &= TXGBE_ATR_HASH_MASK;
+
+	sig_hash ^= common_hash << 16;
+	sig_hash &= TXGBE_ATR_HASH_MASK << 16;
+
+	/* return completed signature hash */
+	return sig_hash ^ bucket_hash;
+}
+
+/**
+ *  txgbe_atr_add_signature_filter - Adds a signature hash filter
+ *  @hw: pointer to hardware structure
+ *  @input: unique input dword
+ *  @common: compressed common input dword
+ *  @queue: queue index to direct traffic to
+ **/
+s32 txgbe_fdir_add_signature_filter(struct txgbe_hw *hw,
+					  union txgbe_atr_hash_dword input,
+					  union txgbe_atr_hash_dword common,
+					  u8 queue)
+{
+	u32 fdirhashcmd = 0;
+	u8 flow_type;
+	u32 fdircmd;
+	s32 err;
+
+	/*
+	 * Get the flow_type in order to program FDIRCMD properly
+	 * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6
+	 * fifth is FDIRCMD.TUNNEL_FILTER
+	 */
+	flow_type = input.formatted.flow_type;
+	switch (flow_type) {
+	case TXGBE_ATR_FLOW_TYPE_TCPV4:
+	case TXGBE_ATR_FLOW_TYPE_UDPV4:
+	case TXGBE_ATR_FLOW_TYPE_SCTPV4:
+	case TXGBE_ATR_FLOW_TYPE_TCPV6:
+	case TXGBE_ATR_FLOW_TYPE_UDPV6:
+	case TXGBE_ATR_FLOW_TYPE_SCTPV6:
+		break;
+	default:
+		DEBUGOUT(" Error on flow type input\n");
+		return TXGBE_ERR_CONFIG;
+	}
+
+	/* configure FDIRCMD register */
+	fdircmd = TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW |
+		  TXGBE_RDB_FDIR_CMD_FILTER_UPDATE |
+		  TXGBE_RDB_FDIR_CMD_LAST | TXGBE_RDB_FDIR_CMD_QUEUE_EN;
+	fdircmd |= (u32)flow_type << TXGBE_RDB_FDIR_CMD_FLOW_TYPE_SHIFT;
+	fdircmd |= (u32)queue << TXGBE_RDB_FDIR_CMD_RX_QUEUE_SHIFT;
+
+	fdirhashcmd |= txgbe_atr_compute_sig_hash(input, common);
+	fdirhashcmd |= 0x1 << TXGBE_RDB_FDIR_HASH_BUCKET_VALID_SHIFT;
+	wr32(hw, TXGBE_RDB_FDIR_HASH, fdirhashcmd);
+
+	wr32(hw, TXGBE_RDB_FDIR_CMD, fdircmd);
+
+	err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
+	if (err) {
+		DEBUGOUT("Flow Director command did not complete!\n");
+		return err;
+	}
+
+	DEBUGOUT2("Tx Queue=%x hash=%x\n", queue, (u32)fdirhashcmd);
+
+	return 0;
+}
+
+#define TXGBE_COMPUTE_BKT_HASH_ITERATION(_n) \
+do { \
+	u32 n = (_n); \
+	if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \
+		bucket_hash ^= lo_hash_dword >> n; \
+	if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \
+		bucket_hash ^= hi_hash_dword >> n; \
+} while (0)
+
+/**
+ *  txgbe_atr_compute_perfect_hash - Compute the perfect filter hash
+ *  @atr_input: input bitstream to compute the hash on
+ *  @input_mask: mask for the input bitstream
+ *
+ *  This function serves two main purposes.  First it applies the input_mask
+ *  to the atr_input resulting in a cleaned up atr_input data stream.
+ *  Secondly it computes the hash and stores it in the bkt_hash field at
+ *  the end of the input byte stream.  This way it will be available for
+ *  future use without needing to recompute the hash.
+ **/
+void txgbe_atr_compute_perfect_hash(union txgbe_atr_input *input,
+					  union txgbe_atr_input *input_mask)
+{
+	u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
+	u32 bucket_hash = 0;
+	u32 hi_dword = 0;
+	u32 i = 0;
+
+	/* Apply masks to input data */
+	for (i = 0; i < 11; i++)
+		input->dword_stream[i]  &= input_mask->dword_stream[i];
+
+	/* record the flow_vm_vlan bits as they are a key part to the hash */
+	flow_vm_vlan = TXGBE_NTOHL(input->dword_stream[0]);
+
+	/* generate common hash dword */
+	for (i = 1; i <= 10; i++)
+		hi_dword ^= input->dword_stream[i];
+	hi_hash_dword = TXGBE_NTOHL(hi_dword);
+
+	/* low dword is word swapped version of common */
+	lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
+
+	/* apply flow ID/VM pool/VLAN ID bits to hash words */
+	hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16);
+
+	/* Process bits 0 and 16 */
+	TXGBE_COMPUTE_BKT_HASH_ITERATION(0);
+
+	/*
+	 * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
+	 * delay this because bit 0 of the stream should not be processed
+	 * so we do not add the VLAN until after bit 0 was processed
+	 */
+	lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
+
+	/* Process remaining 30 bit of the key */
+	for (i = 1; i <= 15; i++)
+		TXGBE_COMPUTE_BKT_HASH_ITERATION(i);
+
+	/*
+	 * Limit hash to 13 bits since max bucket count is 8K.
+	 * Store result at the end of the input stream.
+	 */
+	input->formatted.bkt_hash = bucket_hash & 0x1FFF;
+}
+
+/**
+ *  txgbe_get_fdirtcpm - generate a TCP port from atr_input_masks
+ *  @input_mask: mask to be bit swapped
+ *
+ *  The source and destination port masks for flow director are bit swapped
+ *  in that bit 15 effects bit 0, 14 effects 1, 13, 2 etc.  In order to
+ *  generate a correctly swapped value we need to bit swap the mask and that
+ *  is what is accomplished by this function.
+ **/
+STATIC u32 txgbe_get_fdirtcpm(union txgbe_atr_input *input_mask)
+{
+	u32 mask = TXGBE_NTOHS(input_mask->formatted.dst_port);
+	mask <<= TXGBE_RDB_FDIR_TCP_MSK_DPORTM_SHIFT;
+	mask |= TXGBE_NTOHS(input_mask->formatted.src_port);
+
+	return mask;
+}
+
+/*
+ * These two macros are meant to address the fact that we have registers
+ * that are either all or in part big-endian.  As a result on big-endian
+ * systems we will end up byte swapping the value to little-endian before
+ * it is byte swapped again and written to the hardware in the original
+ * big-endian format.
+ */
+#define TXGBE_STORE_AS_BE32(_value) \
+	(((u32)(_value) >> 24) | (((u32)(_value) & 0x00FF0000) >> 8) | \
+	 (((u32)(_value) & 0x0000FF00) << 8) | ((u32)(_value) << 24))
+
+#define TXGBE_WRITE_REG_BE32(a, reg, value) \
+	wr32((a), (reg), TXGBE_STORE_AS_BE32(TXGBE_NTOHL(value)))
+
+#define TXGBE_STORE_AS_BE16(_value) \
+	TXGBE_NTOHS(((u16)(_value) >> 8) | ((u16)(_value) << 8))
+
+s32 txgbe_fdir_set_input_mask(struct txgbe_hw *hw,
+				       union txgbe_atr_input *input_mask,
+				       bool cloud_mode)
+{
+	/* mask IPv6 since it is currently not supported */
+	u32 fdirm = 0;
+	u32 fdirtcpm;
+	u32 flex = 0;
+	int i, j;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)hw->back;
+
+	/*
+	 * Program the relevant mask registers.  If src/dst_port or src/dst_addr
+	 * are zero, then assume a full mask for that field.  Also assume that
+	 * a VLAN of 0 is unspecified, so mask that out as well.  L4type
+	 * cannot be masked out in this implementation.
+	 *
+	 * This also assumes IPv4 only.  IPv6 masking isn't supported at this
+	 * point in time.
+	 */
+
+	/* verify bucket hash is cleared on hash generation */
+	if (input_mask->formatted.bkt_hash)
+		DEBUGOUT(" bucket hash should always be 0 in mask\n");
+
+	/* Program FDIRM and verify partial masks */
+	switch (input_mask->formatted.vm_pool & 0x7F) {
+	case 0x0:
+		fdirm |= TXGBE_RDB_FDIR_OTHER_MSK_POOL;
+	case 0x7F:
+		break;
+	default:
+		DEBUGOUT(" Error on vm pool mask\n");
+		return TXGBE_ERR_CONFIG;
+	}
+
+	switch (input_mask->formatted.flow_type & TXGBE_ATR_L4TYPE_MASK) {
+	case 0x0:
+		fdirm |= TXGBE_RDB_FDIR_OTHER_MSK_L4P;
+		if (input_mask->formatted.dst_port ||
+		    input_mask->formatted.src_port) {
+			DEBUGOUT(" Error on src/dst port mask\n");
+			return TXGBE_ERR_CONFIG;
+		}
+	case TXGBE_ATR_L4TYPE_MASK:
+		break;
+	default:
+		DEBUGOUT(" Error on flow type mask\n");
+		return TXGBE_ERR_CONFIG;
+	}
+
+#if 0
+	/* need fix */
+	switch (input_mask->formatted.tunnel_type & 0xFFFFFFFF) {
+	case 0x0:
+		/* Mask turnnel type, fall through */
+		fdirm |= TXGBE_RDB_FDIR_OTHER_MSK_TUN |
+			TXGBE_RDB_FDIR_OTHER_MSK_TUN_OUTIP |
+			TXGBE_RDB_FDIR_OTHER_MSK_TUN_TYPE;
+	case 0xFFFFFFFF:
+		break;
+	default:
+		DEBUGOUT(" Error on tunnel type byte mask\n");
+		return TXGBE_ERR_CONFIG;
+	}
+#endif
+
+	/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
+	wr32(hw, TXGBE_RDB_FDIR_OTHER_MSK, fdirm);
+
+	i = VMDQ_P(0) / 4;
+	j = VMDQ_P(0) % 4;
+	flex = rd32m(hw, TXGBE_RDB_FDIR_FLEX_CFG(i),
+		~((TXGBE_RDB_FDIR_FLEX_CFG_BASE_MSK |
+		   TXGBE_RDB_FDIR_FLEX_CFG_MSK |
+		   TXGBE_RDB_FDIR_FLEX_CFG_OFST) <<
+		   (TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT * j)));
+	flex |= (TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC |
+		0x6 << TXGBE_RDB_FDIR_FLEX_CFG_OFST_SHIFT) <<
+		(TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT * j);
+
+	switch (input_mask->formatted.flex_bytes & 0xFFFF) {
+	case 0x0000:
+		/* Mask Flex Bytes, fall through */
+		flex |= TXGBE_RDB_FDIR_FLEX_CFG_MSK <<
+			(TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT * j);
+	case 0xFFFF:
+		break;
+	default:
+		DEBUGOUT(" Error on flexible byte mask\n");
+		return TXGBE_ERR_CONFIG;
+	}
+	wr32(hw, TXGBE_RDB_FDIR_FLEX_CFG(i), flex);
+
+	/* store the TCP/UDP port masks, bit reversed from port
+	 * layout */
+	fdirtcpm = txgbe_get_fdirtcpm(input_mask);
+
+	/* write both the same so that UDP and TCP use the same mask */
+	wr32(hw, TXGBE_RDB_FDIR_TCP_MSK, ~fdirtcpm);
+	wr32(hw, TXGBE_RDB_FDIR_UDP_MSK, ~fdirtcpm);
+	wr32(hw, TXGBE_RDB_FDIR_SCTP_MSK, ~fdirtcpm);
+
+	/* store source and destination IP masks (little-enian) */
+	wr32(hw, TXGBE_RDB_FDIR_SA4_MSK,
+			     TXGBE_NTOHL(~input_mask->formatted.src_ip[0]));
+	wr32(hw, TXGBE_RDB_FDIR_DA4_MSK,
+			     TXGBE_NTOHL(~input_mask->formatted.dst_ip[0]));
+	return 0;
+}
+
+s32 txgbe_fdir_write_perfect_filter(struct txgbe_hw *hw,
+					     union txgbe_atr_input *input,
+					     u16 soft_id, u8 queue,
+					     bool cloud_mode)
+{
+	u32 fdirport, fdirvlan, fdirhash, fdircmd;
+	s32 err;
+
+	if (!cloud_mode) {
+		/* currently IPv6 is not supported, must be programmed with 0 */
+		wr32(hw, TXGBE_RDB_FDIR_IP6(2),
+				     TXGBE_NTOHL(input->formatted.src_ip[0]));
+		wr32(hw, TXGBE_RDB_FDIR_IP6(1),
+				     TXGBE_NTOHL(input->formatted.src_ip[1]));
+		wr32(hw, TXGBE_RDB_FDIR_IP6(0),
+				     TXGBE_NTOHL(input->formatted.src_ip[2]));
+
+		/* record the source address (little-endian) */
+		wr32(hw, TXGBE_RDB_FDIR_SA,
+			TXGBE_NTOHL(input->formatted.src_ip[0]));
+
+		/* record the first 32 bits of the destination address
+		 * (little-endian) */
+		wr32(hw, TXGBE_RDB_FDIR_DA,
+			TXGBE_NTOHL(input->formatted.dst_ip[0]));
+
+		/* record source and destination port (little-endian)*/
+		fdirport = TXGBE_NTOHS(input->formatted.dst_port);
+		fdirport <<= TXGBE_RDB_FDIR_PORT_DESTINATION_SHIFT;
+		fdirport |= TXGBE_NTOHS(input->formatted.src_port);
+		wr32(hw, TXGBE_RDB_FDIR_PORT, fdirport);
+	}
+
+	/* record packet type and flex_bytes(little-endian) */
+	fdirvlan = TXGBE_NTOHS(input->formatted.flex_bytes);
+	fdirvlan <<= TXGBE_RDB_FDIR_FLEX_FLEX_SHIFT;
+
+	fdirvlan |= TXGBE_NTOHS(input->formatted.vlan_id);
+	wr32(hw, TXGBE_RDB_FDIR_FLEX, fdirvlan);
+
+
+	/* configure FDIRHASH register */
+	fdirhash = input->formatted.bkt_hash |
+		0x1 << TXGBE_RDB_FDIR_HASH_BUCKET_VALID_SHIFT;
+	fdirhash |= soft_id << TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX_SHIFT;
+	wr32(hw, TXGBE_RDB_FDIR_HASH, fdirhash);
+
+	/*
+	 * flush all previous writes to make certain registers are
+	 * programmed prior to issuing the command
+	 */
+	TXGBE_WRITE_FLUSH(hw);
+
+	/* configure FDIRCMD register */
+	fdircmd = TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW |
+		  TXGBE_RDB_FDIR_CMD_FILTER_UPDATE |
+		  TXGBE_RDB_FDIR_CMD_LAST | TXGBE_RDB_FDIR_CMD_QUEUE_EN;
+	if (queue == TXGBE_RDB_FDIR_DROP_QUEUE)
+		fdircmd |= TXGBE_RDB_FDIR_CMD_DROP;
+	fdircmd |= input->formatted.flow_type <<
+			TXGBE_RDB_FDIR_CMD_FLOW_TYPE_SHIFT;
+	fdircmd |= (u32)queue << TXGBE_RDB_FDIR_CMD_RX_QUEUE_SHIFT;
+	fdircmd |= (u32)input->formatted.vm_pool <<
+			TXGBE_RDB_FDIR_CMD_VT_POOL_SHIFT;
+
+	wr32(hw, TXGBE_RDB_FDIR_CMD, fdircmd);
+	err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
+	if (err) {
+		DEBUGOUT("Flow Director command did not complete!\n");
+		return err;
+	}
+
+	return 0;
+}
+
+s32 txgbe_fdir_erase_perfect_filter(struct txgbe_hw *hw,
+					  union txgbe_atr_input *input,
+					  u16 soft_id)
+{
+	u32 fdirhash;
+	u32 fdircmd;
+	s32 err;
+
+	/* configure FDIRHASH register */
+	fdirhash = input->formatted.bkt_hash;
+	fdirhash |= soft_id << TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX_SHIFT;
+	wr32(hw, TXGBE_RDB_FDIR_HASH, fdirhash);
+
+	/* flush hash to HW */
+	TXGBE_WRITE_FLUSH(hw);
+
+	/* Query if filter is present */
+	wr32(hw, TXGBE_RDB_FDIR_CMD,
+			TXGBE_RDB_FDIR_CMD_CMD_QUERY_REM_FILT);
+
+	err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
+	if (err) {
+		DEBUGOUT("Flow Director command did not complete!\n");
+		return err;
+	}
+
+	/* if filter exists in hardware then remove it */
+	if (fdircmd & TXGBE_RDB_FDIR_CMD_FILTER_VALID) {
+		wr32(hw, TXGBE_RDB_FDIR_HASH, fdirhash);
+		TXGBE_WRITE_FLUSH(hw);
+		wr32(hw, TXGBE_RDB_FDIR_CMD,
+				TXGBE_RDB_FDIR_CMD_CMD_REMOVE_FLOW);
+	}
+
+	return 0;
+}
+
+
+/**
+ *  txgbe_start_hw - Prepare hardware for Tx/Rx
+ *  @hw: pointer to hardware structure
+ *
+ *  Starts the hardware using the generic start_hw function
+ *  and the generation start_hw function.
+ *  Then performs revision-specific operations, if any.
+ **/
+s32 txgbe_start_hw(struct txgbe_hw *hw)
+{
+	int ret_val = 0;
+	u32 i;
+
+	/* Set the media type */
+	hw->phy.media_type = TCALL(hw, mac.ops.get_media_type);
+
+	/* PHY ops initialization must be done in reset_hw() */
+
+	/* Clear the VLAN filter table */
+	TCALL(hw, mac.ops.clear_vfta);
+
+	/* Clear statistics registers */
+	TCALL(hw, mac.ops.clear_hw_cntrs);
+
+	TXGBE_WRITE_FLUSH(hw);
+	/* Setup flow control */
+	ret_val = TCALL(hw, mac.ops.setup_fc);
+
+	/* Clear the rate limiters */
+	for (i = 0; i < hw->mac.max_tx_queues; i++) {
+		wr32(hw, TXGBE_TDM_RP_IDX, i);
+		wr32(hw, TXGBE_TDM_RP_RATE, 0);
+	}
+	TXGBE_WRITE_FLUSH(hw);
+
+	/* Clear adapter stopped flag */
+	hw->adapter_stopped = false;
+
+	/* We need to run link autotry after the driver loads */
+	hw->mac.autotry_restart = true;
+
+	return ret_val;
+}
+
+/**
+ *  txgbe_identify_phy - Get physical layer module
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines the physical layer module found on the current adapter.
+ *  If PHY already detected, maintains current PHY type in hw struct,
+ *  otherwise executes the PHY detection routine.
+ **/
+s32 txgbe_identify_phy(struct txgbe_hw *hw)
+{
+	/* Detect PHY if not unknown - returns success if already detected. */
+	s32 status = TXGBE_ERR_PHY_ADDR_INVALID;
+	enum txgbe_media_type media_type;
+
+	if (!hw->phy.phy_semaphore_mask) {
+		hw->phy.phy_semaphore_mask = TXGBE_MNG_SWFW_SYNC_SW_PHY;
+	}
+
+	media_type = TCALL(hw, mac.ops.get_media_type);
+	if (media_type == txgbe_media_type_copper) {
+		status = txgbe_init_external_phy(hw);
+		if (status != 0) {
+			return status;
+		}
+		txgbe_get_phy_id(hw);
+		hw->phy.type = txgbe_get_phy_type_from_id(hw);
+		status = 0;
+	} else if (media_type == txgbe_media_type_fiber) {
+		status = txgbe_identify_module(hw);
+	} else {
+		hw->phy.type = txgbe_phy_none;
+		status = 0;
+	}
+
+	/* Return error if SFP module has been detected but is not supported */
+	if (hw->phy.type == txgbe_phy_sfp_unsupported)
+		return TXGBE_ERR_SFP_NOT_SUPPORTED;
+
+	return status;
+}
+
+
+/**
+ *  txgbe_enable_rx_dma - Enable the Rx DMA unit on sapphire
+ *  @hw: pointer to hardware structure
+ *  @regval: register value to write to RXCTRL
+ *
+ *  Enables the Rx DMA unit for sapphire
+ **/
+s32 txgbe_enable_rx_dma(struct txgbe_hw *hw, u32 regval)
+{
+	/*
+	 * Workaround for sapphire silicon errata when enabling the Rx datapath.
+	 * If traffic is incoming before we enable the Rx unit, it could hang
+	 * the Rx DMA unit.  Therefore, make sure the security engine is
+	 * completely disabled prior to enabling the Rx unit.
+	 */
+
+	TCALL(hw, mac.ops.disable_sec_rx_path);
+
+	if (regval & TXGBE_RDB_PB_CTL_RXEN)
+		TCALL(hw, mac.ops.enable_rx);
+	else
+		TCALL(hw, mac.ops.disable_rx);
+
+	TCALL(hw, mac.ops.enable_sec_rx_path);
+
+	return 0;
+}
+
+/**
+ *  txgbe_init_flash_params - Initialize flash params
+ *  @hw: pointer to hardware structure
+ *
+ *  Initializes the EEPROM parameters txgbe_eeprom_info within the
+ *  txgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 txgbe_init_flash_params(struct txgbe_hw *hw)
+{
+	struct txgbe_flash_info *flash = &hw->flash;
+	u32 eec;
+
+	eec = 0x1000000;
+	flash->semaphore_delay = 10;
+	flash->dword_size = (eec >> 2);
+	flash->address_bits = 24;
+	DEBUGOUT3("FLASH params: size = %d, address bits: %d\n",
+		  flash->dword_size,
+		  flash->address_bits);
+
+	return 0;
+}
+
+/**
+ *  txgbe_read_flash_buffer - Read FLASH dword(s) using
+ *  fastest available method
+ *
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  dword in EEPROM to read
+ *  @dwords: number of dwords
+ *  @data: dword(s) read from the EEPROM
+ *
+ *  Retrieves 32 bit dword(s) read from EEPROM
+ **/
+s32 txgbe_read_flash_buffer(struct txgbe_hw *hw, u32 offset,
+					  u32 dwords, u32 *data)
+{
+	s32 status = 0;
+	u32 i;
+
+	TCALL(hw, eeprom.ops.init_params);
+
+	if (!dwords || offset + dwords >= hw->flash.dword_size) {
+		status = TXGBE_ERR_INVALID_ARGUMENT;
+		ERROR_REPORT1(TXGBE_ERROR_ARGUMENT, "Invalid FLASH arguments");
+		return status;
+	}
+
+	for (i = 0; i < dwords; i++) {
+		wr32(hw, TXGBE_SPI_DATA, data[i]);
+		wr32(hw, TXGBE_SPI_CMD,
+			TXGBE_SPI_CMD_ADDR(offset + i) |
+			TXGBE_SPI_CMD_CMD(0x0));
+
+		status = po32m(hw, TXGBE_SPI_STATUS,
+			TXGBE_SPI_STATUS_OPDONE, TXGBE_SPI_STATUS_OPDONE,
+			TXGBE_SPI_TIMEOUT, 0);
+		if (status) {
+			DEBUGOUT("FLASH read timed out\n");
+			break;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_write_flash_buffer - Write FLASH dword(s) using
+ *  fastest available method
+ *
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  dword in EEPROM to write
+ *  @dwords: number of dwords
+ *  @data: dword(s) write from to EEPROM
+ *
+ **/
+s32 txgbe_write_flash_buffer(struct txgbe_hw *hw, u32 offset,
+					  u32 dwords, u32 *data)
+{
+	s32 status = 0;
+	u32 i;
+
+	TCALL(hw, eeprom.ops.init_params);
+
+	if (!dwords || offset + dwords >= hw->flash.dword_size) {
+		status = TXGBE_ERR_INVALID_ARGUMENT;
+		ERROR_REPORT1(TXGBE_ERROR_ARGUMENT, "Invalid FLASH arguments");
+		return status;
+	}
+
+	for (i = 0; i < dwords; i++) {
+		wr32(hw, TXGBE_SPI_CMD,
+			TXGBE_SPI_CMD_ADDR(offset + i) |
+			TXGBE_SPI_CMD_CMD(0x1));
+
+		status = po32m(hw, TXGBE_SPI_STATUS,
+			TXGBE_SPI_STATUS_OPDONE, TXGBE_SPI_STATUS_OPDONE,
+			TXGBE_SPI_TIMEOUT, 0);
+		if (status != 0) {
+			DEBUGOUT("FLASH write timed out\n");
+			break;
+		}
+		data[i] = rd32(hw, TXGBE_SPI_DATA);
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_init_eeprom_params - Initialize EEPROM params
+ *  @hw: pointer to hardware structure
+ *
+ *  Initializes the EEPROM parameters txgbe_eeprom_info within the
+ *  txgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 txgbe_init_eeprom_params(struct txgbe_hw *hw)
+{
+	struct txgbe_eeprom_info *eeprom = &hw->eeprom;
+	u16 eeprom_size;
+	s32 status = 0;
+	u16 data;
+
+	if (eeprom->type == txgbe_eeprom_uninitialized) {
+		eeprom->semaphore_delay = 10;
+		eeprom->type = txgbe_eeprom_none;
+
+		if (!(rd32(hw, TXGBE_SPI_STATUS) &
+			TXGBE_SPI_STATUS_FLASH_BYPASS)) {
+			eeprom->type = txgbe_flash;
+
+			eeprom_size = 4096;
+			eeprom->word_size = eeprom_size >> 1;
+
+			DEBUGOUT2("Eeprom params: type = %d, size = %d\n",
+				  eeprom->type, eeprom->word_size);
+		}
+	}
+
+	status = TCALL(hw, eeprom.ops.read, TXGBE_SW_REGION_PTR,
+			&data);
+	if (status) {
+		DEBUGOUT("NVM Read Error\n");
+		return status;
+	}
+	eeprom->sw_region_offset = data >> 1;
+
+	return status;
+}
+
+/**
+ *  txgbe_read_ee_hostif - Read EEPROM word using a host interface cmd
+ *  assuming that the semaphore is already obtained.
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the hostif.
+ **/
+s32 txgbe_read_ee_hostif_data(struct txgbe_hw *hw, u16 offset,
+				   u16 *data)
+{
+	s32 status;
+	struct txgbe_hic_read_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+	/* convert offset from words to bytes */
+	buffer.address = TXGBE_CPU_TO_BE32(offset * 2);
+	/* one word */
+	buffer.length = TXGBE_CPU_TO_BE16(sizeof(u16));
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+					      sizeof(buffer),
+					      TXGBE_HI_COMMAND_TIMEOUT, false);
+
+	if (status)
+		return status;
+	if (txgbe_check_mng_access(hw))
+		*data = (u16)rd32a(hw, TXGBE_MNG_MBOX,
+							FW_NVM_DATA_OFFSET);
+	else {
+		status = TXGBE_ERR_MNG_ACCESS_FAILED;
+		return status;
+	}
+
+
+	return 0;
+}
+
+/**
+ *  txgbe_read_ee_hostif - Read EEPROM word using a host interface cmd
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the hostif.
+ **/
+s32 txgbe_read_ee_hostif(struct txgbe_hw *hw, u16 offset,
+			      u16 *data)
+{
+	s32 status = 0;
+
+	if (TCALL(hw, mac.ops.acquire_swfw_sync,
+		TXGBE_MNG_SWFW_SYNC_SW_FLASH) == 0) {
+		status = txgbe_read_ee_hostif_data(hw, offset, data);
+		TCALL(hw, mac.ops.release_swfw_sync,
+			TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+	} else {
+		status = TXGBE_ERR_SWFW_SYNC;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_read_ee_hostif_buffer- Read EEPROM word(s) using hostif
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @words: number of words
+ *  @data: word(s) read from the EEPROM
+ *
+ *  Reads a 16 bit word(s) from the EEPROM using the hostif.
+ **/
+s32 txgbe_read_ee_hostif_buffer(struct txgbe_hw *hw,
+				     u16 offset, u16 words, u16 *data)
+{
+	struct txgbe_hic_read_shadow_ram buffer;
+	u32 current_word = 0;
+	u16 words_to_read;
+	s32 status;
+	u32 i;
+	u32 value = 0;
+
+	/* Take semaphore for the entire operation. */
+	status = TCALL(hw, mac.ops.acquire_swfw_sync,
+			TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+	if (status) {
+		DEBUGOUT("EEPROM read buffer - semaphore failed\n");
+		return status;
+	}
+	while (words) {
+		if (words > FW_MAX_READ_BUFFER_SIZE / 2)
+			words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
+		else
+			words_to_read = words;
+
+		buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+		buffer.hdr.req.buf_lenh = 0;
+		buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+		buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+		/* convert offset from words to bytes */
+		buffer.address = TXGBE_CPU_TO_BE32((offset + current_word) * 2);
+		buffer.length = TXGBE_CPU_TO_BE16(words_to_read * 2);
+
+		status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+						      sizeof(buffer),
+						      TXGBE_HI_COMMAND_TIMEOUT,
+						      false);
+
+		if (status) {
+			DEBUGOUT("Host interface command failed\n");
+			goto out;
+		}
+
+		for (i = 0; i < words_to_read; i++) {
+			u32 reg = TXGBE_MNG_MBOX + (FW_NVM_DATA_OFFSET << 2) +
+				  2 * i;
+			if (txgbe_check_mng_access(hw))
+				value = rd32(hw, reg);
+			else {
+				status = TXGBE_ERR_MNG_ACCESS_FAILED;
+				return status;
+			}
+			data[current_word] = (u16)(value & 0xffff);
+			current_word++;
+			i++;
+			if (i < words_to_read) {
+				value >>= 16;
+				data[current_word] = (u16)(value & 0xffff);
+				current_word++;
+			}
+		}
+		words -= words_to_read;
+	}
+
+out:
+	TCALL(hw, mac.ops.release_swfw_sync,
+		TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+	return status;
+}
+
+/**
+ *  txgbe_write_ee_hostif - Write EEPROM word using hostif
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @data: word write to the EEPROM
+ *
+ *  Write a 16 bit word to the EEPROM using the hostif.
+ **/
+s32 txgbe_write_ee_hostif_data(struct txgbe_hw *hw, u16 offset,
+				    u16 data)
+{
+	s32 status;
+	struct txgbe_hic_write_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
+	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+	/* one word */
+	buffer.length = TXGBE_CPU_TO_BE16(sizeof(u16));
+	buffer.data = data;
+	buffer.address = TXGBE_CPU_TO_BE32(offset * 2);
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+					      sizeof(buffer),
+					      TXGBE_HI_COMMAND_TIMEOUT, false);
+
+	return status;
+}
+
+s32 txgbe_close_notify(struct txgbe_hw *hw)
+{
+	int tmp;
+	s32 status;
+	struct txgbe_hic_write_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = FW_DW_CLOSE_NOTIFY;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = 0;
+	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+	/* one word */
+	buffer.length = 0;
+	buffer.address = 0;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+					      sizeof(buffer),
+					      500, false);
+	if (status)
+		return status;
+
+	if (txgbe_check_mng_access(hw)){
+		tmp = (u32)rd32a(hw, TXGBE_MNG_MBOX, 1);
+		if (tmp == TXGBE_CHECKSUM_CAP_ST_PASS)
+			status = 0;
+		else
+			status = TXGBE_ERR_EEPROM_CHECKSUM;
+	} else {
+			status = TXGBE_ERR_MNG_ACCESS_FAILED;
+			return status;
+	}
+
+	return status;
+}
+
+s32 txgbe_open_notify(struct txgbe_hw *hw)
+{
+	int tmp;
+	s32 status;
+	struct txgbe_hic_write_shadow_ram buffer;
+
+	buffer.hdr.req.cmd = FW_DW_OPEN_NOTIFY;
+	buffer.hdr.req.buf_lenh = 0;
+	buffer.hdr.req.buf_lenl = 0;
+	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
+
+	/* one word */
+	buffer.length = 0;
+	buffer.address = 0;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+					      sizeof(buffer),
+					      500, false);
+		if (status)
+		return status;
+
+	if (txgbe_check_mng_access(hw)){
+		tmp = (u32)rd32a(hw, TXGBE_MNG_MBOX, 1);
+		if (tmp == TXGBE_CHECKSUM_CAP_ST_PASS)
+			status = 0;
+		else
+			status = TXGBE_ERR_EEPROM_CHECKSUM;
+		
+	} else {
+			status = TXGBE_ERR_MNG_ACCESS_FAILED;
+			return status;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_write_ee_hostif - Write EEPROM word using hostif
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @data: word write to the EEPROM
+ *
+ *  Write a 16 bit word to the EEPROM using the hostif.
+ **/
+s32 txgbe_write_ee_hostif(struct txgbe_hw *hw, u16 offset,
+			       u16 data)
+{
+	s32 status = 0;
+
+	if (TCALL(hw, mac.ops.acquire_swfw_sync,
+		TXGBE_MNG_SWFW_SYNC_SW_FLASH) == 0) {
+		status = txgbe_write_ee_hostif_data(hw, offset, data);
+		TCALL(hw, mac.ops.release_swfw_sync,
+			TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+	} else {
+		DEBUGOUT("write ee hostif failed to get semaphore");
+		status = TXGBE_ERR_SWFW_SYNC;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_write_ee_hostif_buffer - Write EEPROM word(s) using hostif
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @words: number of words
+ *  @data: word(s) write to the EEPROM
+ *
+ *  Write a 16 bit word(s) to the EEPROM using the hostif.
+ **/
+s32 txgbe_write_ee_hostif_buffer(struct txgbe_hw *hw,
+				      u16 offset, u16 words, u16 *data)
+{
+	s32 status = 0;
+	u16 i = 0;
+
+	/* Take semaphore for the entire operation. */
+	status = TCALL(hw, mac.ops.acquire_swfw_sync,
+		       TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+	if (status != 0) {
+		DEBUGOUT("EEPROM write buffer - semaphore failed\n");
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		status = txgbe_write_ee_hostif_data(hw, offset + i,
+							 data[i]);
+
+		if (status != 0) {
+			DEBUGOUT("Eeprom buffered write failed\n");
+			break;
+		}
+	}
+
+	TCALL(hw, mac.ops.release_swfw_sync, TXGBE_MNG_SWFW_SYNC_SW_FLASH);
+out:
+
+	return status;
+}
+
+
+
+/**
+ *  txgbe_calc_eeprom_checksum - Calculates and returns the checksum
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns a negative error code on error, or the 16-bit checksum
+ **/
+s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw)
+{
+	u16 *buffer = NULL;
+	u32 buffer_size = 0;
+
+	u16 *eeprom_ptrs = NULL;
+	u16 *local_buffer;
+	s32 status;
+	u16 checksum = 0;
+	u16 i;
+
+	TCALL(hw, eeprom.ops.init_params);
+
+	if (!buffer) {
+		eeprom_ptrs = (u16 *)vmalloc(TXGBE_EEPROM_LAST_WORD *
+				sizeof(u16));
+		if (!eeprom_ptrs)
+			return TXGBE_ERR_NO_SPACE;
+		/* Read pointer area */
+		status = txgbe_read_ee_hostif_buffer(hw, 0,
+						     TXGBE_EEPROM_LAST_WORD,
+						     eeprom_ptrs);
+		if (status) {
+			DEBUGOUT("Failed to read EEPROM image\n");
+			return status;
+		}
+		local_buffer = eeprom_ptrs;
+	} else {
+		if (buffer_size < TXGBE_EEPROM_LAST_WORD)
+			return TXGBE_ERR_PARAM;
+		local_buffer = buffer;
+	}
+
+	for (i = 0; i < TXGBE_EEPROM_LAST_WORD; i++)
+		if (i != hw->eeprom.sw_region_offset + TXGBE_EEPROM_CHECKSUM)
+			checksum += local_buffer[i];
+
+	checksum = (u16)TXGBE_EEPROM_SUM - checksum;
+	if (eeprom_ptrs)
+		vfree(eeprom_ptrs);
+
+	return (s32)checksum;
+}
+
+/**
+ * txgbe_update_eeprom_checksum - Updates the EEPROM checksum and flash
+ * @hw: pointer to hardware structure
+ *
+ * After writing EEPROM to shadow RAM using EEWR register, software calculates
+ * checksum and updates the EEPROM and instructs the hardware to update
+ * the flash.
+ **/
+s32 txgbe_update_eeprom_checksum(struct txgbe_hw *hw)
+{
+	s32 status;
+	u16 checksum = 0;
+
+	/* Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = txgbe_read_ee_hostif(hw, 0, &checksum);
+	if (status) {
+		DEBUGOUT("EEPROM read failed\n");
+		return status;
+	}
+
+	status = txgbe_calc_eeprom_checksum(hw);
+	if (status < 0)
+		return status;
+
+	checksum = (u16)(status & 0xffff);
+
+	status = txgbe_write_ee_hostif(hw, TXGBE_EEPROM_CHECKSUM,
+					    checksum);
+	if (status)
+		return status;
+
+	return status;
+}
+
+/**
+ *  txgbe_validate_eeprom_checksum - Validate EEPROM checksum
+ *  @hw: pointer to hardware structure
+ *  @checksum_val: calculated checksum
+ *
+ *  Performs checksum calculation and validates the EEPROM checksum.  If the
+ *  caller does not need checksum_val, the value can be NULL.
+ **/
+s32 txgbe_validate_eeprom_checksum(struct txgbe_hw *hw,
+					    u16 *checksum_val)
+{
+	s32 status;
+	u16 checksum;
+	u16 read_checksum = 0;
+
+	/* Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = TCALL(hw, eeprom.ops.read, 0, &checksum);
+	if (status) {
+		DEBUGOUT("EEPROM read failed\n");
+		return status;
+	}
+
+	status = TCALL(hw, eeprom.ops.calc_checksum);
+	if (status < 0)
+		return status;
+
+	checksum = (u16)(status & 0xffff);
+
+	status = txgbe_read_ee_hostif(hw, hw->eeprom.sw_region_offset +
+					TXGBE_EEPROM_CHECKSUM,
+					&read_checksum);
+	if (status)
+		return status;
+
+	/* Verify read checksum from EEPROM is the same as
+	 * calculated checksum
+	 */
+	if (read_checksum != checksum) {
+		status = TXGBE_ERR_EEPROM_CHECKSUM;
+		ERROR_REPORT1(TXGBE_ERROR_INVALID_STATE,
+			     "Invalid EEPROM checksum\n");
+	}
+
+	/* If the user cares, return the calculated checksum */
+	if (checksum_val)
+		*checksum_val = checksum;
+
+	return status;
+}
+
+/**
+ *  txgbe_update_flash - Instruct HW to copy EEPROM to Flash device
+ *  @hw: pointer to hardware structure
+ *
+ *  Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
+ **/
+s32 txgbe_update_flash(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+	union txgbe_hic_hdr2 buffer;
+
+	buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
+	buffer.req.buf_lenh = 0;
+	buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
+	buffer.req.checksum = FW_DEFAULT_CHECKSUM;
+
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+					      sizeof(buffer),
+					      TXGBE_HI_COMMAND_TIMEOUT, false);
+
+	return status;
+}
+
+
+/**
+ *  txgbe_check_mac_link - Determine link and speed status
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true when link is up
+ *  @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ *  Reads the links register to determine if link is up and the current speed
+ **/
+s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed,
+				bool *link_up, bool link_up_wait_to_complete)
+{
+	u32 links_reg = 0;
+	u32 i;
+	u16 value;
+
+	if (link_up_wait_to_complete) {
+		for (i = 0; i < TXGBE_LINK_UP_TIME; i++) {
+			if (TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_copper &&
+				 ((hw->subsystem_device_id & 0xF0) != TXGBE_ID_SFI_XAUI)) {
+				/* read ext phy link status */
+				txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 0x03, 0x8008, &value);
+				if (value & 0x400) {
+					*link_up = true;
+				} else {
+					*link_up = false;
+				}
+			} else {
+				*link_up = true;
+			}
+			if (*link_up) {
+				links_reg = rd32(hw,
+							TXGBE_CFG_PORT_ST);
+				if (links_reg & TXGBE_CFG_PORT_ST_LINK_UP) {
+					*link_up = true;
+					break;
+				} else {
+					*link_up = false;
+				}
+			}
+			msleep(100);
+		}
+	} else {
+		if (TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_copper  &&
+			 ((hw->subsystem_device_id & 0xF0) != TXGBE_ID_SFI_XAUI)) {
+			/* read ext phy link status */
+			txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 0x03, 0x8008, &value);
+			if (value & 0x400) {
+				*link_up = true;
+			} else {
+				*link_up = false;
+			}
+		} else {
+			*link_up = true;
+		}
+		if (*link_up) {
+			links_reg = rd32(hw, TXGBE_CFG_PORT_ST);
+			if (links_reg & TXGBE_CFG_PORT_ST_LINK_UP) {
+				*link_up = true;
+			} else {
+				*link_up = false;
+			}
+		}
+	}
+
+	if ((hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0) ||
+		(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1)) {
+		*link_up = hw->f2c_mod_status;
+
+		if (*link_up) {	
+			/* recover led configure when link up */
+			wr32(hw, TXGBE_CFG_LED_CTL, 0);
+		}
+		else {			
+			/* over write led when link down */
+			TCALL(hw, mac.ops.led_off, TXGBE_LED_LINK_UP | TXGBE_LED_LINK_10G | 
+									   TXGBE_LED_LINK_1G | TXGBE_LED_LINK_ACTIVE);
+		}			
+	}
+
+	if (*link_up) {
+		if (TCALL(hw, mac.ops.get_media_type) == txgbe_media_type_copper  &&
+				 ((hw->subsystem_device_id & 0xF0) != TXGBE_ID_SFI_XAUI)) {
+			if ((value & 0xc000) == 0xc000) {
+				*speed = TXGBE_LINK_SPEED_10GB_FULL;
+			} else if ((value & 0xc000) == 0x8000) {
+				*speed = TXGBE_LINK_SPEED_1GB_FULL;
+			} else if ((value & 0xc000) == 0x4000) {
+				*speed = TXGBE_LINK_SPEED_100_FULL;
+			} else if ((value & 0xc000) == 0x0000) {
+				*speed = TXGBE_LINK_SPEED_10_FULL;
+			}
+		} else {
+			if ((links_reg & TXGBE_CFG_PORT_ST_LINK_10G) ==
+					TXGBE_CFG_PORT_ST_LINK_10G) {
+				*speed = TXGBE_LINK_SPEED_10GB_FULL;
+			} else if ((links_reg & TXGBE_CFG_PORT_ST_LINK_1G) ==
+					TXGBE_CFG_PORT_ST_LINK_1G){
+				*speed = TXGBE_LINK_SPEED_1GB_FULL;
+			} else if ((links_reg & TXGBE_CFG_PORT_ST_LINK_100M) ==
+					TXGBE_CFG_PORT_ST_LINK_100M){
+				*speed = TXGBE_LINK_SPEED_100_FULL;
+			} else
+				*speed = TXGBE_LINK_SPEED_10_FULL;
+		}
+	} else
+		*speed = TXGBE_LINK_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+/**
+ *  txgbe_setup_eee - Enable/disable EEE support
+ *  @hw: pointer to the HW structure
+ *  @enable_eee: boolean flag to enable EEE
+ *
+ *  Enable/disable EEE based on enable_eee flag.
+ *  Auto-negotiation must be started after BASE-T EEE bits in PHY register 7.3C
+ *  are modified.
+ *
+ **/
+s32 txgbe_setup_eee(struct txgbe_hw *hw, bool enable_eee)
+{
+	/* fix eee */
+
+	return 0;
+}
+
+s32 txgbe_hic_write_lldp(struct txgbe_hw *hw,u32 open)
+{
+	int status;
+	struct txgbe_adapter *adapter = hw->back;
+	struct pci_dev *pdev = adapter->pdev;
+	struct txgbe_hic_write_lldp buffer;
+
+	buffer.hdr.cmd = 0xf1 - open;
+	buffer.hdr.buf_len = 0x1;
+	buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
+	buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
+	buffer.func = PCI_FUNC(pdev->devfn);
+	status = txgbe_host_interface_command(hw, (u32 *)&buffer,
+										sizeof(buffer), 5000, false);
+	return status;
+	
+}
+
+bool txgbe_is_lldp(struct txgbe_hw *hw)
+{
+	struct txgbe_adapter *adapter = hw->back;
+	struct pci_dev *pdev = adapter->pdev;
+	u32 tmp = 0;
+	u32 lldp_flash_data = 0 ;
+	u32 i = 0;
+
+	for (; i < 0x1000 / sizeof(u32); i++) {
+        tmp = txgbe_flash_read_dword(hw, TXGBE_LLDP_REG + i * 4);
+        if (tmp != 0xffffffff) {
+            lldp_flash_data = tmp;
+        } else {
+            break;
+        }
+    }
+	return (lldp_flash_data & BIT(PCI_FUNC(pdev->devfn)));
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
new file mode 100644
index 000000000000..000ae874cf29
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
@@ -0,0 +1,313 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#ifndef _TXGBE_HW_H_
+#define _TXGBE_HW_H_
+
+#define TXGBE_EMC_INTERNAL_DATA         0x00
+#define TXGBE_EMC_INTERNAL_THERM_LIMIT  0x20
+#define TXGBE_EMC_DIODE1_DATA           0x01
+#define TXGBE_EMC_DIODE1_THERM_LIMIT    0x19
+#define TXGBE_EMC_DIODE2_DATA           0x23
+#define TXGBE_EMC_DIODE2_THERM_LIMIT    0x1A
+#define TXGBE_EMC_DIODE3_DATA           0x2A
+#define TXGBE_EMC_DIODE3_THERM_LIMIT    0x30
+
+#define SPI_CLK_DIV                        2
+
+#define SPI_CMD_ERASE_CHIP                 4  // SPI erase chip command
+#define SPI_CMD_ERASE_SECTOR               3  // SPI erase sector command
+#define SPI_CMD_WRITE_DWORD                0  // SPI write a dword command
+#define SPI_CMD_READ_DWORD                 1  // SPI read a dword command
+#define SPI_CMD_USER_CMD                   5  // SPI user command
+				
+#define SPI_CLK_CMD_OFFSET                28  // SPI command field offset in Command register
+#define SPI_CLK_DIV_OFFSET                25  // SPI clock divide field offset in Command register
+				
+#define SPI_TIME_OUT_VALUE             10000
+#define SPI_SECTOR_SIZE          (4 * 1024)  // FLASH sector size is 64KB
+#define SPI_H_CMD_REG_ADDR           0x10104  // SPI Command register address
+#define SPI_H_DAT_REG_ADDR           0x10108  // SPI Data register address
+#define SPI_H_STA_REG_ADDR           0x1010c  // SPI Status register address
+#define SPI_H_USR_CMD_REG_ADDR       0x10110  // SPI User Command register address
+#define SPI_CMD_CFG1_ADDR            0x10118  // Flash command configuration register 1
+#define MISC_RST_REG_ADDR            0x1000c  // Misc reset register address
+#define MGR_FLASH_RELOAD_REG_ADDR    0x101a0  // MGR reload flash read
+
+#define MAC_ADDR0_WORD0_OFFSET_1G    0x006000c  // MAC Address for LAN0, stored in external FLASH
+#define MAC_ADDR0_WORD1_OFFSET_1G    0x0060014
+#define MAC_ADDR1_WORD0_OFFSET_1G    0x007000c  // MAC Address for LAN1, stored in external FLASH
+#define MAC_ADDR1_WORD1_OFFSET_1G    0x0070014
+#define PRODUCT_SERIAL_NUM_OFFSET_1G    0x00f0000  // Product Serial Number, stored in external FLASH last sector
+
+struct txgbe_hic_read_cab {
+	union txgbe_hic_hdr2 hdr;
+	union {
+		u8 d8[252];
+		u16 d16[126];
+		u32 d32[63];
+	} dbuf;
+};
+
+
+/**
+ * Packet Type decoding
+ **/
+/* txgbe_dec_ptype.mac: outer mac */
+enum txgbe_dec_ptype_mac {
+	TXGBE_DEC_PTYPE_MAC_IP = 0,
+	TXGBE_DEC_PTYPE_MAC_L2 = 2,
+	TXGBE_DEC_PTYPE_MAC_FCOE = 3,
+};
+
+/* txgbe_dec_ptype.[e]ip: outer&encaped ip */
+#define TXGBE_DEC_PTYPE_IP_FRAG (0x4)
+enum txgbe_dec_ptype_ip {
+	TXGBE_DEC_PTYPE_IP_NONE = 0,
+	TXGBE_DEC_PTYPE_IP_IPV4 = 1,
+	TXGBE_DEC_PTYPE_IP_IPV6 = 2,
+	TXGBE_DEC_PTYPE_IP_FGV4 =
+		(TXGBE_DEC_PTYPE_IP_FRAG | TXGBE_DEC_PTYPE_IP_IPV4),
+	TXGBE_DEC_PTYPE_IP_FGV6 =
+		(TXGBE_DEC_PTYPE_IP_FRAG | TXGBE_DEC_PTYPE_IP_IPV6),
+};
+
+/* txgbe_dec_ptype.etype: encaped type */
+enum txgbe_dec_ptype_etype {
+	TXGBE_DEC_PTYPE_ETYPE_NONE = 0,
+	TXGBE_DEC_PTYPE_ETYPE_IPIP = 1, /* IP+IP */
+	TXGBE_DEC_PTYPE_ETYPE_IG = 2, /* IP+GRE */
+	TXGBE_DEC_PTYPE_ETYPE_IGM = 3, /* IP+GRE+MAC */
+	TXGBE_DEC_PTYPE_ETYPE_IGMV = 4, /* IP+GRE+MAC+VLAN */
+};
+
+/* txgbe_dec_ptype.proto: payload proto */
+enum txgbe_dec_ptype_prot {
+	TXGBE_DEC_PTYPE_PROT_NONE = 0,
+	TXGBE_DEC_PTYPE_PROT_UDP = 1,
+	TXGBE_DEC_PTYPE_PROT_TCP = 2,
+	TXGBE_DEC_PTYPE_PROT_SCTP = 3,
+	TXGBE_DEC_PTYPE_PROT_ICMP = 4,
+	TXGBE_DEC_PTYPE_PROT_TS = 5, /* time sync */
+};
+
+/* txgbe_dec_ptype.layer: payload layer */
+enum txgbe_dec_ptype_layer {
+	TXGBE_DEC_PTYPE_LAYER_NONE = 0,
+	TXGBE_DEC_PTYPE_LAYER_PAY2 = 1,
+	TXGBE_DEC_PTYPE_LAYER_PAY3 = 2,
+	TXGBE_DEC_PTYPE_LAYER_PAY4 = 3,
+};
+
+struct txgbe_dec_ptype {
+	u32 ptype:8;
+	u32 known:1;
+	u32 mac:2; /* outer mac */
+	u32 ip:3; /* outer ip*/
+	u32 etype:3; /* encaped type */
+	u32 eip:3; /* encaped ip */
+	u32 prot:4; /* payload proto */
+	u32 layer:3; /* payload layer */
+};
+typedef struct txgbe_dec_ptype txgbe_dptype;
+
+
+void txgbe_dcb_get_rtrup2tc(struct txgbe_hw *hw, u8 *map);
+u16 txgbe_get_pcie_msix_count(struct txgbe_hw *hw);
+s32 txgbe_init_hw(struct txgbe_hw *hw);
+s32 txgbe_start_hw(struct txgbe_hw *hw);
+s32 txgbe_clear_hw_cntrs(struct txgbe_hw *hw);
+s32 txgbe_read_pba_string(struct txgbe_hw *hw, u8 *pba_num,
+				  u32 pba_num_size);
+s32 txgbe_get_mac_addr(struct txgbe_hw *hw, u8 *mac_addr);
+s32 txgbe_get_bus_info(struct txgbe_hw *hw);
+void txgbe_set_pci_config_data(struct txgbe_hw *hw, u16 link_status);
+void txgbe_set_lan_id_multi_port_pcie(struct txgbe_hw *hw);
+s32 txgbe_stop_adapter(struct txgbe_hw *hw);
+
+s32 txgbe_led_on(struct txgbe_hw *hw, u32 index);
+s32 txgbe_led_off(struct txgbe_hw *hw, u32 index);
+
+s32 txgbe_set_rar(struct txgbe_hw *hw, u32 index, u8 *addr, u64 pools,
+			  u32 enable_addr);
+s32 txgbe_clear_rar(struct txgbe_hw *hw, u32 index);
+s32 txgbe_init_rx_addrs(struct txgbe_hw *hw);
+s32 txgbe_update_mc_addr_list(struct txgbe_hw *hw, u8 *mc_addr_list,
+				      u32 mc_addr_count,
+				      txgbe_mc_addr_itr func, bool clear);
+s32 txgbe_update_uc_addr_list(struct txgbe_hw *hw, u8 *addr_list,
+				      u32 addr_count, txgbe_mc_addr_itr func);
+s32 txgbe_enable_mc(struct txgbe_hw *hw);
+s32 txgbe_disable_mc(struct txgbe_hw *hw);
+s32 txgbe_disable_sec_rx_path(struct txgbe_hw *hw);
+s32 txgbe_enable_sec_rx_path(struct txgbe_hw *hw);
+
+s32 txgbe_fc_enable(struct txgbe_hw *hw);
+bool txgbe_device_supports_autoneg_fc(struct txgbe_hw *hw);
+void txgbe_fc_autoneg(struct txgbe_hw *hw);
+s32 txgbe_setup_fc(struct txgbe_hw *hw);
+
+s32 txgbe_validate_mac_addr(u8 *mac_addr);
+s32 txgbe_acquire_swfw_sync(struct txgbe_hw *hw, u32 mask);
+void txgbe_release_swfw_sync(struct txgbe_hw *hw, u32 mask);
+s32 txgbe_disable_pcie_master(struct txgbe_hw *hw);
+
+
+s32 txgbe_get_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr);
+s32 txgbe_set_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr);
+
+s32 txgbe_set_vmdq(struct txgbe_hw *hw, u32 rar, u32 vmdq);
+s32 txgbe_set_vmdq_san_mac(struct txgbe_hw *hw, u32 vmdq);
+s32 txgbe_clear_vmdq(struct txgbe_hw *hw, u32 rar, u32 vmdq);
+s32 txgbe_insert_mac_addr(struct txgbe_hw *hw, u8 *addr, u32 vmdq);
+s32 txgbe_init_uta_tables(struct txgbe_hw *hw);
+s32 txgbe_set_vfta(struct txgbe_hw *hw, u32 vlan,
+			 u32 vind, bool vlan_on);
+s32 txgbe_set_vlvf(struct txgbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on, bool *vfta_changed);
+s32 txgbe_clear_vfta(struct txgbe_hw *hw);
+s32 txgbe_find_vlvf_slot(struct txgbe_hw *hw, u32 vlan);
+
+s32 txgbe_get_wwn_prefix(struct txgbe_hw *hw, u16 *wwnn_prefix,
+				 u16 *wwpn_prefix);
+
+void txgbe_set_mac_anti_spoofing(struct txgbe_hw *hw, bool enable, int pf);
+void txgbe_set_vlan_anti_spoofing(struct txgbe_hw *hw, bool enable, int vf);
+void txgbe_set_ethertype_anti_spoofing(struct txgbe_hw *hw,
+					bool enable, int vf);
+s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps);
+void txgbe_set_rxpba(struct txgbe_hw *hw, int num_pb, u32 headroom,
+			     int strategy);
+s32 txgbe_set_fw_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min,
+				 u8 build, u8 ver);
+s32 txgbe_reset_hostif(struct txgbe_hw *hw);
+u8 txgbe_calculate_checksum(u8 *buffer, u32 length);
+s32 txgbe_host_interface_command(struct txgbe_hw *hw, u32 *buffer,
+				 u32 length, u32 timeout, bool return_data);
+
+void txgbe_clear_tx_pending(struct txgbe_hw *hw);
+void txgbe_stop_mac_link_on_d3(struct txgbe_hw *hw);
+bool txgbe_mng_present(struct txgbe_hw *hw);
+bool txgbe_check_mng_access(struct txgbe_hw *hw);
+
+s32 txgbe_get_thermal_sensor_data(struct txgbe_hw *hw);
+s32 txgbe_init_thermal_sensor_thresh(struct txgbe_hw *hw);
+void txgbe_enable_rx(struct txgbe_hw *hw);
+void txgbe_disable_rx(struct txgbe_hw *hw);
+s32 txgbe_setup_mac_link_multispeed_fiber(struct txgbe_hw *hw,
+					  u32 speed,
+					  bool autoneg_wait_to_complete);
+int txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit);
+
+#if 0
+void txgbe_disable_fdir(struct txgbe_hw *hw);
+#endif
+
+/* @txgbe_api.h */
+s32 txgbe_reinit_fdir_tables(struct txgbe_hw *hw);
+s32 txgbe_init_fdir_signature(struct txgbe_hw *hw, u32 fdirctrl);
+s32 txgbe_init_fdir_perfect(struct txgbe_hw *hw, u32 fdirctrl,
+					bool cloud_mode);
+s32 txgbe_fdir_add_signature_filter(struct txgbe_hw *hw,
+					  union txgbe_atr_hash_dword input,
+					  union txgbe_atr_hash_dword common,
+					  u8 queue);
+s32 txgbe_fdir_set_input_mask(struct txgbe_hw *hw,
+			union txgbe_atr_input *input_mask, bool cloud_mode);
+s32 txgbe_fdir_write_perfect_filter(struct txgbe_hw *hw,
+				  union txgbe_atr_input *input,
+				  u16 soft_id, u8 queue, bool cloud_mode);
+s32 txgbe_fdir_erase_perfect_filter(struct txgbe_hw *hw,
+					  union txgbe_atr_input *input,
+					  u16 soft_id);
+s32 txgbe_fdir_add_perfect_filter(struct txgbe_hw *hw,
+					union txgbe_atr_input *input,
+					union txgbe_atr_input *mask,
+					u16 soft_id,
+					u8 queue,
+					bool cloud_mode);
+void txgbe_atr_compute_perfect_hash(union txgbe_atr_input *input,
+					  union txgbe_atr_input *mask);
+u32 txgbe_atr_compute_sig_hash(union txgbe_atr_hash_dword input,
+				     union txgbe_atr_hash_dword common);
+
+s32 txgbe_get_link_capabilities(struct txgbe_hw *hw,
+				      u32 *speed, bool *autoneg);
+enum txgbe_media_type txgbe_get_media_type(struct txgbe_hw *hw);
+void txgbe_disable_tx_laser_multispeed_fiber(struct txgbe_hw *hw);
+void txgbe_enable_tx_laser_multispeed_fiber(struct txgbe_hw *hw);
+void txgbe_flap_tx_laser_multispeed_fiber(struct txgbe_hw *hw);
+void txgbe_set_hard_rate_select_speed(struct txgbe_hw *hw,
+					u32 speed);
+s32 txgbe_setup_mac_link(struct txgbe_hw *hw, u32 speed,
+			       bool autoneg_wait_to_complete);
+void txgbe_init_mac_link_ops(struct txgbe_hw *hw);
+s32 txgbe_reset_hw(struct txgbe_hw *hw);
+s32 txgbe_identify_phy(struct txgbe_hw *hw);
+s32 txgbe_init_phy_ops(struct txgbe_hw *hw);
+s32 txgbe_enable_rx_dma(struct txgbe_hw *hw, u32 regval);
+s32 txgbe_init_ops(struct txgbe_hw *hw);
+s32 txgbe_setup_eee(struct txgbe_hw *hw, bool enable_eee);
+
+s32 txgbe_init_flash_params(struct txgbe_hw *hw);
+s32 txgbe_read_flash_buffer(struct txgbe_hw *hw, u32 offset,
+					  u32 dwords, u32 *data);
+s32 txgbe_write_flash_buffer(struct txgbe_hw *hw, u32 offset,
+					  u32 dwords, u32 *data);
+
+s32 txgbe_read_eeprom(struct txgbe_hw *hw,
+				   u16 offset, u16 *data);
+s32 txgbe_read_eeprom_buffer(struct txgbe_hw *hw, u16 offset,
+					  u16 words, u16 *data);
+s32 txgbe_init_eeprom_params(struct txgbe_hw *hw);
+s32 txgbe_update_eeprom_checksum(struct txgbe_hw *hw);
+s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw);
+s32 txgbe_validate_eeprom_checksum(struct txgbe_hw *hw,
+					    u16 *checksum_val);
+s32 txgbe_update_flash(struct txgbe_hw *hw);
+int txgbe_upgrade_flash(struct txgbe_hw *hw, u32 region,
+								const u8 *data, u32 size);
+s32 txgbe_write_ee_hostif_buffer(struct txgbe_hw *hw,
+				u16 offset, u16 words, u16 *data);
+s32 txgbe_write_ee_hostif(struct txgbe_hw *hw, u16 offset,
+				u16 data);
+s32 txgbe_read_ee_hostif_buffer(struct txgbe_hw *hw,
+				u16 offset, u16 words, u16 *data);
+s32 txgbe_read_ee_hostif(struct txgbe_hw *hw, u16 offset, u16 *data);
+u32 txgbe_rd32_epcs(struct txgbe_hw *hw, u32 addr);
+void txgbe_wr32_epcs(struct txgbe_hw *hw, u32 addr, u32 data);
+void txgbe_wr32_ephy(struct txgbe_hw *hw, u32 addr, u32 data);
+u32 rd32_ephy(struct txgbe_hw *hw, u32 addr);
+
+s32 txgbe_upgrade_flash_hostif(struct txgbe_hw *hw,  u32 region,
+				const u8 *data, u32 size);
+
+s32 txgbe_close_notify(struct txgbe_hw *hw);
+s32 txgbe_open_notify(struct txgbe_hw *hw);
+
+s32 txgbe_set_link_to_kr(struct txgbe_hw *hw, bool autoneg);
+s32 txgbe_set_link_to_kx4(struct txgbe_hw *hw, bool autoneg);
+
+s32 txgbe_set_link_to_kx(struct txgbe_hw *hw,
+			       u32 speed,
+			       bool autoneg);
+u32 txgbe_flash_read_dword(struct txgbe_hw *hw, u32 addr);
+s32 txgbe_hic_write_lldp(struct txgbe_hw *hw,u32 open);
+bool txgbe_is_lldp(struct txgbe_hw *hw);
+
+
+#endif /* _TXGBE_HW_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_lib.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_lib.c
new file mode 100644
index 000000000000..c4a1226cca23
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_lib.c
@@ -0,0 +1,1223 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_lib.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+#include "txgbe_sriov.h"
+
+#ifdef HAVE_TX_MQ
+/**
+ * txgbe_cache_ring_dcb_vmdq - Descriptor ring to register mapping for VMDq
+ * @adapter: board private structure to initialize
+ *
+ * Cache the descriptor ring offsets for VMDq to the assigned rings.  It
+ * will also try to cache the proper offsets if RSS/FCoE are enabled along
+ * with VMDq.
+ *
+ **/
+static bool txgbe_cache_ring_dcb_vmdq(struct txgbe_adapter *adapter)
+{
+#if IS_ENABLED(CONFIG_FCOE)
+	struct txgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE];
+#endif /* CONFIG_FCOE */
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	int i;
+	u16 reg_idx;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	/* verify we have DCB enabled before proceeding */
+	if (tcs <= 1)
+		return false;
+
+	/* verify we have VMDq enabled before proceeding */
+	if (!(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED))
+		return false;
+
+	/* start at VMDq register offset for SR-IOV enabled setups */
+	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
+	for (i = 0; i < adapter->num_rx_queues; i++, reg_idx++) {
+		/* If we are greater than indices move to next pool */
+		if ((reg_idx & ~vmdq->mask) >= tcs)
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
+		adapter->rx_ring[i]->reg_idx = reg_idx;
+	}
+
+	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
+	for (i = 0; i < adapter->num_tx_queues; i++, reg_idx++) {
+		/* If we are greater than indices move to next pool */
+		if ((reg_idx & ~vmdq->mask) >= tcs)
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
+		adapter->tx_ring[i]->reg_idx = reg_idx;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* nothing to do if FCoE is disabled */
+	if (!(adapter->flags & TXGBE_FLAG_FCOE_ENABLED))
+		return true;
+
+	/* The work is already done if the FCoE ring is shared */
+	if (fcoe->offset < tcs)
+		return true;
+
+	/* The FCoE rings exist separately, we need to move their reg_idx */
+	if (fcoe->indices) {
+		u16 queues_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+		u8 fcoe_tc = txgbe_fcoe_get_tc(adapter);
+
+		reg_idx = (vmdq->offset + vmdq->indices) * queues_per_pool;
+		for (i = fcoe->offset; i < adapter->num_rx_queues; i++) {
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask) + fcoe_tc;
+			adapter->rx_ring[i]->reg_idx = reg_idx;
+			reg_idx++;
+		}
+
+		reg_idx = (vmdq->offset + vmdq->indices) * queues_per_pool;
+		for (i = fcoe->offset; i < adapter->num_tx_queues; i++) {
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask) + fcoe_tc;
+			adapter->tx_ring[i]->reg_idx = reg_idx;
+			reg_idx++;
+		}
+	}
+#endif /* CONFIG_FCOE */
+
+	return true;
+}
+
+/* txgbe_get_first_reg_idx - Return first register index associated with ring */
+static void txgbe_get_first_reg_idx(struct txgbe_adapter *adapter, u8 tc,
+				    u16 *tx, u16 *rx)
+{
+	struct net_device *dev = adapter->netdev;
+	u8 num_tcs = netdev_get_num_tc(dev);
+
+	*tx = 0;
+	*rx = 0;
+
+
+	if (num_tcs > 4) {
+		/*
+		 * TCs    : TC0/1 TC2/3 TC4-7
+		 * TxQs/TC:    32    16     8
+		 * RxQs/TC:    16    16    16
+		 */
+		*rx = tc << 4;
+		if (tc < 3)
+			*tx = tc << 5;          /*   0,  32,  64 */
+		else if (tc < 5)
+			*tx = (tc + 2) << 4;    /*  80,  96 */
+		else
+			*tx = (tc + 8) << 3;    /* 104, 112, 120 */
+	} else {
+		/*
+		 * TCs    : TC0 TC1 TC2/3
+		 * TxQs/TC:  64  32    16
+		 * RxQs/TC:  32  32    32
+		 */
+		*rx = tc << 5;
+		if (tc < 2)
+			*tx = tc << 6;          /*  0,  64 */
+		else
+			*tx = (tc + 4) << 4;    /* 96, 112 */
+	}
+
+}
+
+/**
+ * txgbe_cache_ring_dcb - Descriptor ring to register mapping for DCB
+ * @adapter: board private structure to initialize
+ *
+ * Cache the descriptor ring offsets for DCB to the assigned rings.
+ *
+ **/
+static bool txgbe_cache_ring_dcb(struct txgbe_adapter *adapter)
+{
+	int tc, offset, rss_i, i;
+	u16 tx_idx, rx_idx;
+	struct net_device *dev = adapter->netdev;
+	u8 num_tcs = netdev_get_num_tc(dev);
+
+	if (num_tcs <= 1)
+		return false;
+
+	rss_i = adapter->ring_feature[RING_F_RSS].indices;
+
+	for (tc = 0, offset = 0; tc < num_tcs; tc++, offset += rss_i) {
+		txgbe_get_first_reg_idx(adapter, (u8)tc, &tx_idx, &rx_idx);
+		for (i = 0; i < rss_i; i++, tx_idx++, rx_idx++) {
+			adapter->tx_ring[offset + i]->reg_idx = tx_idx;
+			adapter->rx_ring[offset + i]->reg_idx = rx_idx;
+			adapter->tx_ring[offset + i]->dcb_tc = (u8)tc;
+			adapter->rx_ring[offset + i]->dcb_tc = (u8)tc;
+		}
+	}
+
+	return true;
+}
+#endif /* HAVE_TX_MQ */
+
+/**
+ * txgbe_cache_ring_vmdq - Descriptor ring to register mapping for VMDq
+ * @adapter: board private structure to initialize
+ *
+ * Cache the descriptor ring offsets for VMDq to the assigned rings.  It
+ * will also try to cache the proper offsets if RSS/FCoE/SRIOV are enabled along
+ * with VMDq.
+ *
+ **/
+static bool txgbe_cache_ring_vmdq(struct txgbe_adapter *adapter)
+{
+#if IS_ENABLED(CONFIG_FCOE)
+	struct txgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE];
+#endif
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	struct txgbe_ring_feature *rss = &adapter->ring_feature[RING_F_RSS];
+	int i;
+	u16 reg_idx;
+
+	/* only proceed if VMDq is enabled */
+	if (!(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED))
+		return false;
+
+	/* start at VMDq register offset for SR-IOV enabled setups */
+	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
+	for (i = 0; i < adapter->num_rx_queues; i++, reg_idx++) {
+#if IS_ENABLED(CONFIG_FCOE)
+		/* Allow first FCoE queue to be mapped as RSS */
+		if (fcoe->offset && (i > fcoe->offset))
+			break;
+#endif
+		/* If we are greater than indices move to next pool */
+		if ((reg_idx & ~vmdq->mask) >= rss->indices)
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
+		adapter->rx_ring[i]->reg_idx = reg_idx;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* FCoE uses a linear block of queues so just assigning 1:1 */
+	for (; i < adapter->num_rx_queues; i++, reg_idx++)
+		adapter->rx_ring[i]->reg_idx = reg_idx;
+#endif
+
+	reg_idx = vmdq->offset * __ALIGN_MASK(1, ~vmdq->mask);
+	for (i = 0; i < adapter->num_tx_queues; i++, reg_idx++) {
+#if IS_ENABLED(CONFIG_FCOE)
+		/* Allow first FCoE queue to be mapped as RSS */
+		if (fcoe->offset && (i > fcoe->offset))
+			break;
+#endif
+		/* If we are greater than indices move to next pool */
+		if ((reg_idx & rss->mask) >= rss->indices)
+			reg_idx = __ALIGN_MASK(reg_idx, ~vmdq->mask);
+		adapter->tx_ring[i]->reg_idx = reg_idx;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* FCoE uses a linear block of queues so just assigning 1:1 */
+	for (; i < adapter->num_tx_queues; i++, reg_idx++)
+		adapter->tx_ring[i]->reg_idx = reg_idx;
+#endif
+
+	return true;
+}
+
+/**
+ * txgbe_cache_ring_rss - Descriptor ring to register mapping for RSS
+ * @adapter: board private structure to initialize
+ *
+ * Cache the descriptor ring offsets for RSS, ATR, FCoE, and SR-IOV.
+ *
+ **/
+static bool txgbe_cache_ring_rss(struct txgbe_adapter *adapter)
+{
+	u16 i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		adapter->rx_ring[i]->reg_idx = i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		adapter->tx_ring[i]->reg_idx = i;
+
+	return true;
+}
+
+/**
+ * txgbe_cache_ring_register - Descriptor ring to register mapping
+ * @adapter: board private structure to initialize
+ *
+ * Once we know the feature-set enabled for the device, we'll cache
+ * the register offset the descriptor ring is assigned to.
+ *
+ * Note, the order the various feature calls is important.  It must start with
+ * the "most" features enabled at the same time, then trickle down to the
+ * least amount of features turned on at once.
+ **/
+static void txgbe_cache_ring_register(struct txgbe_adapter *adapter)
+{
+#ifdef HAVE_TX_MQ
+	if (txgbe_cache_ring_dcb_vmdq(adapter))
+		return;
+
+	if (txgbe_cache_ring_dcb(adapter))
+		return;
+
+#endif
+	if (txgbe_cache_ring_vmdq(adapter))
+		return;
+
+	txgbe_cache_ring_rss(adapter);
+}
+
+#define TXGBE_RSS_64Q_MASK      0x3F
+#define TXGBE_RSS_16Q_MASK      0xF
+#define TXGBE_RSS_8Q_MASK       0x7
+#define TXGBE_RSS_4Q_MASK       0x3
+#define TXGBE_RSS_2Q_MASK       0x1
+#define TXGBE_RSS_DISABLED_MASK 0x0
+
+#ifdef HAVE_TX_MQ
+/**
+ * txgbe_set_dcb_vmdq_queues: Allocate queues for VMDq devices w/ DCB
+ * @adapter: board private structure to initialize
+ *
+ * When VMDq (Virtual Machine Devices queue) is enabled, allocate queues
+ * and VM pools where appropriate.  Also assign queues based on DCB
+ * priorities and map accordingly..
+ *
+ **/
+static bool txgbe_set_dcb_vmdq_queues(struct txgbe_adapter *adapter)
+{
+	u16 i;
+	u16 vmdq_i = adapter->ring_feature[RING_F_VMDQ].limit;
+	u16 vmdq_m = 0;
+#if IS_ENABLED(CONFIG_FCOE)
+	u16 fcoe_i = 0;
+#endif
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	/* verify we have DCB enabled before proceeding */
+	if (tcs <= 1)
+		return false;
+
+	/* verify we have VMDq enabled before proceeding */
+	if (!(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED))
+		return false;
+
+	/* Add starting offset to total pool count */
+	vmdq_i += adapter->ring_feature[RING_F_VMDQ].offset;
+
+	/* 16 pools w/ 8 TC per pool */
+	if (tcs > 4) {
+		vmdq_i = min_t(u16, vmdq_i, 16);
+		vmdq_m = TXGBE_VMDQ_8Q_MASK;
+	/* 32 pools w/ 4 TC per pool */
+	} else {
+		vmdq_i = min_t(u16, vmdq_i, 32);
+		vmdq_m = TXGBE_VMDQ_4Q_MASK;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* queues in the remaining pools are available for FCoE */
+	fcoe_i = (128 / __ALIGN_MASK(1, ~vmdq_m)) - vmdq_i;
+#endif /* CONFIG_FCOE */
+
+	/* remove the starting offset from the pool count */
+	vmdq_i -= adapter->ring_feature[RING_F_VMDQ].offset;
+
+	/* save features for later use */
+	adapter->ring_feature[RING_F_VMDQ].indices = vmdq_i;
+	adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
+
+	/*
+	 * We do not support DCB, VMDq, and RSS all simultaneously
+	 * so we will disable RSS since it is the lowest priority
+	 */
+	adapter->ring_feature[RING_F_RSS].indices = 1;
+	adapter->ring_feature[RING_F_RSS].mask = TXGBE_RSS_DISABLED_MASK;
+
+	adapter->queues_per_pool = tcs;/*maybe same to num_rx_queues_per_pool*/
+	adapter->num_rx_pools = vmdq_i;
+	adapter->num_rx_queues_per_pool = tcs;
+
+	adapter->num_tx_queues = vmdq_i * tcs;
+	adapter->num_rx_queues = vmdq_i * tcs;
+
+	/* disable ATR as it is not supported when VMDq is enabled */
+	adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED) {
+		struct txgbe_ring_feature *fcoe;
+
+		fcoe = &adapter->ring_feature[RING_F_FCOE];
+
+		/* limit ourselves based on feature limits */
+		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
+
+		if (fcoe_i) {
+			/* alloc queues for FCoE separately */
+			fcoe->indices = fcoe_i;
+			fcoe->offset = vmdq_i * tcs;
+
+			/* add queues to adapter */
+			adapter->num_tx_queues += fcoe_i;
+			adapter->num_rx_queues += fcoe_i;
+		} else if (tcs > 1) {
+			/* use queue belonging to FcoE TC */
+			fcoe->indices = 1;
+			fcoe->offset = txgbe_fcoe_get_tc(adapter);
+		} else {
+			adapter->flags &= ~TXGBE_FLAG_FCOE_ENABLED;
+
+			fcoe->indices = 0;
+			fcoe->offset = 0;
+		}
+	}
+#endif /* CONFIG_FCOE */
+
+	/* configure TC to queue mapping */
+	for (i = 0; i < tcs; i++)
+		netdev_set_tc_queue(adapter->netdev, (u8)i, 1, i);
+
+	return true;
+}
+
+/**
+ * txgbe_set_dcb_queues: Allocate queues for a DCB-enabled device
+ * @adapter: board private structure to initialize
+ *
+ * When DCB (Data Center Bridging) is enabled, allocate queues for
+ * each traffic class.  If multiqueue isn't available,then abort DCB
+ * initialization.
+ *
+ * This function handles all combinations of DCB, RSS, and FCoE.
+ *
+ **/
+static bool txgbe_set_dcb_queues(struct txgbe_adapter *adapter)
+{
+	struct net_device *dev = adapter->netdev;
+	struct txgbe_ring_feature *f;
+	u16 rss_i, rss_m, i;
+	u16 tcs;
+
+	/* Map queue offset and counts onto allocated tx queues */
+	tcs = netdev_get_num_tc(dev);
+
+	if (tcs <= 1)
+		return false;
+
+	/* determine the upper limit for our current DCB mode */
+#ifndef HAVE_NETDEV_SELECT_QUEUE
+	rss_i = adapter->indices;
+#else
+	rss_i = dev->num_tx_queues / tcs;
+#endif
+	if (tcs > 4) {
+		/* 8 TC w/ 8 queues per TC */
+		rss_i = min_t(u16, rss_i, 8);
+		rss_m = TXGBE_RSS_8Q_MASK;
+	} else {
+		/* 4 TC w/ 16 queues per TC */
+		rss_i = min_t(u16, rss_i, 16);
+		rss_m = TXGBE_RSS_16Q_MASK;
+	}
+
+	/* set RSS mask and indices */
+	f = &adapter->ring_feature[RING_F_RSS];
+	rss_i = min_t(u16, rss_i, f->limit);
+	f->indices = rss_i;
+	f->mask = rss_m;
+
+	/* disable ATR as it is not supported when DCB is enabled */
+	adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/*
+	 * FCoE enabled queues require special configuration indexed
+	 * by feature specific indices and mask. Here we map FCoE
+	 * indices onto the DCB queue pairs allowing FCoE to own
+	 * configuration later.
+	 */
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED) {
+		u8 tc = txgbe_fcoe_get_tc(adapter);
+
+		f = &adapter->ring_feature[RING_F_FCOE];
+		f->indices = min_t(u16, rss_i, f->limit);
+		f->offset = rss_i * tc;
+	}
+#endif /* CONFIG_FCOE */
+
+	for (i = 0; i < tcs; i++)
+		netdev_set_tc_queue(dev, (u8)i, rss_i, rss_i * i);
+
+	adapter->num_tx_queues = rss_i * tcs;
+	adapter->num_rx_queues = rss_i * tcs;
+
+	return true;
+}
+#endif
+
+/**
+ * txgbe_set_vmdq_queues: Allocate queues for VMDq devices
+ * @adapter: board private structure to initialize
+ *
+ * When VMDq (Virtual Machine Devices queue) is enabled, allocate queues
+ * and VM pools where appropriate.  If RSS is available, then also try and
+ * enable RSS and map accordingly.
+ *
+ **/
+static bool txgbe_set_vmdq_queues(struct txgbe_adapter *adapter)
+{
+	u16 vmdq_i = adapter->ring_feature[RING_F_VMDQ].limit;
+	u16 vmdq_m = 0;
+	u16 rss_i = adapter->ring_feature[RING_F_RSS].limit;
+	u16 rss_m = TXGBE_RSS_DISABLED_MASK;
+#if IS_ENABLED(CONFIG_FCOE)
+	u16 fcoe_i = 0;
+#endif
+
+	/* only proceed if VMDq is enabled */
+	if (!(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED))
+		return false;
+	/* Add starting offset to total pool count */
+	vmdq_i += adapter->ring_feature[RING_F_VMDQ].offset;
+
+	/* double check we are limited to maximum pools */
+	vmdq_i = min_t(u16, TXGBE_MAX_VMDQ_INDICES, vmdq_i);
+
+	/* 64 pool mode with 2 queues per pool, or
+	 * 16/32/64 pool mode with 1 queue per pool */
+	if ((vmdq_i > 32) || (rss_i < 4) || adapter->vf_mode == 63) {
+		vmdq_m = TXGBE_VMDQ_2Q_MASK;
+		rss_m = TXGBE_RSS_2Q_MASK;
+		rss_i = min_t(u16, rss_i, 2);
+	/* 32 pool mode with 4 queues per pool */
+	} else {
+		vmdq_m = TXGBE_VMDQ_4Q_MASK;
+		rss_m = TXGBE_RSS_4Q_MASK;
+		rss_i = 4;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* queues in the remaining pools are available for FCoE */
+	fcoe_i = 128 - (vmdq_i * __ALIGN_MASK(1, ~vmdq_m));
+#endif
+
+	/* remove the starting offset from the pool count */
+	vmdq_i -= adapter->ring_feature[RING_F_VMDQ].offset;
+
+	/* save features for later use */
+	adapter->ring_feature[RING_F_VMDQ].indices = vmdq_i;
+	adapter->ring_feature[RING_F_VMDQ].mask = vmdq_m;
+
+	/* limit RSS based on user input and save for later use */
+	adapter->ring_feature[RING_F_RSS].indices = rss_i;
+	adapter->ring_feature[RING_F_RSS].mask = rss_m;
+
+	adapter->queues_per_pool = rss_i;/*maybe same to num_rx_queues_per_pool*/
+	adapter->num_rx_pools = vmdq_i;
+	adapter->num_rx_queues_per_pool = rss_i;
+
+	adapter->num_rx_queues = vmdq_i * rss_i;
+#ifdef HAVE_TX_MQ
+	adapter->num_tx_queues = vmdq_i * rss_i;
+#else
+	adapter->num_tx_queues = vmdq_i;
+#endif /* HAVE_TX_MQ */
+
+	/* disable ATR as it is not supported when VMDq is enabled */
+	adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/*
+	 * FCoE can use rings from adjacent buffers to allow RSS
+	 * like behavior.  To account for this we need to add the
+	 * FCoE indices to the total ring count.
+	 */
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED) {
+		struct txgbe_ring_feature *fcoe;
+
+		fcoe = &adapter->ring_feature[RING_F_FCOE];
+
+		/* limit ourselves based on feature limits */
+		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
+
+		if (vmdq_i > 1 && fcoe_i) {
+			/* alloc queues for FCoE separately */
+			fcoe->indices = fcoe_i;
+			fcoe->offset = vmdq_i * rss_i;
+		} else {
+			/* merge FCoE queues with RSS queues */
+			fcoe_i = min_t(u16, fcoe_i + rss_i, num_online_cpus());
+
+			/* limit indices to rss_i if MSI-X is disabled */
+			if (!(adapter->flags & TXGBE_FLAG_MSIX_ENABLED))
+				fcoe_i = rss_i;
+
+			/* attempt to reserve some queues for just FCoE */
+			fcoe->indices = min_t(u16, fcoe_i, fcoe->limit);
+			fcoe->offset = fcoe_i - fcoe->indices;
+			fcoe_i -= rss_i;
+		}
+
+		/* add queues to adapter */
+		adapter->num_tx_queues += fcoe_i;
+		adapter->num_rx_queues += fcoe_i;
+	}
+#endif /* CONFIG_FCOE */
+
+	return true;
+}
+
+/**
+ * txgbe_set_rss_queues: Allocate queues for RSS
+ * @adapter: board private structure to initialize
+ *
+ * This is our "base" multiqueue mode.  RSS (Receive Side Scaling) will try
+ * to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
+ *
+ **/
+static bool txgbe_set_rss_queues(struct txgbe_adapter *adapter)
+{
+	struct txgbe_ring_feature *f;
+	u16 rss_i;
+
+	/* set mask for 16 queue limit of RSS */
+	f = &adapter->ring_feature[RING_F_RSS];
+	rss_i = f->limit;
+
+	f->indices = rss_i;
+	f->mask = TXGBE_RSS_64Q_MASK;
+
+	/* disable ATR by default, it will be configured below */
+	adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+
+	/*
+	 * Use Flow Director in addition to RSS to ensure the best
+	 * distribution of flows across cores, even when an FDIR flow
+	 * isn't matched.
+	 */
+	if (rss_i > 1 && adapter->atr_sample_rate) {
+		f = &adapter->ring_feature[RING_F_FDIR];
+
+		rss_i = f->indices = f->limit;
+
+		if (!(adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+			adapter->flags |= TXGBE_FLAG_FDIR_HASH_CAPABLE;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/*
+	 * FCoE can exist on the same rings as standard network traffic
+	 * however it is preferred to avoid that if possible.  In order
+	 * to get the best performance we allocate as many FCoE queues
+	 * as we can and we place them at the end of the ring array to
+	 * avoid sharing queues with standard RSS on systems with 24 or
+	 * more CPUs.
+	 */
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED) {
+		struct net_device *dev = adapter->netdev;
+		u16 fcoe_i;
+
+		f = &adapter->ring_feature[RING_F_FCOE];
+
+		/* merge FCoE queues with RSS queues */
+		fcoe_i = min_t(u16, f->limit + rss_i, num_online_cpus());
+		fcoe_i = min_t(u16, fcoe_i, dev->num_tx_queues);
+
+		/* limit indices to rss_i if MSI-X is disabled */
+		if (!(adapter->flags & TXGBE_FLAG_MSIX_ENABLED))
+			fcoe_i = rss_i;
+
+		/* attempt to reserve some queues for just FCoE */
+		f->indices = min_t(u16, fcoe_i, f->limit);
+		f->offset = fcoe_i - f->indices;
+		rss_i = max_t(u16, fcoe_i, rss_i);
+	}
+#endif /* CONFIG_FCOE */
+
+	adapter->num_rx_queues = rss_i;
+#ifdef HAVE_TX_MQ
+	adapter->num_tx_queues = rss_i;
+#endif
+
+	return true;
+}
+
+/*
+ * txgbe_set_num_queues: Allocate queues for device, feature dependent
+ * @adapter: board private structure to initialize
+ *
+ * This is the top level queue allocation routine.  The order here is very
+ * important, starting with the "most" number of features turned on at once,
+ * and ending with the smallest set of features.  This way large combinations
+ * can be allocated if they're turned on, and smaller combinations are the
+ * fallthrough conditions.
+ *
+ **/
+static void txgbe_set_num_queues(struct txgbe_adapter *adapter)
+{
+	/* Start with base case */
+	adapter->num_rx_queues = 1;
+	adapter->num_tx_queues = 1;
+	adapter->queues_per_pool = 1;/*maybe same to num_rx_queues_per_pool*/
+	adapter->num_xdp_queues = 0;
+	adapter->num_rx_pools = adapter->num_rx_queues;
+	adapter->num_rx_queues_per_pool = 1;
+
+#ifdef HAVE_TX_MQ
+	if (txgbe_set_dcb_vmdq_queues(adapter))
+		return;
+
+	if (txgbe_set_dcb_queues(adapter))
+		return;
+#endif
+	if (txgbe_set_vmdq_queues(adapter))
+		return;
+
+	txgbe_set_rss_queues(adapter);
+}
+
+/**
+ * txgbe_acquire_msix_vectors - acquire MSI-X vectors
+ * @adapter: board private structure
+ *
+ * Attempts to acquire a suitable range of MSI-X vector interrupts. Will
+ * return a negative error code if unable to acquire MSI-X vectors for any
+ * reason.
+ */
+static int txgbe_acquire_msix_vectors(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i, vectors, vector_threshold;
+
+	if (!(adapter->flags & TXGBE_FLAG_MSIX_CAPABLE))
+		return -EOPNOTSUPP;
+
+	/* We start by asking for one vector per queue pair */
+	vectors = max(adapter->num_rx_queues, adapter->num_tx_queues);
+
+	/* It is easy to be greedy for MSI-X vectors. However, it really
+	 * doesn't do much good if we have a lot more vectors than CPUs. We'll
+	 * be somewhat conservative and only ask for (roughly) the same number
+	 * of vectors as there are CPUs.
+	 */
+	vectors = min_t(int, vectors, num_online_cpus());
+
+	/* Some vectors are necessary for non-queue interrupts */
+	vectors += NON_Q_VECTORS;
+
+	/* Hardware can only support a maximum of hw.mac->max_msix_vectors.
+	 * With features such as RSS and VMDq, we can easily surpass the
+	 * number of Rx and Tx descriptor queues supported by our device.
+	 * Thus, we cap the maximum in the rare cases where the CPU count also
+	 * exceeds our vector limit
+	 */
+	vectors = min_t(int, vectors, hw->mac.max_msix_vectors);
+
+	/* We want a minimum of two MSI-X vectors for (1) a TxQ[0] + RxQ[0]
+	 * handler, and (2) an Other (Link Status Change, etc.) handler.
+	 */
+	vector_threshold = MIN_MSIX_COUNT;
+
+	adapter->msix_entries = kcalloc(vectors,
+					sizeof(struct msix_entry),
+					GFP_KERNEL);
+	if (!adapter->msix_entries)
+		return -ENOMEM;
+
+	for (i = 0; i < vectors; i++)
+		adapter->msix_entries[i].entry = i;
+
+	vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+					vector_threshold, vectors);
+	if (vectors < 0) {
+		/* A negative count of allocated vectors indicates an error in
+		 * acquiring within the specified range of MSI-X vectors */
+		e_dev_warn("Failed to allocate MSI-X interrupts. Err: %d\n",
+			   vectors);
+
+		adapter->flags &= ~TXGBE_FLAG_MSIX_ENABLED;
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+
+		return vectors;
+	}
+
+	/* we successfully allocated some number of vectors within our
+	 * requested range.
+	 */
+	adapter->flags |= TXGBE_FLAG_MSIX_ENABLED;
+
+	/* Adjust for only the vectors we'll use, which is minimum
+	 * of max_q_vectors, or the number of vectors we were allocated.
+	 */
+	vectors -= NON_Q_VECTORS;
+	adapter->num_q_vectors = min_t(int, vectors, adapter->max_q_vectors);
+
+	return 0;
+}
+
+static void txgbe_add_ring(struct txgbe_ring *ring,
+			   struct txgbe_ring_container *head)
+{
+	ring->next = head->ring;
+	head->ring = ring;
+	head->count++;
+}
+
+/**
+ * txgbe_alloc_q_vector - Allocate memory for a single interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_count: q_vectors allocated on adapter, used for ring interleaving
+ * @v_idx: index of vector in adapter struct
+ * @txr_count: total number of Tx rings to allocate
+ * @txr_idx: index of first Tx ring to allocate
+ * @rxr_count: total number of Rx rings to allocate
+ * @rxr_idx: index of first Rx ring to allocate
+ *
+ * We allocate one q_vector.  If allocation fails we return -ENOMEM.
+ **/
+static int txgbe_alloc_q_vector(struct txgbe_adapter *adapter,
+				unsigned int v_count, unsigned int v_idx,
+				unsigned int txr_count, unsigned int txr_idx,
+				unsigned int rxr_count, unsigned int rxr_idx)
+{
+	struct txgbe_q_vector *q_vector;
+	struct txgbe_ring *ring;
+	int node = -1;
+#ifdef HAVE_IRQ_AFFINITY_HINT
+	int cpu = -1;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+#endif
+	int ring_count, size;
+
+	/* note this will allocate space for the ring structure as well! */
+	ring_count = txr_count + rxr_count;
+	size = sizeof(struct txgbe_q_vector) +
+	       (sizeof(struct txgbe_ring) * ring_count);
+
+#ifdef HAVE_IRQ_AFFINITY_HINT
+	/* customize cpu for Flow Director mapping */
+	if ((tcs <= 1) && !(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED)) {
+		u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+		if (rss_i > 1 && adapter->atr_sample_rate) {
+			if (cpu_online(v_idx)) {
+				cpu = v_idx;
+				node = cpu_to_node(cpu);
+			}
+		}
+	}
+
+#endif
+	/* allocate q_vector and rings */
+	q_vector = kzalloc_node(size, GFP_KERNEL, node);
+	if (!q_vector)
+		q_vector = kzalloc(size, GFP_KERNEL);
+	if (!q_vector)
+		return -ENOMEM;
+
+	/* setup affinity mask and node */
+#ifdef HAVE_IRQ_AFFINITY_HINT
+	if (cpu != -1)
+		cpumask_set_cpu(cpu, &q_vector->affinity_mask);
+#endif
+	q_vector->numa_node = node;
+
+	/* initialize CPU for DCA */
+	q_vector->cpu = -1;
+
+#ifndef TXGBE_NO_LRO
+	/* initialize LRO */
+	__skb_queue_head_init(&q_vector->lrolist.active);
+
+#endif
+	/* initialize NAPI */
+	netif_napi_add(adapter->netdev, &q_vector->napi, txgbe_poll);
+#ifndef HAVE_NETIF_NAPI_ADD_CALLS_NAPI_HASH_ADD
+#ifdef HAVE_NDO_BUSY_POLL
+	napi_hash_add(&q_vector->napi);
+#endif
+#endif /*HAVE_NETIF_NAPI_ADD_CALLS_NAPI_HASH_ADD*/
+
+#ifdef HAVE_NDO_BUSY_POLL
+	/* initialize busy poll */
+	atomic_set(&q_vector->state, TXGBE_QV_STATE_DISABLE);
+
+#endif
+	/* tie q_vector and adapter together */
+	adapter->q_vector[v_idx] = q_vector;
+	q_vector->adapter = adapter;
+	q_vector->v_idx = v_idx;
+
+	/* initialize work limits */
+	q_vector->tx.work_limit = adapter->tx_work_limit;
+	q_vector->rx.work_limit = adapter->rx_work_limit;
+
+	/* initialize pointer to rings */
+	ring = q_vector->ring;
+
+	/* intialize ITR */
+	if (txr_count && !rxr_count) {
+		/* tx only vector */
+		if (adapter->tx_itr_setting == 1)
+			q_vector->itr = TXGBE_12K_ITR;
+		else
+			q_vector->itr = adapter->tx_itr_setting;
+	} else {
+		/* rx or rx/tx vector */
+		if (adapter->rx_itr_setting == 1)
+			q_vector->itr = TXGBE_20K_ITR;
+		else
+			q_vector->itr = adapter->rx_itr_setting;
+	}
+
+	while (txr_count) {
+		/* assign generic ring traits */
+		ring->dev = pci_dev_to_dev(adapter->pdev);
+		ring->netdev = adapter->netdev;
+
+		/* configure backlink on ring */
+		ring->q_vector = q_vector;
+
+		/* update q_vector Tx values */
+		txgbe_add_ring(ring, &q_vector->tx);
+
+		/* apply Tx specific ring traits */
+		ring->count = adapter->tx_ring_count;
+		if (adapter->num_vmdqs > 1)
+			ring->queue_index =
+				txr_idx % adapter->queues_per_pool;
+		else
+			ring->queue_index = txr_idx;
+
+		/* assign ring to adapter */
+		adapter->tx_ring[txr_idx] = ring;
+
+		/* update count and index */
+		txr_count--;
+		txr_idx += v_count;
+
+		/* push pointer to next ring */
+		ring++;
+	}
+
+	while (rxr_count) {
+		/* assign generic ring traits */
+		ring->dev = pci_dev_to_dev(adapter->pdev);
+		ring->netdev = adapter->netdev;
+
+		/* configure backlink on ring */
+		ring->q_vector = q_vector;
+
+		/* update q_vector Rx values */
+		txgbe_add_ring(ring, &q_vector->rx);
+
+#if IS_ENABLED(CONFIG_FCOE)
+		if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED) {
+			struct txgbe_ring_feature *f;
+			f = &adapter->ring_feature[RING_F_FCOE];
+
+			if ((rxr_idx >= f->offset) &&
+			    (rxr_idx < f->offset + f->indices)) {
+				set_bit(__TXGBE_RX_FCOE, &ring->state);
+			}
+		}
+#endif /* CONFIG_FCOE */
+
+		/* apply Rx specific ring traits */
+		ring->count = adapter->rx_ring_count;
+		if (adapter->num_vmdqs > 1)
+			ring->queue_index =
+				rxr_idx % adapter->queues_per_pool;
+		else
+			ring->queue_index = rxr_idx;
+
+		/* assign ring to adapter */
+		adapter->rx_ring[rxr_idx] = ring;
+
+		/* update count and index */
+		rxr_count--;
+		rxr_idx += v_count;
+
+		/* push pointer to next ring */
+		ring++;
+	}
+
+	return 0;
+}
+
+/**
+ * txgbe_free_q_vector - Free memory allocated for specific interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_idx: Index of vector to be freed
+ *
+ * This function frees the memory allocated to the q_vector.  In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
+ **/
+static void txgbe_free_q_vector(struct txgbe_adapter *adapter, int v_idx)
+{
+	struct txgbe_q_vector *q_vector = adapter->q_vector[v_idx];
+	struct txgbe_ring *ring;
+
+	txgbe_for_each_ring(ring, q_vector->tx)
+		adapter->tx_ring[ring->queue_index] = NULL;
+
+	txgbe_for_each_ring(ring, q_vector->rx)
+		adapter->rx_ring[ring->queue_index] = NULL;
+
+	adapter->q_vector[v_idx] = NULL;
+#ifdef HAVE_NDO_BUSY_POLL
+	napi_hash_del(&q_vector->napi);
+#endif
+	netif_napi_del(&q_vector->napi);
+#ifndef TXGBE_NO_LRO
+	__skb_queue_purge(&q_vector->lrolist.active);
+#endif
+	kfree_rcu(q_vector, rcu);
+}
+
+/**
+ * txgbe_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one q_vector per queue interrupt.  If allocation fails we
+ * return -ENOMEM.
+ **/
+static int txgbe_alloc_q_vectors(struct txgbe_adapter *adapter)
+{
+	unsigned int q_vectors = adapter->num_q_vectors;
+	unsigned int rxr_remaining = adapter->num_rx_queues;
+	unsigned int txr_remaining = adapter->num_tx_queues;
+	unsigned int rxr_idx = 0, txr_idx = 0, v_idx = 0;
+	int err;
+
+	if (q_vectors >= (rxr_remaining + txr_remaining)) {
+		for (; rxr_remaining; v_idx++) {
+			err = txgbe_alloc_q_vector(adapter, q_vectors, v_idx,
+						   0, 0, 1, rxr_idx);
+			if (err)
+				goto err_out;
+
+			/* update counts and index */
+			rxr_remaining--;
+			rxr_idx++;
+		}
+	}
+
+	for (; v_idx < q_vectors; v_idx++) {
+		int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
+		int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
+		err = txgbe_alloc_q_vector(adapter, q_vectors, v_idx,
+					   tqpv, txr_idx,
+					   rqpv, rxr_idx);
+
+		if (err)
+			goto err_out;
+
+		/* update counts and index */
+		rxr_remaining -= rqpv;
+		txr_remaining -= tqpv;
+		rxr_idx++;
+		txr_idx++;
+	}
+
+	return 0;
+
+err_out:
+	adapter->num_tx_queues = 0;
+	adapter->num_rx_queues = 0;
+	adapter->num_q_vectors = 0;
+
+	while (v_idx--)
+		txgbe_free_q_vector(adapter, v_idx);
+
+	return -ENOMEM;
+}
+
+/**
+ * txgbe_free_q_vectors - Free memory allocated for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function frees the memory allocated to the q_vectors.  In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
+ **/
+static void txgbe_free_q_vectors(struct txgbe_adapter *adapter)
+{
+	int v_idx = adapter->num_q_vectors;
+
+	adapter->num_tx_queues = 0;
+	adapter->num_rx_queues = 0;
+	adapter->num_q_vectors = 0;
+
+	while (v_idx--)
+		txgbe_free_q_vector(adapter, v_idx);
+}
+
+void txgbe_reset_interrupt_capability(struct txgbe_adapter *adapter)
+{
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED) {
+		adapter->flags &= ~TXGBE_FLAG_MSIX_ENABLED;
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+	} else if (adapter->flags & TXGBE_FLAG_MSI_ENABLED) {
+		adapter->flags &= ~TXGBE_FLAG_MSI_ENABLED;
+		pci_disable_msi(adapter->pdev);
+	}
+}
+
+/**
+ * txgbe_set_interrupt_capability - set MSI-X or MSI if supported
+ * @adapter: board private structure to initialize
+ *
+ * Attempt to configure the interrupts using the best available
+ * capabilities of the hardware and the kernel.
+ **/
+void txgbe_set_interrupt_capability(struct txgbe_adapter *adapter)
+{
+	int err;
+
+	/* We will try to get MSI-X interrupts first */
+	if (!txgbe_acquire_msix_vectors(adapter))
+		return;
+
+	/* At this point, we do not have MSI-X capabilities. We need to
+	 * reconfigure or disable various features which require MSI-X
+	 * capability.
+	 */
+
+	/* Disable DCB unless we only have a single traffic class */
+	if (netdev_get_num_tc(adapter->netdev) > 1) {
+		e_dev_warn("Number of DCB TCs exceeds number of available "
+			"queues. Disabling DCB support.\n");
+		netdev_reset_tc(adapter->netdev);
+
+		adapter->flags &= ~TXGBE_FLAG_DCB_ENABLED;
+		adapter->temp_dcb_cfg.pfc_mode_enable = false;
+		adapter->dcb_cfg.pfc_mode_enable = false;
+	}
+
+	adapter->dcb_cfg.num_tcs.pg_tcs = 1;
+	adapter->dcb_cfg.num_tcs.pfc_tcs = 1;
+
+	/* Disable VMDq support */
+	e_dev_warn("Disabling VMQd support\n");
+	adapter->flags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+
+#ifdef CONFIG_PCI_IOV
+	/* Disable SR-IOV support */
+	e_dev_warn("Disabling SR-IOV support\n");
+	txgbe_disable_sriov(adapter);
+#endif /* CONFIG_PCI_IOV */
+
+	/* Disable RSS */
+	e_dev_warn("Disabling RSS support\n");
+	adapter->ring_feature[RING_F_RSS].limit = 1;
+
+	/* recalculate number of queues now that many features have been
+	 * changed or disabled.
+	 */
+	txgbe_set_num_queues(adapter);
+	adapter->num_q_vectors = 1;
+
+	if (!(adapter->flags & TXGBE_FLAG_MSI_CAPABLE))
+		return;
+
+	err = pci_enable_msi(adapter->pdev);
+	if (err)
+		e_dev_warn("Failed to allocate MSI interrupt, falling back to "
+		"legacy. Error: %d\n",
+			   err);
+	else
+		adapter->flags |= TXGBE_FLAG_MSI_ENABLED;
+}
+
+/**
+ * txgbe_init_interrupt_scheme - Determine proper interrupt scheme
+ * @adapter: board private structure to initialize
+ *
+ * We determine which interrupt scheme to use based on...
+ * - Kernel support (MSI, MSI-X)
+ *   - which can be user-defined (via MODULE_PARAM)
+ * - Hardware queue count (num_*_queues)
+ *   - defined by miscellaneous hardware support/features (RSS, etc.)
+ **/
+int txgbe_init_interrupt_scheme(struct txgbe_adapter *adapter)
+{
+	int err;
+
+	/* Number of supported queues */
+	txgbe_set_num_queues(adapter);
+
+	/* Set interrupt mode */
+	txgbe_set_interrupt_capability(adapter);
+
+	/* Allocate memory for queues */
+	err = txgbe_alloc_q_vectors(adapter);
+	if (err) {
+		e_err(probe, "Unable to allocate memory for queue vectors\n");
+		txgbe_reset_interrupt_capability(adapter);
+		return err;
+	}
+
+	txgbe_cache_ring_register(adapter);
+
+	set_bit(__TXGBE_DOWN, &adapter->state);
+
+	return 0;
+}
+
+/**
+ * txgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
+ * @adapter: board private structure to clear interrupt scheme on
+ *
+ * We go through and clear interrupt specific resources and reset the structure
+ * to pre-load conditions
+ **/
+void txgbe_clear_interrupt_scheme(struct txgbe_adapter *adapter)
+{
+	txgbe_free_q_vectors(adapter);
+	txgbe_reset_interrupt_capability(adapter);
+}
+
+void txgbe_tx_ctxtdesc(struct txgbe_ring *tx_ring, u32 vlan_macip_lens,
+		       u32 fcoe_sof_eof, u32 type_tucmd, u32 mss_l4len_idx)
+{
+	struct txgbe_tx_context_desc *context_desc;
+	u16 i = tx_ring->next_to_use;
+
+	context_desc = TXGBE_TX_CTXTDESC(tx_ring, i);
+
+	i++;
+	tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
+
+	/* set bits to identify this as an advanced context descriptor */
+	type_tucmd |= TXGBE_TXD_DTYP_CTXT;
+	context_desc->vlan_macip_lens   = cpu_to_le32(vlan_macip_lens);
+	context_desc->seqnum_seed       = cpu_to_le32(fcoe_sof_eof);
+	context_desc->type_tucmd_mlhl   = cpu_to_le32(type_tucmd);
+	context_desc->mss_l4len_idx     = cpu_to_le32(mss_l4len_idx);
+}
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index d3b9f73ecba4..efe43ef7b26a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -1,17 +1,119 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_main.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code
+ */
 
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
 #include <linux/string.h>
-#include <linux/aer.h>
-#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/pkt_sched.h>
+#include <linux/ipv6.h>
+#ifdef NETIF_F_TSO
+#include <net/checksum.h>
+#ifdef NETIF_F_TSO6
+#include <net/ipv6.h>
+#include <net/ip6_checksum.h>
+#endif /* NETIF_F_TSO6 */
+#endif /* NETIF_F_TSO */
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#endif
 
+#include <linux/if_bridge.h>
 #include "txgbe.h"
+#ifdef HAVE_XDP_SUPPORT
+#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
+#include <linux/atomic.h>
+#endif
+#ifdef HAVE_AF_XDP_ZC_SUPPORT
+#ifndef HAVE_MEM_TYPE_XSK_BUFF_POOL
+#include <net/xdp_sock.h>
+#else
+#include <net/xdp_sock_drv.h>
+#endif
+#endif /* HAVE_AF_XDP_ZC_SUPPORT */
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+#include <net/vxlan.h>
+#include <net/udp_tunnel.h>
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD */
+#ifdef HAVE_VXLAN_RX_OFFLOAD
+#include <net/vxlan.h>
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+#ifdef NETIF_F_HW_TC
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_gact.h>
+#include <net/tc_act/tc_mirred.h>
+#endif /* NETIF_F_HW_TC */
+
+
+#include "txgbe_dcb.h"
+#include "txgbe_sriov.h"
+#include "txgbe_hw.h"
+#include "txgbe_phy.h"
+#include "txgbe_pcierr.h"
+#include "txgbe_bp.h"
 
-char txgbe_driver_name[] = "txgbe";
+char txgbe_driver_name[32] = TXGBE_NAME;
+static const char txgbe_driver_string[] =
+			"WangXun 10 Gigabit PCI Express Network Driver";
+
+#define DRV_HW_PERF
+
+#define FPGA
+
+#define DRIVERIOV
+
+#define BYPASS_TAG
+
+#define RELEASE_TAG
+
+#if (defined(TXGBE_SUPPORT_KYLIN_FT) || defined(TXGBE_SUPPORT_KYLIN_LX))
+#define DRV_VERSION     __stringify(1.3.3klos)
+#elif defined(CONFIG_EULER_KERNEL)
+#define DRV_VERSION     __stringify(1.3.3elos)
+#elif defined(CONFIG_UOS_KERNEL)
+#define DRV_VERSION     __stringify(1.3.3uos)
+#else
+#define DRV_VERSION     __stringify(1.3.3)
+#endif
+const char txgbe_driver_version[32] = DRV_VERSION;
+static const char txgbe_copyright[] =
+		"Copyright (c) 2015 -2017 Beijing WangXun Technology Co., Ltd";
+static const char txgbe_overheat_msg[] =
+		"Network adapter has been stopped because it has over heated. "
+		"If the problem persists, restart the computer, or "
+		"power off the system and replace the adapter";
+static const char txgbe_underheat_msg[] =
+		"Network adapter has been started again since the temperature "
+		"has been back to normal state";
 
 /* txgbe_pci_tbl - PCI Device ID Table
  *
@@ -22,36 +124,10455 @@ char txgbe_driver_name[] = "txgbe";
  *   Class, Class Mask, private data (not used) }
  */
 static const struct pci_device_id txgbe_pci_tbl[] = {
-	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0},
-	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0},
+	{ PCI_VDEVICE(TRUSTNETIC, TXGBE_DEV_ID_SP1000), 0},
+	{ PCI_VDEVICE(TRUSTNETIC, TXGBE_DEV_ID_WX1820), 0},
 	/* required last entry */
 	{ .device = 0 }
 };
+MODULE_DEVICE_TABLE(pci, txgbe_pci_tbl);
+
+
+MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <linux.nic@trustnetic.com>");
+MODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+static struct workqueue_struct *txgbe_wq;
+
+static bool txgbe_is_sfp(struct txgbe_hw *hw);
+static bool txgbe_check_cfg_remove(struct txgbe_hw *hw, struct pci_dev *pdev);
+static void txgbe_clean_rx_ring(struct txgbe_ring *rx_ring);
+static void txgbe_clean_tx_ring(struct txgbe_ring *tx_ring);
+static void txgbe_napi_enable_all(struct txgbe_adapter *adapter);
+static void txgbe_napi_disable_all(struct txgbe_adapter *adapter);
+
+extern txgbe_dptype txgbe_ptype_lookup[256];
+
+static inline txgbe_dptype txgbe_decode_ptype(const u8 ptype)
+{
+	return txgbe_ptype_lookup[ptype];
+}
+
+static inline txgbe_dptype
+decode_rx_desc_ptype(const union txgbe_rx_desc *rx_desc)
+{
+	return txgbe_decode_ptype(TXGBE_RXD_PKTTYPE(rx_desc));
+}
+
+void txgbe_print_tx_hang_status(struct txgbe_adapter *adapter)
+{
+	int pos;
+	u32 value;
+	struct pci_dev *pdev = adapter->pdev;
+	u16 devctl2;
+
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+	if (!pos)
+		return;
+	pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &value);
+	e_info(probe, "AER Uncorrectable Error Status: 0x%08x\n", value);
+	pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &value);
+	e_info(probe, "AER Uncorrectable Error Mask: 0x%08x\n", value);
+	pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &value);
+	e_info(probe, "AER Uncorrectable Error Severity: 0x%08x\n", value);
+	pci_read_config_dword(pdev, pos + PCI_ERR_COR_STATUS, &value);
+	e_info(probe, "AER Correctable Error Status: 0x%08x\n", value);
+	pci_read_config_dword(pdev, pos + PCI_ERR_COR_MASK, &value);
+	e_info(probe, "AER Correctable Error Mask: 0x%08x\n", value);
+	pci_read_config_dword(pdev, pos + PCI_ERR_CAP, &value);
+	e_info(probe, "AER Capabilities and Control Register: 0x%08x\n", value);
+
+	pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &devctl2);
+	e_info(probe, "Device Control2 Register: 0x%04x\n", devctl2);
+
+	e_info(probe, "Tx flow control Status[TDB_TFCS 0xCE00]: 0x%x\n",
+		rd32(&adapter->hw, TXGBE_TDB_TFCS));
+	return;
+}
+
+static void txgbe_check_minimum_link(struct txgbe_adapter *adapter,
+				     int expected_gts)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct pci_dev *pdev;
+
+	/* Some devices are not connected over PCIe and thus do not negotiate
+	 * speed. These devices do not have valid bus info, and thus any report
+	 * we generate may not be correct.
+	 */
+	if (hw->bus.type == txgbe_bus_type_internal)
+		return;
+
+	pdev = adapter->pdev;
+	pcie_print_link_status(pdev);
+}
+
+/**
+ * txgbe_enumerate_functions - Get the number of ports this device has
+ * @adapter: adapter structure
+ *
+ * This function enumerates the phsyical functions co-located on a single slot,
+ * in order to determine how many ports a device has. This is most useful in
+ * determining the required GT/s of PCIe bandwidth necessary for optimal
+ * performance.
+ **/
+static inline int txgbe_enumerate_functions(struct txgbe_adapter *adapter)
+{
+	struct pci_dev *entry, *pdev = adapter->pdev;
+	int physfns = 0;
+
+	list_for_each_entry(entry, &pdev->bus->devices, bus_list) {
+#ifdef CONFIG_PCI_IOV
+		/* don't count virtual functions */
+		if (entry->is_virtfn)
+			continue;
+#endif
+
+		/* When the devices on the bus don't all match our device ID,
+		 * we can't reliably determine the correct number of
+		 * functions. This can occur if a function has been direct
+		 * attached to a virtual machine using VT-d, for example. In
+		 * this case, simply return -1 to indicate this.
+		 */
+		if ((entry->vendor != pdev->vendor) ||
+			(entry->device != pdev->device))
+			return -1;
+
+		physfns++;
+	}
+
+	return physfns;
+}
+
+void txgbe_service_event_schedule(struct txgbe_adapter *adapter)
+{
+	if (!test_bit(__TXGBE_DOWN, &adapter->state) &&
+	    !test_bit(__TXGBE_REMOVING, &adapter->state) &&
+	    !test_and_set_bit(__TXGBE_SERVICE_SCHED, &adapter->state))
+		queue_work(txgbe_wq, &adapter->service_task);
+}
+
+static void txgbe_service_event_complete(struct txgbe_adapter *adapter)
+{
+	BUG_ON(!test_bit(__TXGBE_SERVICE_SCHED, &adapter->state));
+
+	/* flush memory to make sure state is correct before next watchdog */
+	smp_mb__before_atomic();
+	clear_bit(__TXGBE_SERVICE_SCHED, &adapter->state);
+}
+
+static void txgbe_remove_adapter(struct txgbe_hw *hw)
+{
+	struct txgbe_adapter *adapter = hw->back;
+
+	if (!hw->hw_addr)
+		return;
+	hw->hw_addr = NULL;
+	e_dev_err("Adapter removed\n");
+	if (test_bit(__TXGBE_SERVICE_INITED, &adapter->state))
+		txgbe_service_event_schedule(adapter);
+}
+
+static void txgbe_check_remove(struct txgbe_hw *hw, u32 reg)
+{
+	u32 value;
+
+	/* The following check not only optimizes a bit by not
+	 * performing a read on the status register when the
+	 * register just read was a status register read that
+	 * returned TXGBE_FAILED_READ_REG. It also blocks any
+	 * potential recursion.
+	 */
+	if (reg == TXGBE_CFG_PORT_ST) {
+		txgbe_remove_adapter(hw);
+		return;
+	}
+	value = rd32(hw, TXGBE_CFG_PORT_ST);
+	if (value == TXGBE_FAILED_READ_REG)
+		txgbe_remove_adapter(hw);
+}
+
+static u32 txgbe_validate_register_read(struct txgbe_hw *hw, u32 reg, bool quiet)
+{
+	int i;
+	u32 value;
+	u8 __iomem *reg_addr;
+	struct txgbe_adapter *adapter = hw->back;
+
+	reg_addr = READ_ONCE(hw->hw_addr);
+	if (TXGBE_REMOVED(reg_addr))
+		return TXGBE_FAILED_READ_REG;
+	for (i = 0; i < TXGBE_DEAD_READ_RETRIES; ++i) {
+		value = txgbe_rd32(reg_addr + reg);
+		if (value != TXGBE_DEAD_READ_REG)
+			break;
+	}
+	if (quiet)
+		return value;
+	if (value == TXGBE_DEAD_READ_REG)
+		e_err(drv, "%s: register %x read unchanged\n", __func__, reg);
+	else
+		e_warn(hw, "%s: register %x read recovered after %d retries\n",
+			__func__, reg, i + 1);
+	return value;
+}
+
+/**
+ * txgbe_read_reg - Read from device register
+ * @hw: hw specific details
+ * @reg: offset of register to read
+ *
+ * Returns : value read or TXGBE_FAILED_READ_REG if removed
+ *
+ * This function is used to read device registers. It checks for device
+ * removal by confirming any read that returns all ones by checking the
+ * status register value for all ones. This function avoids reading from
+ * the hardware if a removal was previously detected in which case it
+ * returns TXGBE_FAILED_READ_REG (all ones).
+ */
+u32 txgbe_read_reg(struct txgbe_hw *hw, u32 reg, bool quiet)
+{
+	u32 value;
+	u8 __iomem *reg_addr;
+
+	reg_addr = READ_ONCE(hw->hw_addr);
+	if (TXGBE_REMOVED(reg_addr))
+		return TXGBE_FAILED_READ_REG;
+	value = txgbe_rd32(reg_addr + reg);
+	if (unlikely(value == TXGBE_FAILED_READ_REG))
+		txgbe_check_remove(hw, reg);
+	if (unlikely(value == TXGBE_DEAD_READ_REG))
+		value = txgbe_validate_register_read(hw, reg, quiet);
+	return value;
+}
+
+static void txgbe_release_hw_control(struct txgbe_adapter *adapter)
+{
+	/* Let firmware take over control of h/w */
+	wr32m(&adapter->hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_DRV_LOAD, 0);
+}
+
+static void txgbe_get_hw_control(struct txgbe_adapter *adapter)
+{
+	/* Let firmware know the driver has taken over */
+	wr32m(&adapter->hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_DRV_LOAD, TXGBE_CFG_PORT_CTL_DRV_LOAD);
+}
+
+/**
+ * txgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
+ * @adapter: pointer to adapter struct
+ * @direction: 0 for Rx, 1 for Tx, -1 for other causes
+ * @queue: queue to map the corresponding interrupt to
+ * @msix_vector: the vector to map to the corresponding queue
+ *
+ **/
+static void txgbe_set_ivar(struct txgbe_adapter *adapter, s8 direction,
+	u16 queue, u16 msix_vector)
+{
+	u32 ivar, index;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (direction == -1) {
+		/* other causes */
+		msix_vector |= TXGBE_PX_IVAR_ALLOC_VAL;
+		index = 0; 
+		ivar = rd32(&adapter->hw, TXGBE_PX_MISC_IVAR);
+		ivar &= ~(0xFF << index);
+		ivar |= (msix_vector << index);
+		wr32(&adapter->hw, TXGBE_PX_MISC_IVAR, ivar);
+	} else {
+		/* tx or rx causes */
+		msix_vector |= TXGBE_PX_IVAR_ALLOC_VAL;
+		index = ((16 * (queue & 1)) + (8 * direction));
+		ivar = rd32(hw, TXGBE_PX_IVAR(queue >> 1));
+		ivar &= ~(0xFF << index);
+		ivar |= (msix_vector << index);
+		wr32(hw, TXGBE_PX_IVAR(queue >> 1), ivar);
+	}
+}
+
+void txgbe_unmap_and_free_tx_resource(struct txgbe_ring *ring,
+				      struct txgbe_tx_buffer *tx_buffer)
+{
+	if (tx_buffer->skb) {
+		dev_kfree_skb_any(tx_buffer->skb);
+		if (dma_unmap_len(tx_buffer, len))
+			dma_unmap_single(ring->dev,
+					 dma_unmap_addr(tx_buffer, dma),
+					 dma_unmap_len(tx_buffer, len),
+					 DMA_TO_DEVICE);
+	} else if (dma_unmap_len(tx_buffer, len)) {
+		dma_unmap_page(ring->dev,
+			       dma_unmap_addr(tx_buffer, dma),
+			       dma_unmap_len(tx_buffer, len),
+			       DMA_TO_DEVICE);
+	}
+	tx_buffer->next_to_watch = NULL;
+	tx_buffer->skb = NULL;
+	dma_unmap_len_set(tx_buffer, len, 0);
+	/* tx_buffer must be completely set up in the transmit path */
+}
+
+static void txgbe_update_xoff_rx_lfc(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_hw_stats *hwstats = &adapter->stats;
+	int i;
+	u32 data;
+
+	if ((hw->fc.current_mode != txgbe_fc_full) &&
+	    (hw->fc.current_mode != txgbe_fc_rx_pause))
+		return;
+
+	data = rd32(hw, TXGBE_MAC_LXOFFRXC);
+
+	hwstats->lxoffrxc += data;
+
+	/* refill credits (no tx hang) if we received xoff */
+	if (!data)
+		return;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		clear_bit(__TXGBE_HANG_CHECK_ARMED,
+			  &adapter->tx_ring[i]->state);
+}
+
+static void txgbe_update_xoff_received(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_hw_stats *hwstats = &adapter->stats;
+	u32 xoff[8] = {0};
+	int tc;
+	int i;
+	bool pfc_en = adapter->dcb_cfg.pfc_mode_enable;
+
+#ifdef HAVE_DCBNL_IEEE
+	if (adapter->txgbe_ieee_pfc)
+		pfc_en |= !!(adapter->txgbe_ieee_pfc->pfc_en);
+
+#endif
+	if (!(adapter->flags & TXGBE_FLAG_DCB_ENABLED) || !pfc_en) {
+		txgbe_update_xoff_rx_lfc(adapter);
+		return;
+	}
+
+	/* update stats for each tc, only valid with PFC enabled */
+	for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) {
+		u32 pxoffrxc;
+		wr32m(hw, TXGBE_MMC_CONTROL, TXGBE_MMC_CONTROL_UP, i<<16);
+		pxoffrxc = rd32(hw, TXGBE_MAC_PXOFFRXC);
+		hwstats->pxoffrxc[i] += pxoffrxc;
+		/* Get the TC for given UP */
+		tc = netdev_get_prio_tc_map(adapter->netdev, i);
+		xoff[tc] += pxoffrxc;
+	}
+
+	/* disarm tx queues that have received xoff frames */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct txgbe_ring *tx_ring = adapter->tx_ring[i];
+
+		tc = tx_ring->dcb_tc;
+		if ((tc <= 7) && (xoff[tc]))
+			clear_bit(__TXGBE_HANG_CHECK_ARMED, &tx_ring->state);
+	}
+}
+
+static u64 txgbe_get_tx_completed(struct txgbe_ring *ring)
+{
+	return ring->stats.packets;
+}
+
+static u64 txgbe_get_tx_pending(struct txgbe_ring *ring)
+{
+	struct txgbe_adapter *adapter;
+	struct txgbe_hw *hw;
+	u32 head, tail;
+
+	if (ring->accel)
+		adapter = ring->accel->adapter;
+	else
+		adapter = ring->q_vector->adapter;
+
+	hw = &adapter->hw;
+	head = rd32(hw, TXGBE_PX_TR_RP(ring->reg_idx));
+	tail = rd32(hw, TXGBE_PX_TR_WP(ring->reg_idx));
+
+	return ((head <= tail) ? tail : tail + ring->count) - head;
+}
+
+static inline bool txgbe_check_tx_hang(struct txgbe_ring *tx_ring)
+{
+	u64 tx_done = txgbe_get_tx_completed(tx_ring);
+	u64 tx_done_old = tx_ring->tx_stats.tx_done_old;
+	u64 tx_pending = txgbe_get_tx_pending(tx_ring);
+
+	clear_check_for_tx_hang(tx_ring);
+
+	/*
+	 * Check for a hung queue, but be thorough. This verifies
+	 * that a transmit has been completed since the previous
+	 * check AND there is at least one packet pending. The
+	 * ARMED bit is set to indicate a potential hang. The
+	 * bit is cleared if a pause frame is received to remove
+	 * false hang detection due to PFC or 802.3x frames. By
+	 * requiring this to fail twice we avoid races with
+	 * pfc clearing the ARMED bit and conditions where we
+	 * run the check_tx_hang logic with a transmit completion
+	 * pending but without time to complete it yet.
+	 */
+	if (tx_done_old == tx_done && tx_pending)
+		/* make sure it is true for two checks in a row */
+		return test_and_set_bit(__TXGBE_HANG_CHECK_ARMED,
+					&tx_ring->state);
+	/* update completed stats and continue */
+	tx_ring->tx_stats.tx_done_old = tx_done;
+	/* reset the countdown */
+	clear_bit(__TXGBE_HANG_CHECK_ARMED, &tx_ring->state);
+
+	return false;
+}
+
+/**
+ * txgbe_tx_timeout_reset - initiate reset due to Tx timeout
+ * @adapter: driver private struct
+ **/
+static void txgbe_tx_timeout_reset(struct txgbe_adapter *adapter)
+{
+	if (!test_bit(__TXGBE_DOWN, &adapter->state)) {
+		adapter->flags2 |= TXGBE_FLAG2_PF_RESET_REQUESTED;
+		e_warn(drv, "initiating reset due to tx timeout\n");
+		txgbe_service_event_schedule(adapter);
+	}
+}
+
+/**
+ * txgbe_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+#ifdef HAVE_TX_TIMEOUT_TXQUEUE
+static void txgbe_tx_timeout(struct net_device *netdev, unsigned int txqueue)
+#else
+static void txgbe_tx_timeout(struct net_device *netdev)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	bool real_tx_hang = false;
+	int i;
+	u16 value = 0;
+	u32 value2 = 0, value3 = 0;
+	u32 head, tail;
+	u16 vid = 0;
+
+#define TX_TIMEO_LIMIT 16000
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct txgbe_ring *tx_ring = adapter->tx_ring[i];
+		if (check_for_tx_hang(tx_ring) && txgbe_check_tx_hang(tx_ring))
+			real_tx_hang = true;
+	}
+
+	pci_read_config_word(adapter->pdev, PCI_VENDOR_ID, &vid);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "pci vendor id is 0x%x\n", vid);
+
+	pci_read_config_word(adapter->pdev, PCI_COMMAND, &value);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "pci command reg is 0x%x.\n", value);
+
+	value2 = rd32(&adapter->hw,0x10000);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "reg 0x10000 value is 0x%08x\n", value2);
+	value2 = rd32(&adapter->hw,0x180d0);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "reg 0x180d0 value is 0x%08x\n", value2);
+	value2 = rd32(&adapter->hw,0x180d4);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "reg 0x180d4 value is 0x%08x\n", value2);
+	value2 = rd32(&adapter->hw,0x180d8);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "reg 0x180d8 value is 0x%08x\n", value2);
+	value2 = rd32(&adapter->hw,0x180dc);
+	ERROR_REPORT1(TXGBE_ERROR_POLLING, "reg 0x180dc value is 0x%08x\n", value2);
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		head = rd32(&adapter->hw, TXGBE_PX_TR_RP(adapter->tx_ring[i]->reg_idx));
+		tail = rd32(&adapter->hw, TXGBE_PX_TR_WP(adapter->tx_ring[i]->reg_idx));
+
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			"tx ring %d next_to_use is %d, next_to_clean is %d\n", 
+			i, adapter->tx_ring[i]->next_to_use, adapter->tx_ring[i]->next_to_clean);
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			"tx ring %d hw rp is 0x%x, wp is 0x%x\n", i, head, tail);
+	}
+
+	value2= rd32(&adapter->hw, TXGBE_PX_IMS(0));
+	value3= rd32(&adapter->hw, TXGBE_PX_IMS(1));
+	ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			"PX_IMS0 value is 0x%08x, PX_IMS1 value is 0x%08x\n", value2, value3);
+
+	if (value2 || value3) {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING, "clear interrupt mask.\n");
+		wr32(&adapter->hw, TXGBE_PX_ICS(0), value2);
+		wr32(&adapter->hw, TXGBE_PX_IMC(0), value2);
+		wr32(&adapter->hw, TXGBE_PX_ICS(1), value3);
+		wr32(&adapter->hw, TXGBE_PX_IMC(1), value3);
+	}
+
+#ifdef TXGBE_RECOVER_CHECK
+	if (vid == TXGBE_FAILED_READ_CFG_WORD) {
+#endif
+		if (adapter->hw.bus.lan_id == 0) {
+			adapter->flags2 |= TXGBE_FLAG2_PCIE_NEED_RECOVER;
+			txgbe_service_event_schedule(adapter);
+		} else
+			wr32(&adapter->hw, TXGBE_MIS_PF_SM, 1);
+#ifdef TXGBE_RECOVER_CHECK
+	} else {
+		txgbe_print_tx_hang_status(adapter);
+		txgbe_tx_timeout_reset(adapter);
+	}
+#endif
+}
+
+/**
+ * txgbe_clean_tx_irq - Reclaim resources after transmit completes
+ * @q_vector: structure containing interrupt and ring information
+ * @tx_ring: tx ring to clean
+ **/
+static bool txgbe_clean_tx_irq(struct txgbe_q_vector *q_vector,
+			       struct txgbe_ring *tx_ring)
+{
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	struct txgbe_tx_buffer *tx_buffer;
+	union txgbe_tx_desc *tx_desc;
+	unsigned int total_bytes = 0, total_packets = 0;
+	unsigned int budget = q_vector->tx.work_limit;
+	unsigned int i = tx_ring->next_to_clean;
+	u16 vid = 0;
+
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return true;
+
+	tx_buffer = &tx_ring->tx_buffer_info[i];
+	tx_desc = TXGBE_TX_DESC(tx_ring, i);
+	i -= tx_ring->count;
+
+	do {
+		union txgbe_tx_desc *eop_desc = tx_buffer->next_to_watch;
+
+		/* if next_to_watch is not set then there is no work pending */
+		if (!eop_desc)
+			break;
+
+		/* prevent any other reads prior to eop_desc */
+		smp_rmb();
+
+		/* if DD is not set pending work has not been completed */
+		if (!(eop_desc->wb.status & cpu_to_le32(TXGBE_TXD_STAT_DD)))
+			break;
+
+		/* clear next_to_watch to prevent false hangs */
+		tx_buffer->next_to_watch = NULL;
+
+		/* update the statistics for this packet */
+		total_bytes += tx_buffer->bytecount;
+		total_packets += tx_buffer->gso_segs;
+
+		/* free the skb */
+		dev_consume_skb_any(tx_buffer->skb);
+
+		/* unmap skb header data */
+		dma_unmap_single(tx_ring->dev,
+				 dma_unmap_addr(tx_buffer, dma),
+				 dma_unmap_len(tx_buffer, len),
+				 DMA_TO_DEVICE);
+
+		/* clear tx_buffer data */
+		tx_buffer->skb = NULL;
+		dma_unmap_len_set(tx_buffer, len, 0);
+
+		/* unmap remaining buffers */
+		while (tx_desc != eop_desc) {
+			tx_buffer++;
+			tx_desc++;
+			i++;
+			if (unlikely(!i)) {
+				i -= tx_ring->count;
+				tx_buffer = tx_ring->tx_buffer_info;
+				tx_desc = TXGBE_TX_DESC(tx_ring, 0);
+			}
+
+			/* unmap any remaining paged data */
+			if (dma_unmap_len(tx_buffer, len)) {
+				dma_unmap_page(tx_ring->dev,
+					       dma_unmap_addr(tx_buffer, dma),
+					       dma_unmap_len(tx_buffer, len),
+					       DMA_TO_DEVICE);
+				dma_unmap_len_set(tx_buffer, len, 0);
+			}
+		}
+
+		/* move us one more past the eop_desc for start of next pkt */
+		tx_buffer++;
+		tx_desc++;
+		i++;
+		if (unlikely(!i)) {
+			i -= tx_ring->count;
+			tx_buffer = tx_ring->tx_buffer_info;
+			tx_desc = TXGBE_TX_DESC(tx_ring, 0);
+		}
+
+		/* issue prefetch for next Tx descriptor */
+		prefetch(tx_desc);
+
+		/* update budget accounting */
+		budget--;
+	} while (likely(budget));
+
+	i += tx_ring->count;
+	tx_ring->next_to_clean = i;
+	u64_stats_update_begin(&tx_ring->syncp);
+	tx_ring->stats.bytes += total_bytes;
+	tx_ring->stats.packets += total_packets;
+	u64_stats_update_end(&tx_ring->syncp);
+	q_vector->tx.total_bytes += total_bytes;
+	q_vector->tx.total_packets += total_packets;
+
+	if (check_for_tx_hang(tx_ring) && txgbe_check_tx_hang(tx_ring)) {
+	/* schedule immediate reset if we believe we hung */
+		struct txgbe_hw *hw = &adapter->hw;
+//		u16 value = 0;
+
+		e_err(drv, "Detected Tx Unit Hang\n"
+			"  Tx Queue             <%d>\n"
+			"  TDH, TDT             <%x>, <%x>\n"
+			"  next_to_use          <%x>\n"
+			"  next_to_clean        <%x>\n"
+			"tx_buffer_info[next_to_clean]\n"
+			"  time_stamp           <%lx>\n"
+			"  jiffies              <%lx>\n",
+			tx_ring->queue_index,
+			rd32(hw, TXGBE_PX_TR_RP(tx_ring->reg_idx)),
+			rd32(hw, TXGBE_PX_TR_WP(tx_ring->reg_idx)),
+			tx_ring->next_to_use, i,
+			tx_ring->tx_buffer_info[i].time_stamp, jiffies);
+
+		pci_read_config_word(adapter->pdev, PCI_VENDOR_ID, &vid);
+		if (vid == TXGBE_FAILED_READ_CFG_WORD) {
+			e_info(hw, "pcie link has been lost.\n");
+		}
+
+		netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+		e_info(probe,
+		       "tx hang %d detected on queue %d, resetting adapter\n",
+			adapter->tx_timeout_count + 1, tx_ring->queue_index);
+
+#ifdef TXGBE_RECOVER_CHECK
+		if (vid == TXGBE_FAILED_READ_CFG_WORD) {
+#endif
+			/* schedule immediate reset if we believe we hung */
+			if (adapter->hw.bus.lan_id == 0) {
+				adapter->flags2 |= TXGBE_FLAG2_PCIE_NEED_RECOVER;
+				txgbe_service_event_schedule(adapter);
+			} else
+				wr32(&adapter->hw, TXGBE_MIS_PF_SM, 1);
+#ifdef TXGBE_RECOVER_CHECK
+		} else {
+			txgbe_print_tx_hang_status(adapter);
+			txgbe_tx_timeout_reset(adapter);
+		}
+#endif
+
+		/* the adapter is about to reset, no point in enabling stuff */
+		return true;
+	}
+
+	netdev_tx_completed_queue(txring_txq(tx_ring),
+				  total_packets, total_bytes);
+
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+	if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
+		     (txgbe_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) {
+		/* Make sure that anybody stopping the queue after this
+		 * sees the new next_to_clean.
+		 */
+		smp_mb();
+#ifdef HAVE_TX_MQ
+		if (__netif_subqueue_stopped(tx_ring->netdev,
+		    tx_ring->queue_index)
+		    && !test_bit(__TXGBE_DOWN, &adapter->state)) {
+			netif_wake_subqueue(tx_ring->netdev,
+					    tx_ring->queue_index);
+			++tx_ring->tx_stats.restart_queue;
+		}
+#else
+		if (netif_queue_stopped(tx_ring->netdev) &&
+		    !test_bit(__TXGBE_DOWN, &adapter->state)) {
+			netif_wake_queue(tx_ring->netdev);
+			++tx_ring->tx_stats.restart_queue;
+		}
+#endif
+	}
+
+	return !!budget;
+}
+
+
+#ifdef NETIF_F_RXHASH
+#define TXGBE_RSS_L4_TYPES_MASK \
+	((1ul << TXGBE_RXD_RSSTYPE_IPV4_TCP) | \
+	 (1ul << TXGBE_RXD_RSSTYPE_IPV4_UDP) | \
+	 (1ul << TXGBE_RXD_RSSTYPE_IPV4_SCTP) | \
+	 (1ul << TXGBE_RXD_RSSTYPE_IPV6_TCP) | \
+	 (1ul << TXGBE_RXD_RSSTYPE_IPV6_UDP) | \
+	 (1ul << TXGBE_RXD_RSSTYPE_IPV6_SCTP))
+
+static inline void txgbe_rx_hash(struct txgbe_ring *ring,
+				 union txgbe_rx_desc *rx_desc,
+				 struct sk_buff *skb)
+{
+	u16 rss_type;
+
+	if (!(ring->netdev->features & NETIF_F_RXHASH))
+		return;
+
+	rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) &
+		   TXGBE_RXD_RSSTYPE_MASK;
+
+	if (!rss_type)
+		return;
+
+	skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+		     (TXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ?
+		     PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
+}
+#endif /* NETIF_F_RXHASH */
+
+#if IS_ENABLED(CONFIG_FCOE)
+/**
+ * txgbe_rx_is_fcoe - check the rx desc for incoming pkt type
+ * @ring: structure containing ring specific data
+ * @rx_desc: advanced rx descriptor
+ *
+ * Returns : true if it is FCoE pkt
+ */
+static inline bool txgbe_rx_is_fcoe(struct txgbe_ring *ring,
+				    union txgbe_rx_desc *rx_desc)
+{
+	u8 ptype = TXGBE_RXD_PKTTYPE(rx_desc);
+
+	return test_bit(__TXGBE_RX_FCOE, &ring->state) &&
+	       ptype >= TXGBE_PTYPE_L2_FCOE &&
+	       ptype <= TXGBE_PTYPE_L2_FCOE_VFT_FCOTHER;
+}
+#endif /* CONFIG_FCOE */
+
+/**
+ * txgbe_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @ring: structure containing ring specific data
+ * @rx_desc: current Rx descriptor being processed
+ * @skb: skb currently being received and modified
+ **/
+static inline void txgbe_rx_checksum(struct txgbe_ring *ring,
+				     union txgbe_rx_desc *rx_desc,
+				     struct sk_buff *skb)
+{
+	txgbe_dptype dptype = decode_rx_desc_ptype(rx_desc);
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	skb_checksum_none_assert(skb);
+
+	/* Rx csum disabled */
+	if (!(ring->netdev->features & NETIF_F_RXCSUM))
+		return;
+
+	/* if IPv4 header checksum error */
+	if ((txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_IPCS) &&
+		txgbe_test_staterr(rx_desc, TXGBE_RXD_ERR_IPE)) ||
+		(txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_OUTERIPCS) &&
+		txgbe_test_staterr(rx_desc, TXGBE_RXD_ERR_OUTERIPER))) {
+		ring->rx_stats.csum_err++;
+		return;
+	}
+
+	/* L4 checksum offload flag must set for the below code to work */
+	if (!txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_L4CS))
+		return;
+
+	/*likely incorrect csum if IPv6 Dest Header found */
+	if (dptype.prot != TXGBE_DEC_PTYPE_PROT_SCTP && TXGBE_RXD_IPV6EX(rx_desc))
+		return;
+
+	/* if L4 checksum error */
+	if (txgbe_test_staterr(rx_desc, TXGBE_RXD_ERR_TCPE)) {
+		ring->rx_stats.csum_err++;
+		return;
+	}
+	/* If there is an outer header present that might contain a checksum
+	 * we need to bump the checksum level by 1 to reflect the fact that
+	 * we are indicating we validated the inner checksum.
+	*/
+	if (dptype.etype >= TXGBE_DEC_PTYPE_ETYPE_IG) {
+	#ifdef HAVE_SKBUFF_CSUM_LEVEL
+		skb->csum_level = 1;
+	#endif /* FIXME :does skb->csum_level skb->encapsulation can both set ? */
+	#ifdef HAVE_VXLAN_CHECKS
+		skb->encapsulation = 1;
+	#endif
+	}
+
+	/* It must be a TCP or UDP or SCTP packet with a valid checksum */
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	ring->rx_stats.csum_good_cnt++;
+}
+
+static bool txgbe_alloc_mapped_skb(struct txgbe_ring *rx_ring,
+			struct txgbe_rx_buffer *bi)
+{
+	struct sk_buff *skb = bi->skb;
+	dma_addr_t dma = bi->dma;
+
+	if (unlikely(dma))
+		return true;
+
+	if (likely(!skb)) {
+		skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+						rx_ring->rx_buf_len);
+		if (unlikely(!skb)) {
+			rx_ring->rx_stats.alloc_rx_buff_failed++;
+			return false;
+		}
+
+		bi->skb = skb;
+
+	}
+
+	dma = dma_map_single(rx_ring->dev, skb->data,
+			     rx_ring->rx_buf_len, DMA_FROM_DEVICE);
+
+	/*
+	 * if mapping failed free memory back to system since
+	 * there isn't much point in holding memory we can't use
+	 */
+	if (dma_mapping_error(rx_ring->dev, dma)) {
+		dev_kfree_skb_any(skb);
+		bi->skb = NULL;
+
+		rx_ring->rx_stats.alloc_rx_buff_failed++;
+		return false;
+	}
+
+	bi->dma = dma;
+	return true;
+}
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+static bool txgbe_alloc_mapped_page(struct txgbe_ring *rx_ring,
+				    struct txgbe_rx_buffer *bi)
+{
+	struct page *page = bi->page;
+	dma_addr_t dma;
+
+	/* since we are recycling buffers we should seldom need to alloc */
+	if (likely(page))
+		return true;
+
+	/* alloc new page for storage */
+	page = dev_alloc_pages(txgbe_rx_pg_order(rx_ring));
+	if (unlikely(!page)) {
+		rx_ring->rx_stats.alloc_rx_page_failed++;
+		return false;
+	}
+
+	/* map page for use */
+	dma = dma_map_page(rx_ring->dev, page, 0,
+			   txgbe_rx_pg_size(rx_ring), DMA_FROM_DEVICE);
+
+	/*
+	 * if mapping failed free memory back to system since
+	 * there isn't much point in holding memory we can't use
+	 */
+	if (dma_mapping_error(rx_ring->dev, dma)) {
+		__free_pages(page, txgbe_rx_pg_order(rx_ring));
+
+		rx_ring->rx_stats.alloc_rx_page_failed++;
+		return false;
+	}
+
+	bi->page_dma = dma;
+	bi->page = page;
+	bi->page_offset = 0;
+
+	return true;
+}
+#endif
+
+/**
+ * txgbe_alloc_rx_buffers - Replace used receive buffers
+ * @rx_ring: ring to place buffers on
+ * @cleaned_count: number of buffers to replace
+ **/
+void txgbe_alloc_rx_buffers(struct txgbe_ring *rx_ring, u16 cleaned_count)
+{
+	union txgbe_rx_desc *rx_desc;
+	struct txgbe_rx_buffer *bi;
+	u16 i = rx_ring->next_to_use;
+
+	/* nothing to do */
+	if (!cleaned_count)
+		return;
+
+	rx_desc = TXGBE_RX_DESC(rx_ring, i);
+	bi = &rx_ring->rx_buffer_info[i];
+	i -= rx_ring->count;
+
+	do {
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		if (!txgbe_alloc_mapped_skb(rx_ring, bi))
+			break;
+		rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+
+#else
+		if (ring_is_hs_enabled(rx_ring)) {
+			if (!txgbe_alloc_mapped_skb(rx_ring, bi))
+				break;
+			rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
+		}
+
+		if (!txgbe_alloc_mapped_page(rx_ring, bi))
+			break;
+		rx_desc->read.pkt_addr =
+			cpu_to_le64(bi->page_dma + bi->page_offset);
+#endif
+
+		rx_desc++;
+		bi++;
+		i++;
+		if (unlikely(!i)) {
+			rx_desc = TXGBE_RX_DESC(rx_ring, 0);
+			bi = rx_ring->rx_buffer_info;
+			i -= rx_ring->count;
+		}
+
+		/* clear the status bits for the next_to_use descriptor */
+		rx_desc->wb.upper.status_error = 0;
+
+		cleaned_count--;
+	} while (cleaned_count);
+
+	i += rx_ring->count;
+
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		/* update next to alloc since we have filled the ring */
+		rx_ring->next_to_alloc = i;
+#endif
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64).
+		 */
+		wmb();
+		writel(i, rx_ring->tail);
+	}
+}
+
+static inline u16 txgbe_get_hlen(struct txgbe_ring *rx_ring,
+				 union txgbe_rx_desc *rx_desc)
+{
+	__le16 hdr_info = rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
+	u16 hlen = le16_to_cpu(hdr_info) & TXGBE_RXD_HDRBUFLEN_MASK;
+
+	UNREFERENCED_PARAMETER(rx_ring);
+
+	if (hlen > (TXGBE_RX_HDR_SIZE << TXGBE_RXD_HDRBUFLEN_SHIFT))
+		hlen = 0;
+	else
+		hlen >>= TXGBE_RXD_HDRBUFLEN_SHIFT;
+
+	return hlen;
+}
+
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+/**
+ * txgbe_merge_active_tail - merge active tail into lro skb
+ * @tail: pointer to active tail in frag_list
+ *
+ * This function merges the length and data of an active tail into the
+ * skb containing the frag_list.  It resets the tail's pointer to the head,
+ * but it leaves the heads pointer to tail intact.
+ **/
+static inline struct sk_buff *txgbe_merge_active_tail(struct sk_buff *tail)
+{
+	struct sk_buff *head = TXGBE_CB(tail)->head;
+
+	if (!head)
+		return tail;
+
+	head->len += tail->len;
+	head->data_len += tail->len;
+	head->truesize += tail->truesize;
+
+	TXGBE_CB(tail)->head = NULL;
+
+	return head;
+}
+
+/**
+ * txgbe_add_active_tail - adds an active tail into the skb frag_list
+ * @head: pointer to the start of the skb
+ * @tail: pointer to active tail to add to frag_list
+ *
+ * This function adds an active tail to the end of the frag list.  This tail
+ * will still be receiving data so we cannot yet ad it's stats to the main
+ * skb.  That is done via txgbe_merge_active_tail.
+ **/
+static inline void txgbe_add_active_tail(struct sk_buff *head,
+					 struct sk_buff *tail)
+{
+	struct sk_buff *old_tail = TXGBE_CB(head)->tail;
+
+	if (old_tail) {
+		txgbe_merge_active_tail(old_tail);
+		old_tail->next = tail;
+	} else {
+		skb_shinfo(head)->frag_list = tail;
+	}
+
+	TXGBE_CB(tail)->head = head;
+	TXGBE_CB(head)->tail = tail;
+}
+
+/**
+ * txgbe_close_active_frag_list - cleanup pointers on a frag_list skb
+ * @head: pointer to head of an active frag list
+ *
+ * This function will clear the frag_tail_tracker pointer on an active
+ * frag_list and returns true if the pointer was actually set
+ **/
+static inline bool txgbe_close_active_frag_list(struct sk_buff *head)
+{
+	struct sk_buff *tail = TXGBE_CB(head)->tail;
+
+	if (!tail)
+		return false;
+
+	txgbe_merge_active_tail(tail);
+
+	TXGBE_CB(head)->tail = NULL;
+
+	return true;
+}
+
+#endif
+#ifdef HAVE_VLAN_RX_REGISTER
+/**
+ * txgbe_receive_skb - Send a completed packet up the stack
+ * @q_vector: structure containing interrupt and ring information
+ * @skb: packet to send up
+ **/
+static void txgbe_receive_skb(struct txgbe_q_vector *q_vector,
+			      struct sk_buff *skb)
+{
+	u16 vlan_tag = TXGBE_CB(skb)->vid;
+
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	if (vlan_tag & VLAN_VID_MASK) {
+		/* by placing vlgrp at start of structure we can alias it */
+		struct vlan_group **vlgrp = netdev_priv(skb->dev);
+		if (!*vlgrp)
+			dev_kfree_skb_any(skb);
+		else if (q_vector->netpoll_rx)
+			vlan_hwaccel_rx(skb, *vlgrp, vlan_tag);
+		else
+			vlan_gro_receive(&q_vector->napi,
+					 *vlgrp, vlan_tag, skb);
+	} else {
+#endif
+		if (q_vector->netpoll_rx)
+			netif_rx(skb);
+		else
+			napi_gro_receive(&q_vector->napi, skb);
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	}
+#endif
+}
+
+#endif /* HAVE_VLAN_RX_REGISTER */
+#ifndef TXGBE_NO_LRO
+/**
+ * txgbe_can_lro - returns true if packet is TCP/IPV4 and LRO is enabled
+ * @rx_ring: structure containing ring specific data
+ * @rx_desc: pointer to the rx descriptor
+ * @skb: pointer to the skb to be merged
+ *
+ **/
+static inline bool txgbe_can_lro(struct txgbe_ring *rx_ring,
+				 union txgbe_rx_desc *rx_desc,
+				 struct sk_buff *skb)
+{
+	struct iphdr *iph = (struct iphdr *)skb->data;
+	txgbe_dptype dec_ptype = decode_rx_desc_ptype(rx_desc);
+
+	/* verify hardware indicates this is IPv4/TCP */
+	if (!dec_ptype.known ||
+		TXGBE_DEC_PTYPE_ETYPE_NONE != dec_ptype.etype ||
+		TXGBE_DEC_PTYPE_IP_IPV4 != dec_ptype.ip ||
+		TXGBE_DEC_PTYPE_PROT_TCP != dec_ptype.prot)
+		return false;
+
+	/* .. and RSC is not already enabled */
+	if (ring_is_rsc_enabled(rx_ring))
+		return false;
+
+	/* .. and LRO is enabled */
+	if (!(rx_ring->netdev->features & NETIF_F_LRO))
+		return false;
+
+	/* .. and we are not in promiscuous mode */
+	if (rx_ring->netdev->flags & IFF_PROMISC)
+		return false;
+
+	/* .. and the header is large enough for us to read IP/TCP fields */
+	if (!pskb_may_pull(skb, sizeof(struct txgbe_lrohdr)))
+		return false;
+
+	/* .. and there are no VLANs on packet */
+	if (skb->protocol != __constant_htons(ETH_P_IP))
+		return false;
+
+	/* .. and we are version 4 with no options */
+	if (*(u8 *)iph != 0x45)
+		return false;
+
+	/* .. and the packet is not fragmented */
+	if (iph->frag_off & htons(IP_MF | IP_OFFSET))
+		return false;
+
+	/* .. and that next header is TCP */
+	if (iph->protocol != IPPROTO_TCP)
+		return false;
+
+	return true;
+}
+
+static inline struct txgbe_lrohdr *txgbe_lro_hdr(struct sk_buff *skb)
+{
+	return (struct txgbe_lrohdr *)skb->data;
+}
+
+/**
+ * txgbe_lro_flush - Indicate packets to upper layer.
+ *
+ * Update IP and TCP header part of head skb if more than one
+ * skb's chained and indicate packets to upper layer.
+ **/
+static void txgbe_lro_flush(struct txgbe_q_vector *q_vector,
+			    struct sk_buff *skb)
+{
+	struct txgbe_lro_list *lrolist = &q_vector->lrolist;
+
+	__skb_unlink(skb, &lrolist->active);
+
+	if (TXGBE_CB(skb)->append_cnt) {
+		struct txgbe_lrohdr *lroh = txgbe_lro_hdr(skb);
+
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		/* close any active lro contexts */
+		txgbe_close_active_frag_list(skb);
+
+#endif
+		/* incorporate ip header and re-calculate checksum */
+		lroh->iph.tot_len = ntohs(skb->len);
+		lroh->iph.check = 0;
+
+		/* header length is 5 since we know no options exist */
+		lroh->iph.check = ip_fast_csum((u8 *)lroh, 5);
+
+		/* clear TCP checksum to indicate we are an LRO frame */
+		lroh->th.check = 0;
+
+		/* incorporate latest timestamp into the tcp header */
+		if (TXGBE_CB(skb)->tsecr) {
+			lroh->ts[2] = TXGBE_CB(skb)->tsecr;
+			lroh->ts[1] = htonl(TXGBE_CB(skb)->tsval);
+		}
+#ifdef NETIF_F_GSO
+#ifdef NAPI_GRO_CB
+		NAPI_GRO_CB(skb)->data_offset = 0;
+#endif
+		skb_shinfo(skb)->gso_size = TXGBE_CB(skb)->mss;
+		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+#endif
+	}
+
+#ifdef HAVE_VLAN_RX_REGISTER
+	txgbe_receive_skb(q_vector, skb);
+#else
+	napi_gro_receive(&q_vector->napi, skb);
+#endif
+	lrolist->stats.flushed++;
+}
+
+static void txgbe_lro_flush_all(struct txgbe_q_vector *q_vector)
+{
+	struct txgbe_lro_list *lrolist = &q_vector->lrolist;
+	struct sk_buff *skb, *tmp;
+
+	skb_queue_reverse_walk_safe(&lrolist->active, skb, tmp)
+		txgbe_lro_flush(q_vector, skb);
+}
+
+/*
+ * txgbe_lro_header_ok - Main LRO function.
+ **/
+static void txgbe_lro_header_ok(struct sk_buff *skb)
+{
+	struct txgbe_lrohdr *lroh = txgbe_lro_hdr(skb);
+	u16 opt_bytes, data_len;
+
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	TXGBE_CB(skb)->tail = NULL;
+#endif
+	TXGBE_CB(skb)->tsecr = 0;
+	TXGBE_CB(skb)->append_cnt = 0;
+	TXGBE_CB(skb)->mss = 0;
+
+	/* ensure that the checksum is valid */
+	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+		return;
+
+	/* If we see CE codepoint in IP header, packet is not mergeable */
+	if (INET_ECN_is_ce(ipv4_get_dsfield(&lroh->iph)))
+		return;
+
+	/* ensure no bits set besides ack or psh */
+	if (lroh->th.fin || lroh->th.syn || lroh->th.rst ||
+	    lroh->th.urg || lroh->th.ece || lroh->th.cwr ||
+	    !lroh->th.ack)
+		return;
+
+	/* store the total packet length */
+	data_len = ntohs(lroh->iph.tot_len);
+
+	/* remove any padding from the end of the skb */
+	__pskb_trim(skb, data_len);
+
+	/* remove header length from data length */
+	data_len -= sizeof(struct txgbe_lrohdr);
+
+	/*
+	 * check for timestamps. Since the only option we handle are timestamps,
+	 * we only have to handle the simple case of aligned timestamps
+	 */
+	opt_bytes = (lroh->th.doff << 2) - sizeof(struct tcphdr);
+	if (opt_bytes != 0) {
+		if ((opt_bytes != TCPOLEN_TSTAMP_ALIGNED) ||
+		    !pskb_may_pull(skb, sizeof(struct txgbe_lrohdr) +
+					TCPOLEN_TSTAMP_ALIGNED) ||
+		    (lroh->ts[0] != htonl((TCPOPT_NOP << 24) |
+					     (TCPOPT_NOP << 16) |
+					     (TCPOPT_TIMESTAMP << 8) |
+					      TCPOLEN_TIMESTAMP)) ||
+		    (lroh->ts[2] == 0)) {
+			return;
+		}
+
+		TXGBE_CB(skb)->tsval = ntohl(lroh->ts[1]);
+		TXGBE_CB(skb)->tsecr = lroh->ts[2];
+
+		data_len -= TCPOLEN_TSTAMP_ALIGNED;
+	}
+
+	/* record data_len as mss for the packet */
+	TXGBE_CB(skb)->mss = data_len;
+	TXGBE_CB(skb)->next_seq = ntohl(lroh->th.seq);
+}
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+static void txgbe_merge_frags(struct sk_buff *lro_skb, struct sk_buff *new_skb)
+{
+	struct skb_shared_info *sh_info;
+	struct skb_shared_info *new_skb_info;
+	unsigned int data_len;
+
+	sh_info = skb_shinfo(lro_skb);
+	new_skb_info = skb_shinfo(new_skb);
+
+	/* copy frags into the last skb */
+	memcpy(sh_info->frags + sh_info->nr_frags,
+	       new_skb_info->frags,
+	       new_skb_info->nr_frags * sizeof(skb_frag_t));
+
+	/* copy size data over */
+	sh_info->nr_frags += new_skb_info->nr_frags;
+	data_len = TXGBE_CB(new_skb)->mss;
+	lro_skb->len += data_len;
+	lro_skb->data_len += data_len;
+	lro_skb->truesize += data_len;
+
+	/* wipe record of data from new_skb and free it */
+	new_skb_info->nr_frags = 0;
+	new_skb->len = new_skb->data_len = 0;
+	dev_kfree_skb_any(new_skb);
+}
+
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+/**
+ * txgbe_lro_receive - if able, queue skb into lro chain
+ * @q_vector: structure containing interrupt and ring information
+ * @new_skb: pointer to current skb being checked
+ *
+ * Checks whether the skb given is eligible for LRO and if that's
+ * fine chains it to the existing lro_skb based on flowid. If an LRO for
+ * the flow doesn't exist create one.
+ **/
+static void txgbe_lro_receive(struct txgbe_q_vector *q_vector,
+			      struct sk_buff *new_skb)
+{
+	struct sk_buff *lro_skb;
+	struct txgbe_lro_list *lrolist = &q_vector->lrolist;
+	struct txgbe_lrohdr *lroh = txgbe_lro_hdr(new_skb);
+	__be32 saddr = lroh->iph.saddr;
+	__be32 daddr = lroh->iph.daddr;
+	__be32 tcp_ports = *(__be32 *)&lroh->th;
+#ifdef HAVE_VLAN_RX_REGISTER
+	u16 vid = TXGBE_CB(new_skb)->vid;
+#else
+	u16 vid = new_skb->vlan_tci;
+#endif
+
+	txgbe_lro_header_ok(new_skb);
+
+	/*
+	 * we have a packet that might be eligible for LRO,
+	 * so see if it matches anything we might expect
+	 */
+	skb_queue_walk(&lrolist->active, lro_skb) {
+		u16 data_len;
+
+		if (*(__be32 *)&txgbe_lro_hdr(lro_skb)->th != tcp_ports ||
+		    txgbe_lro_hdr(lro_skb)->iph.saddr != saddr ||
+		    txgbe_lro_hdr(lro_skb)->iph.daddr != daddr)
+			continue;
+
+#ifdef HAVE_VLAN_RX_REGISTER
+		if (TXGBE_CB(lro_skb)->vid != vid)
+#else
+		if (lro_skb->vlan_tci != vid)
+#endif
+			continue;
+
+		/* out of order packet */
+		if (TXGBE_CB(lro_skb)->next_seq !=
+		    TXGBE_CB(new_skb)->next_seq) {
+			txgbe_lro_flush(q_vector, lro_skb);
+			TXGBE_CB(new_skb)->mss = 0;
+			break;
+		}
+
+		/* TCP timestamp options have changed */
+		if (!TXGBE_CB(lro_skb)->tsecr != !TXGBE_CB(new_skb)->tsecr) {
+			txgbe_lro_flush(q_vector, lro_skb);
+			break;
+		}
+
+		/* make sure timestamp values are increasing */
+		if (TXGBE_CB(lro_skb)->tsecr &&
+		    TXGBE_CB(lro_skb)->tsval > TXGBE_CB(new_skb)->tsval) {
+			txgbe_lro_flush(q_vector, lro_skb);
+			TXGBE_CB(new_skb)->mss = 0;
+			break;
+		}
+
+		data_len = TXGBE_CB(new_skb)->mss;
+
+		/* Check for all of the above below
+		 *   malformed header
+		 *   no tcp data
+		 *   resultant packet would be too large
+		 *   new skb is larger than our current mss
+		 *   data would remain in header
+		 *   we would consume more frags then the sk_buff contains
+		 *   ack sequence numbers changed
+		 *   window size has changed
+		 */
+		if (data_len == 0 ||
+		    data_len > TXGBE_CB(lro_skb)->mss ||
+		    data_len > TXGBE_CB(lro_skb)->free ||
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		    data_len != new_skb->data_len ||
+		    skb_shinfo(new_skb)->nr_frags >=
+		    (MAX_SKB_FRAGS - skb_shinfo(lro_skb)->nr_frags) ||
+#endif
+		    txgbe_lro_hdr(lro_skb)->th.ack_seq != lroh->th.ack_seq ||
+		    txgbe_lro_hdr(lro_skb)->th.window != lroh->th.window) {
+			txgbe_lro_flush(q_vector, lro_skb);
+			break;
+		}
+
+		/* Remove IP and TCP header */
+		skb_pull(new_skb, new_skb->len - data_len);
+
+		/* update timestamp and timestamp echo response */
+		TXGBE_CB(lro_skb)->tsval = TXGBE_CB(new_skb)->tsval;
+		TXGBE_CB(lro_skb)->tsecr = TXGBE_CB(new_skb)->tsecr;
+
+		/* update sequence and free space */
+		TXGBE_CB(lro_skb)->next_seq += data_len;
+		TXGBE_CB(lro_skb)->free -= data_len;
+
+		/* update append_cnt */
+		TXGBE_CB(lro_skb)->append_cnt++;
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		/* if header is empty pull pages into current skb */
+		txgbe_merge_frags(lro_skb, new_skb);
+#else
+		/* chain this new skb in frag_list */
+		txgbe_add_active_tail(lro_skb, new_skb);
+#endif
+
+		if ((data_len < TXGBE_CB(lro_skb)->mss) || lroh->th.psh ||
+		    skb_shinfo(lro_skb)->nr_frags == MAX_SKB_FRAGS) {
+			txgbe_lro_hdr(lro_skb)->th.psh |= lroh->th.psh;
+			txgbe_lro_flush(q_vector, lro_skb);
+		}
+
+		lrolist->stats.coal++;
+		return;
+	}
+
+	if (TXGBE_CB(new_skb)->mss && !lroh->th.psh) {
+		/* if we are at capacity flush the tail */
+		if (skb_queue_len(&lrolist->active) >= TXGBE_LRO_MAX) {
+			lro_skb = skb_peek_tail(&lrolist->active);
+			if (lro_skb)
+				txgbe_lro_flush(q_vector, lro_skb);
+		}
+
+		/* update sequence and free space */
+		TXGBE_CB(new_skb)->next_seq += TXGBE_CB(new_skb)->mss;
+		TXGBE_CB(new_skb)->free = 65521 - new_skb->len;
+
+		/* .. and insert at the front of the active list */
+		__skb_queue_head(&lrolist->active, new_skb);
+
+		lrolist->stats.coal++;
+		return;
+	}
+
+	/* packet not handled by any of the above, pass it to the stack */
+#ifdef HAVE_VLAN_RX_REGISTER
+	txgbe_receive_skb(q_vector, new_skb);
+#else
+	napi_gro_receive(&q_vector->napi, new_skb);
+#endif /* HAVE_VLAN_RX_REGISTER */
+}
+
+#endif /* TXGBE_NO_LRO */
+#ifdef NETIF_F_GSO
+static void txgbe_set_rsc_gso_size(struct txgbe_ring __maybe_unused *ring,
+				   struct sk_buff *skb)
+{
+	u16 hdr_len = eth_get_headlen(skb->dev, skb->data, skb_headlen(skb));
+
+	/* set gso_size to avoid messing up TCP MSS */
+	skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len),
+						 TXGBE_CB(skb)->append_cnt);
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+}
+
+#endif /* NETIF_F_GSO */
+static void txgbe_update_rsc_stats(struct txgbe_ring *rx_ring,
+				   struct sk_buff *skb)
+{
+	/* if append_cnt is 0 then frame is not RSC */
+	if (!TXGBE_CB(skb)->append_cnt)
+		return;
+
+	rx_ring->rx_stats.rsc_count += TXGBE_CB(skb)->append_cnt;
+	rx_ring->rx_stats.rsc_flush++;
+
+#ifdef NETIF_F_GSO
+	txgbe_set_rsc_gso_size(rx_ring, skb);
+
+#endif
+	/* gso_size is computed using append_cnt so always clear it last */
+	TXGBE_CB(skb)->append_cnt = 0;
+}
+
+static void txgbe_rx_vlan(struct txgbe_ring *ring,
+			  union txgbe_rx_desc *rx_desc,
+			  struct sk_buff *skb)
+{
+#ifndef HAVE_VLAN_RX_REGISTER
+	u8 idx = 0;
+	u16 ethertype;
+#endif
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+	if ((ring->netdev->features & (NETIF_F_HW_VLAN_CTAG_RX |
+	    NETIF_F_HW_VLAN_STAG_RX)) &&
+#elif (defined NETIF_F_HW_VLAN_CTAG_RX)
+	if ((ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+#elif (defined NETIF_F_HW_VLAN_STAG_RX)
+	if ((ring->netdev->features & NETIF_F_HW_VLAN_STAG_RX) &&
+#else
+	if ((ring->netdev->features & NETIF_F_HW_VLAN_RX) &&
+#endif
+		txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_VP))
+#ifndef HAVE_VLAN_RX_REGISTER
+	{
+		idx = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) &
+			TXGBE_RXD_TPID_MASK) >> TXGBE_RXD_TPID_SHIFT;
+		ethertype = ring->q_vector->adapter->hw.tpid[idx];
+		__vlan_hwaccel_put_tag(skb,
+				       htons(ethertype),
+				       le16_to_cpu(rx_desc->wb.upper.vlan));
+	}
+#else /* !HAVE_VLAN_RX_REGISTER */
+		TXGBE_CB(skb)->vid = le16_to_cpu(rx_desc->wb.upper.vlan);
+	else
+		TXGBE_CB(skb)->vid = 0;
+#endif /* !HAVE_VLAN_RX_REGISTER */
+}
+
+/**
+ * txgbe_process_skb_fields - Populate skb header fields from Rx descriptor
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being populated
+ *
+ * This function checks the ring, descriptor, and packet information in
+ * order to populate the hash, checksum, VLAN, timestamp, protocol, and
+ * other fields within the skb.
+ **/
+static void txgbe_process_skb_fields(struct txgbe_ring *rx_ring,
+				     union txgbe_rx_desc *rx_desc,
+				     struct sk_buff *skb)
+{
+#ifdef HAVE_PTP_1588_CLOCK
+	u32 flags = rx_ring->q_vector->adapter->flags;
+#endif /* HAVE_PTP_1588_CLOCK */
+
+	txgbe_update_rsc_stats(rx_ring, skb);
+
+#ifdef NETIF_F_RXHASH
+	txgbe_rx_hash(rx_ring, rx_desc, skb);
+#endif /* NETIF_F_RXHASH */
+
+	txgbe_rx_checksum(rx_ring, rx_desc, skb);
+#ifdef HAVE_PTP_1588_CLOCK
+	if (unlikely(flags & TXGBE_FLAG_RX_HWTSTAMP_ENABLED) &&
+		unlikely(txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_TS))) {
+		txgbe_ptp_rx_hwtstamp(rx_ring->q_vector->adapter, skb);
+		rx_ring->last_rx_timestamp = jiffies;
+	}
+#endif /* HAVE_PTP_1588_CLOCK */
+
+	txgbe_rx_vlan(rx_ring, rx_desc, skb);
+
+	skb_record_rx_queue(skb, rx_ring->queue_index);
+
+	skb->protocol = eth_type_trans(skb, rx_ring->netdev);
+}
+
+static void txgbe_rx_skb(struct txgbe_q_vector *q_vector,
+			 struct txgbe_ring *rx_ring,
+			 union txgbe_rx_desc *rx_desc,
+			 struct sk_buff *skb)
+{
+#ifdef HAVE_NDO_BUSY_POLL
+	skb_mark_napi_id(skb, &q_vector->napi);
+
+	if (txgbe_qv_busy_polling(q_vector) || q_vector->netpoll_rx) {
+		netif_receive_skb(skb);
+		/* exit early if we busy polled */
+		return;
+	}
+#endif
+
+#ifndef TXGBE_NO_LRO
+	if (txgbe_can_lro(rx_ring, rx_desc, skb))
+		txgbe_lro_receive(q_vector, skb);
+	else
+#endif
+#ifdef HAVE_VLAN_RX_REGISTER
+		txgbe_receive_skb(q_vector, skb);
+#else
+		napi_gro_receive(&q_vector->napi, skb);
+#endif
+
+#ifndef NETIF_F_GRO
+	rx_ring->netdev->last_rx = jiffies;
+#endif
+}
+
+/**
+ * txgbe_is_non_eop - process handling of non-EOP buffers
+ * @rx_ring: Rx ring being processed
+ * @rx_desc: Rx descriptor for current buffer
+ * @skb: Current socket buffer containing buffer in progress
+ *
+ * This function updates next to clean.  If the buffer is an EOP buffer
+ * this function exits returning false, otherwise it will place the
+ * sk_buff in the next buffer to be chained and return true indicating
+ * that this is in fact a non-EOP buffer.
+ **/
+static bool txgbe_is_non_eop(struct txgbe_ring *rx_ring,
+			     union txgbe_rx_desc *rx_desc,
+			     struct sk_buff *skb)
+{
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	struct txgbe_rx_buffer *rx_buffer =
+			&rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+#else
+	struct sk_buff *next_skb;
+#endif
+	u32 ntc = rx_ring->next_to_clean + 1;
+
+	/* fetch, update, and store next to clean */
+	ntc = (ntc < rx_ring->count) ? ntc : 0;
+	rx_ring->next_to_clean = ntc;
+
+	prefetch(TXGBE_RX_DESC(rx_ring, ntc));
+
+	/* update RSC append count if present */
+	if (ring_is_rsc_enabled(rx_ring)) {
+		__le32 rsc_enabled = rx_desc->wb.lower.lo_dword.data &
+				     cpu_to_le32(TXGBE_RXD_RSCCNT_MASK);
+
+		if (unlikely(rsc_enabled)) {
+			u32 rsc_cnt = le32_to_cpu(rsc_enabled);
+
+			rsc_cnt >>= TXGBE_RXD_RSCCNT_SHIFT;
+			TXGBE_CB(skb)->append_cnt += rsc_cnt - 1;
+
+			/* update ntc based on RSC value */
+			ntc = le32_to_cpu(rx_desc->wb.upper.status_error);
+			ntc &= TXGBE_RXD_NEXTP_MASK;
+			ntc >>= TXGBE_RXD_NEXTP_SHIFT;
+		}
+	}
+
+	/* if we are the last buffer then there is nothing else to do */
+	if (likely(txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_EOP)))
+		return false;
+
+	/* place skb in next buffer to be received */
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	next_skb = rx_ring->rx_buffer_info[ntc].skb;
+
+	txgbe_add_active_tail(skb, next_skb);
+	TXGBE_CB(next_skb)->head = skb;
+#else
+	if (ring_is_hs_enabled(rx_ring)) {
+		rx_buffer->skb = rx_ring->rx_buffer_info[ntc].skb;
+		rx_buffer->dma = rx_ring->rx_buffer_info[ntc].dma;
+		rx_ring->rx_buffer_info[ntc].dma = 0;
+	}
+	rx_ring->rx_buffer_info[ntc].skb = skb;
+#endif
+	rx_ring->rx_stats.non_eop_descs++;
+
+	return true;
+}
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+/**
+ * txgbe_pull_tail - txgbe specific version of skb_pull_tail
+ * @skb: pointer to current skb being adjusted
+ *
+ * This function is an txgbe specific version of __pskb_pull_tail.  The
+ * main difference between this version and the original function is that
+ * this function can make several assumptions about the state of things
+ * that allow for significant optimizations versus the standard function.
+ * As a result we can do things like drop a frag and maintain an accurate
+ * truesize for the skb.
+ */
+static void txgbe_pull_tail(struct sk_buff *skb)
+{
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+	unsigned char *va;
+	unsigned int pull_len;
+
+	/*
+	 * it is valid to use page_address instead of kmap since we are
+	 * working with pages allocated out of the lomem pool per
+	 * alloc_page(GFP_ATOMIC)
+	 */
+	va = skb_frag_address(frag);
+
+	/*
+	 * we need the header to contain the greater of either ETH_HLEN or
+	 * 60 bytes if the skb->len is less than 60 for skb_pad.
+	 */
+	pull_len = eth_get_headlen(skb->dev, va, TXGBE_RX_HDR_SIZE);
+
+	/* align pull length to size of long to optimize memcpy performance */
+	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
+
+	/* update all of the pointers */
+	skb_frag_size_sub(frag, pull_len);
+	skb_frag_off_add(frag, pull_len);
+	skb->data_len -= pull_len;
+	skb->tail += pull_len;
+}
+
+/**
+ * txgbe_dma_sync_frag - perform DMA sync for first frag of SKB
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being updated
+ *
+ * This function provides a basic DMA sync up for the first fragment of an
+ * skb.  The reason for doing this is that the first fragment cannot be
+ * unmapped until we have reached the end of packet descriptor for a buffer
+ * chain.
+ */
+static void txgbe_dma_sync_frag(struct txgbe_ring *rx_ring,
+				struct sk_buff *skb)
+{
+#if defined(HAVE_STRUCT_DMA_ATTRS) && defined(HAVE_SWIOTLB_SKIP_CPU_SYNC)
+	DEFINE_DMA_ATTRS(attrs);
+
+	dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
+	dma_set_attr(DMA_ATTR_WEAK_ORDERING, &attrs);
+
+#endif
+	/* if the page was released unmap it, else just sync our portion */
+	if (unlikely(TXGBE_CB(skb)->page_released)) {
+		dma_unmap_page_attrs(rx_ring->dev, TXGBE_CB(skb)->dma,
+				     txgbe_rx_pg_size(rx_ring),
+				     DMA_FROM_DEVICE,
+#if defined(HAVE_STRUCT_DMA_ATTRS) && defined(HAVE_SWIOTLB_SKIP_CPU_SYNC)
+				     &attrs);
+#else
+				     TXGBE_RX_DMA_ATTR);
+#endif
+	} else if (ring_uses_build_skb(rx_ring)) {
+		unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK;
+
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      TXGBE_CB(skb)->dma,
+					      offset,
+					      skb_headlen(skb),
+					      DMA_FROM_DEVICE);
+	} else {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      TXGBE_CB(skb)->dma,
+					      skb_frag_off(frag),
+					      skb_frag_size(frag),
+					      DMA_FROM_DEVICE);
+	}
+}
+
+/**
+ * txgbe_cleanup_headers - Correct corrupted or empty headers
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being fixed
+ *
+ * Check for corrupted packet headers caused by senders on the local L2
+ * embedded NIC switch not setting up their Tx Descriptors right.  These
+ * should be very rare.
+ *
+ * Also address the case where we are pulling data in on pages only
+ * and as such no data is present in the skb header.
+ *
+ * In addition if skb is not at least 60 bytes we need to pad it so that
+ * it is large enough to qualify as a valid Ethernet frame.
+ *
+ * Returns true if an error was encountered and skb was freed.
+ **/
+static bool txgbe_cleanup_headers(struct txgbe_ring *rx_ring,
+				  union txgbe_rx_desc *rx_desc,
+				  struct sk_buff *skb)
+{
+	struct net_device *netdev = rx_ring->netdev;
+
+	/* verify that the packet does not have any known errors */
+	if (unlikely(txgbe_test_staterr(rx_desc,
+		TXGBE_RXD_ERR_FRAME_ERR_MASK) &&
+		!(netdev->features & NETIF_F_RXALL))) {
+		dev_kfree_skb_any(skb);
+		return true;
+	}
+
+	/* place header in linear portion of buffer */
+	if (skb_is_nonlinear(skb)  && !skb_headlen(skb))
+		txgbe_pull_tail(skb);
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* do not attempt to pad FCoE Frames as this will disrupt DDP */
+	if (txgbe_rx_is_fcoe(rx_ring, rx_desc))
+		return false;
+#endif
+
+	/* if eth_skb_pad returns an error the skb was freed */
+	if (eth_skb_pad(skb))
+		return true;
+
+	return false;
+}
+
+/**
+ * txgbe_reuse_rx_page - page flip buffer and store it back on the ring
+ * @rx_ring: rx descriptor ring to store buffers on
+ * @old_buff: donor buffer to have page reused
+ *
+ * Synchronizes page for reuse by the adapter
+ **/
+static void txgbe_reuse_rx_page(struct txgbe_ring *rx_ring,
+				struct txgbe_rx_buffer *old_buff)
+{
+	struct txgbe_rx_buffer *new_buff;
+	u16 nta = rx_ring->next_to_alloc;
+
+	new_buff = &rx_ring->rx_buffer_info[nta];
+
+	/* update, and store next to alloc */
+	nta++;
+	rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+	/* transfer page from old buffer to new buffer */
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	new_buff->page_dma = old_buff->page_dma;
+	new_buff->page = old_buff->page;
+	new_buff->page_offset = old_buff->page_offset;
+#endif
+
+	/* sync the buffer for use by the device */
+	dma_sync_single_range_for_device(rx_ring->dev, new_buff->page_dma,
+					 new_buff->page_offset,
+					 txgbe_rx_bufsz(rx_ring),
+					 DMA_FROM_DEVICE);
+}
+
+static inline bool txgbe_page_is_reserved(struct page *page)
+{
+	return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
+}
+
+/**
+ * txgbe_add_rx_frag - Add contents of Rx buffer to sk_buff
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @rx_buffer: buffer containing page to add
+ * @rx_desc: descriptor containing length of buffer written by hardware
+ * @skb: sk_buff to place the data into
+ *
+ * This function will add the data contained in rx_buffer->page to the skb.
+ * This is done either through a direct copy if the data in the buffer is
+ * less than the skb header size, otherwise it will just attach the page as
+ * a frag to the skb.
+ *
+ * The function will then update the page offset if necessary and return
+ * true if the buffer can be reused by the adapter.
+ **/
+static bool txgbe_add_rx_frag(struct txgbe_ring *rx_ring,
+			      struct txgbe_rx_buffer *rx_buffer,
+			      union txgbe_rx_desc *rx_desc,
+			      struct sk_buff *skb)
+{
+	struct page *page = rx_buffer->page;
+	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+#if (PAGE_SIZE < 8192)
+	unsigned int truesize = txgbe_rx_bufsz(rx_ring);
+#else
+	unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
+	unsigned int last_offset = txgbe_rx_pg_size(rx_ring) -
+				   txgbe_rx_bufsz(rx_ring);
+#endif
+
+	if ((size <= TXGBE_RX_HDR_SIZE) && !skb_is_nonlinear(skb) &&
+	    !ring_is_hs_enabled(rx_ring)) {
+		unsigned char *va = page_address(page) + rx_buffer->page_offset;
+
+		memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
+
+		/* page is not reserved, we can reuse buffer as-is */
+		if (likely(!txgbe_page_is_reserved(page)))
+			return true;
+
+		/* this page cannot be reused so discard it */
+		__free_pages(page, txgbe_rx_pg_order(rx_ring));
+		return false;
+	}
+
+	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+			rx_buffer->page_offset, size, truesize);
+
+	/* avoid re-using remote pages */
+	if (unlikely(txgbe_page_is_reserved(page)))
+		return false;
+
+#if (PAGE_SIZE < 8192)
+	/* if we are only owner of page we can reuse it */
+	if (unlikely(page_count(page) != 1))
+		return false;
+
+	/* flip page offset to other buffer */
+	rx_buffer->page_offset ^= truesize;
+#else
+	/* move offset up to the next cache line */
+	rx_buffer->page_offset += truesize;
+
+	if (rx_buffer->page_offset > last_offset)
+		return false;
+#endif
+
+	/* Even if we own the page, we are not allowed to use atomic_set()
+	 * This would break get_page_unless_zero() users.
+	 */
+	page_ref_inc(page);
+
+	return true;
+}
+
+static struct sk_buff *txgbe_fetch_rx_buffer(struct txgbe_ring *rx_ring,
+					     union txgbe_rx_desc *rx_desc)
+{
+	struct txgbe_rx_buffer *rx_buffer;
+	struct sk_buff *skb;
+	struct page *page;
+
+	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+	page = rx_buffer->page;
+	prefetchw(page);
+
+	skb = rx_buffer->skb;
+
+	if (likely(!skb)) {
+		void *page_addr = page_address(page) +
+				  rx_buffer->page_offset;
+
+		/* prefetch first cache line of first page */
+		prefetch(page_addr);
+#if L1_CACHE_BYTES < 128
+		prefetch(page_addr + L1_CACHE_BYTES);
+#endif
+
+		/* allocate a skb to store the frags */
+		skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+						TXGBE_RX_HDR_SIZE);
+		if (unlikely(!skb)) {
+			rx_ring->rx_stats.alloc_rx_buff_failed++;
+			return NULL;
+		}
+
+		/*
+		 * we will be copying header into skb->data in
+		 * pskb_may_pull so it is in our interest to prefetch
+		 * it now to avoid a possible cache miss
+		 */
+		prefetchw(skb->data);
+
+		/*
+		 * Delay unmapping of the first packet. It carries the
+		 * header information, HW may still access the header
+		 * after the writeback.  Only unmap it when EOP is
+		 * reached
+		 */
+		if (likely(txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_EOP)))
+			goto dma_sync;
+
+		TXGBE_CB(skb)->dma = rx_buffer->page_dma;
+	} else {
+		if (txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_EOP))
+			txgbe_dma_sync_frag(rx_ring, skb);
+
+dma_sync:
+		/* we are reusing so sync this buffer for CPU use */
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      rx_buffer->page_dma,
+					      rx_buffer->page_offset,
+					      txgbe_rx_bufsz(rx_ring),
+					      DMA_FROM_DEVICE);
+
+		rx_buffer->skb = NULL;
+	}
+
+	/* pull page into skb */
+	if (txgbe_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
+		/* hand second half of page back to the ring */
+		txgbe_reuse_rx_page(rx_ring, rx_buffer);
+	} else if (TXGBE_CB(skb)->dma == rx_buffer->page_dma) {
+		/* the page has been released from the ring */
+		TXGBE_CB(skb)->page_released = true;
+	} else {
+		/* we are not reusing the buffer so unmap it */
+		dma_unmap_page(rx_ring->dev, rx_buffer->page_dma,
+			       txgbe_rx_pg_size(rx_ring),
+			       DMA_FROM_DEVICE);
+	}
+
+	/* clear contents of buffer_info */
+	rx_buffer->page = NULL;
+
+	return skb;
+}
+
+static struct sk_buff *txgbe_fetch_rx_buffer_hs(struct txgbe_ring *rx_ring,
+					     union txgbe_rx_desc *rx_desc)
+{
+	struct txgbe_rx_buffer *rx_buffer;
+	struct sk_buff *skb;
+	struct page *page;
+	int hdr_len = 0;
+
+	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+	page = rx_buffer->page;
+	prefetchw(page);
+
+	skb = rx_buffer->skb;
+	rx_buffer->skb = NULL;
+	prefetchw(skb->data);
+
+	if (!skb_is_nonlinear(skb)) {
+		hdr_len = txgbe_get_hlen(rx_ring, rx_desc);
+		if (hdr_len > 0) {
+			__skb_put(skb, hdr_len);
+			TXGBE_CB(skb)->dma_released = true;
+			TXGBE_CB(skb)->dma = rx_buffer->dma;
+			rx_buffer->dma = 0;
+		} else {
+			dma_unmap_single(rx_ring->dev,
+					 rx_buffer->dma,
+					 rx_ring->rx_buf_len,
+					 DMA_FROM_DEVICE);
+			rx_buffer->dma = 0;
+			if (likely(txgbe_test_staterr(rx_desc,
+			    TXGBE_RXD_STAT_EOP)))
+				goto dma_sync;
+			TXGBE_CB(skb)->dma = rx_buffer->page_dma;
+			goto add_frag;
+		}
+	}
+
+	if (txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_EOP)) {
+		if (skb_headlen(skb)) {
+			if (TXGBE_CB(skb)->dma_released == true) {
+				dma_unmap_single(rx_ring->dev,
+						 TXGBE_CB(skb)->dma,
+						 rx_ring->rx_buf_len,
+						 DMA_FROM_DEVICE);
+				TXGBE_CB(skb)->dma = 0;
+				TXGBE_CB(skb)->dma_released = false;
+			}
+		} else
+			txgbe_dma_sync_frag(rx_ring, skb);
+	}
+
+dma_sync:
+	/* we are reusing so sync this buffer for CPU use */
+	dma_sync_single_range_for_cpu(rx_ring->dev,
+				      rx_buffer->page_dma,
+				      rx_buffer->page_offset,
+				      txgbe_rx_bufsz(rx_ring),
+				      DMA_FROM_DEVICE);
+add_frag:
+	/* pull page into skb */
+	if (txgbe_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
+		/* hand second half of page back to the ring */
+		txgbe_reuse_rx_page(rx_ring, rx_buffer);
+	} else if (TXGBE_CB(skb)->dma == rx_buffer->page_dma) {
+		/* the page has been released from the ring */
+		TXGBE_CB(skb)->page_released = true;
+	} else {
+		/* we are not reusing the buffer so unmap it */
+		dma_unmap_page(rx_ring->dev, rx_buffer->page_dma,
+			       txgbe_rx_pg_size(rx_ring),
+			       DMA_FROM_DEVICE);
+	}
+
+	/* clear contents of buffer_info */
+	rx_buffer->page = NULL;
+
+	return skb;
+}
+
+/**
+ * txgbe_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
+ * @q_vector: structure containing interrupt and ring information
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @budget: Total limit on number of packets to process
+ *
+ * This function provides a "bounce buffer" approach to Rx interrupt
+ * processing.  The advantage to this is that on systems that have
+ * expensive overhead for IOMMU access this provides a means of avoiding
+ * it by maintaining the mapping of the page to the syste.
+ *
+ * Returns amount of work completed.
+ **/
+static int txgbe_clean_rx_irq(struct txgbe_q_vector *q_vector,
+			       struct txgbe_ring *rx_ring,
+			       int budget)
+{
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#if IS_ENABLED(CONFIG_FCOE)
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	int ddp_bytes;
+	unsigned int mss = 0;
+#endif /* CONFIG_FCOE */
+	u16 cleaned_count = txgbe_desc_unused(rx_ring);
+
+	do {
+		union txgbe_rx_desc *rx_desc;
+		struct sk_buff *skb;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= TXGBE_RX_BUFFER_WRITE) {
+			txgbe_alloc_rx_buffers(rx_ring, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		rx_desc = TXGBE_RX_DESC(rx_ring, rx_ring->next_to_clean);
+
+		if (!txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_DD))
+			break;
+
+		/* This memory barrier is needed to keep us from reading
+		 * any other fields out of the rx_desc until we know the
+		 * descriptor has been written back
+		 */
+		dma_rmb();
+
+		/* retrieve a buffer from the ring */
+		if (ring_is_hs_enabled(rx_ring))
+			skb = txgbe_fetch_rx_buffer_hs(rx_ring, rx_desc);
+		else
+			skb = txgbe_fetch_rx_buffer(rx_ring, rx_desc);
+
+		/* exit if we failed to retrieve a buffer */
+		if (!skb)
+			break;
+
+		cleaned_count++;
+
+		/* place incomplete frames back on ring for completion */
+		if (txgbe_is_non_eop(rx_ring, rx_desc, skb))
+			continue;
+
+		/* verify the packet layout is correct */
+		if (txgbe_cleanup_headers(rx_ring, rx_desc, skb))
+			continue;
+
+		/* probably a little skewed due to removing CRC */
+		total_rx_bytes += skb->len;
+
+		/* populate checksum, timestamp, VLAN, and protocol */
+		txgbe_process_skb_fields(rx_ring, rx_desc, skb);
+
+#if IS_ENABLED(CONFIG_FCOE)
+		/* if ddp, not passing to ULD unless for FCP_RSP or error */
+		if (txgbe_rx_is_fcoe(rx_ring, rx_desc)) {
+			ddp_bytes = txgbe_fcoe_ddp(adapter, rx_desc, skb);
+			/* include DDPed FCoE data */
+			if (ddp_bytes > 0) {
+				if (!mss) {
+					mss = rx_ring->netdev->mtu -
+						sizeof(struct fcoe_hdr) -
+						sizeof(struct fc_frame_header) -
+						sizeof(struct fcoe_crc_eof);
+					if (mss > 512)
+						mss &= ~511;
+				}
+				total_rx_bytes += ddp_bytes;
+				total_rx_packets +=
+						DIV_ROUND_UP(ddp_bytes, mss);
+			}
+			if (!ddp_bytes) {
+				dev_kfree_skb_any(skb);
+#ifndef NETIF_F_GRO
+				rx_ring->netdev->last_rx = jiffies;
+#endif
+				continue;
+			}
+		}
+#endif /* CONFIG_FCOE */
+
+		txgbe_rx_skb(q_vector, rx_ring, rx_desc, skb);
+
+		/* update budget accounting */
+		total_rx_packets++;
+	} while (likely(total_rx_packets < budget));
+
+	u64_stats_update_begin(&rx_ring->syncp);
+	rx_ring->stats.packets += total_rx_packets;
+	rx_ring->stats.bytes += total_rx_bytes;
+	u64_stats_update_end(&rx_ring->syncp);
+	q_vector->rx.total_packets += total_rx_packets;
+	q_vector->rx.total_bytes += total_rx_bytes;
+
+#ifndef TXGBE_NO_LRO
+	txgbe_lro_flush_all(q_vector);
+#endif
+	return total_rx_packets;
+}
+
+#else /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+/**
+ * txgbe_clean_rx_irq - Clean completed descriptors from Rx ring - legacy
+ * @q_vector: structure containing interrupt and ring information
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @budget: Total limit on number of packets to process
+ *
+ * This function provides a legacy approach to Rx interrupt
+ * handling.  This version will perform better on systems with a low cost
+ * dma mapping API.
+ *
+ * Returns amount of work completed.
+ **/
+static int txgbe_clean_rx_irq(struct txgbe_q_vector *q_vector,
+			       struct txgbe_ring *rx_ring,
+			       int budget)
+{
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#if IS_ENABLED(CONFIG_FCOE)
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	int ddp_bytes;
+	unsigned int mss = 0;
+#endif /* CONFIG_FCOE */
+	u16 len = 0;
+	u16 cleaned_count = txgbe_desc_unused(rx_ring);
+
+	do {
+		struct txgbe_rx_buffer *rx_buffer;
+		union txgbe_rx_desc *rx_desc;
+		struct sk_buff *skb;
+		u16 ntc;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= TXGBE_RX_BUFFER_WRITE) {
+			txgbe_alloc_rx_buffers(rx_ring, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		ntc = rx_ring->next_to_clean;
+		rx_desc = TXGBE_RX_DESC(rx_ring, ntc);
+		rx_buffer = &rx_ring->rx_buffer_info[ntc];
+
+		if (!txgbe_test_staterr(rx_desc, TXGBE_RXD_STAT_DD))
+			break;
+
+		/*
+		 * This memory barrier is needed to keep us from reading
+		 * any other fields out of the rx_desc until we know the
+		 * RXD_STAT_DD bit is set
+		 */
+		rmb();
+
+		skb = rx_buffer->skb;
+
+		prefetch(skb->data);
+
+		len = le16_to_cpu(rx_desc->wb.upper.length);
+		/* pull the header of the skb in */
+		__skb_put(skb, len);
+
+		/*
+		 * Delay unmapping of the first packet. It carries the
+		 * header information, HW may still access the header after
+		 * the writeback.  Only unmap it when EOP is reached
+		 */
+		if (!TXGBE_CB(skb)->head) {
+			TXGBE_CB(skb)->dma = rx_buffer->dma;
+		} else {
+			skb = txgbe_merge_active_tail(skb);
+			dma_unmap_single(rx_ring->dev,
+					 rx_buffer->dma,
+					 rx_ring->rx_buf_len,
+					 DMA_FROM_DEVICE);
+		}
+
+		/* clear skb reference in buffer info structure */
+		rx_buffer->skb = NULL;
+		rx_buffer->dma = 0;
+
+		cleaned_count++;
+
+		if (txgbe_is_non_eop(rx_ring, rx_desc, skb))
+			continue;
+
+		dma_unmap_single(rx_ring->dev,
+				 TXGBE_CB(skb)->dma,
+				 rx_ring->rx_buf_len,
+				 DMA_FROM_DEVICE);
+
+		TXGBE_CB(skb)->dma = 0;
+
+		if (txgbe_close_active_frag_list(skb) &&
+		    !TXGBE_CB(skb)->append_cnt) {
+			/* if we got here without RSC the packet is invalid */
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+
+		/* ERR_MASK will only have valid bits if EOP set */
+		if (unlikely(txgbe_test_staterr(rx_desc,
+					   TXGBE_RXD_ERR_FRAME_ERR_MASK))) {
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+
+		/* probably a little skewed due to removing CRC */
+		total_rx_bytes += skb->len;
+
+		/* populate checksum, timestamp, VLAN, and protocol */
+		txgbe_process_skb_fields(rx_ring, rx_desc, skb);
+
+#if IS_ENABLED(CONFIG_FCOE)
+		/* if ddp, not passing to ULD unless for FCP_RSP or error */
+		if (txgbe_rx_is_fcoe(rx_ring, rx_desc)) {
+			ddp_bytes = txgbe_fcoe_ddp(adapter, rx_desc, skb);
+			/* include DDPed FCoE data */
+			if (ddp_bytes > 0) {
+				if (!mss) {
+					mss = rx_ring->netdev->mtu -
+						sizeof(struct fcoe_hdr) -
+						sizeof(struct fc_frame_header) -
+						sizeof(struct fcoe_crc_eof);
+					if (mss > 512)
+						mss &= ~511;
+				}
+				total_rx_bytes += ddp_bytes;
+				total_rx_packets +=
+						DIV_ROUND_UP(ddp_bytes, mss);
+			}
+			if (!ddp_bytes) {
+				dev_kfree_skb_any(skb);
+#ifndef NETIF_F_GRO
+				rx_ring->netdev->last_rx = jiffies;
+#endif
+				continue;
+			}
+		}
+
+#endif /* CONFIG_FCOE */
+		txgbe_rx_skb(q_vector, rx_ring, rx_desc, skb);
+
+		/* update budget accounting */
+		total_rx_packets++;
+	} while (likely(total_rx_packets < budget));
+
+	u64_stats_update_begin(&rx_ring->syncp);
+	rx_ring->stats.packets += total_rx_packets;
+	rx_ring->stats.bytes += total_rx_bytes;
+	u64_stats_update_end(&rx_ring->syncp);
+	q_vector->rx.total_packets += total_rx_packets;
+	q_vector->rx.total_bytes += total_rx_bytes;
+
+	if (cleaned_count)
+		txgbe_alloc_rx_buffers(rx_ring, cleaned_count);
+
+#ifndef TXGBE_NO_LRO
+	txgbe_lro_flush_all(q_vector);
+
+#endif /* TXGBE_NO_LRO */
+	return total_rx_packets;
+}
+
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+#ifdef HAVE_NDO_BUSY_POLL
+/* must be called with local_bh_disable()d */
+static int txgbe_busy_poll_recv(struct napi_struct *napi)
+{
+	struct txgbe_q_vector *q_vector =
+			container_of(napi, struct txgbe_q_vector, napi);
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	struct txgbe_ring  *ring;
+	int found = 0;
+
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return LL_FLUSH_FAILED;
+
+	if (!txgbe_qv_lock_poll(q_vector))
+		return LL_FLUSH_BUSY;
+
+	txgbe_for_each_ring(ring, q_vector->rx) {
+		found = txgbe_clean_rx_irq(q_vector, ring, 4);
+#ifdef BP_EXTENDED_STATS
+		if (found)
+			ring->stats.cleaned += found;
+		else
+			ring->stats.misses++;
+#endif
+		if (found)
+			break;
+	}
+
+	txgbe_qv_unlock_poll(q_vector);
+
+	return found;
+}
+
+#endif /* HAVE_NDO_BUSY_POLL */
+/**
+ * txgbe_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * txgbe_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void txgbe_configure_msix(struct txgbe_adapter *adapter)
+{
+	u16 v_idx;
+
+	/* Populate MSIX to EITR Select */
+	if (adapter->num_vfs >= 32) {
+		u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1;
+		wr32(&adapter->hw, TXGBE_PX_ITRSEL, eitrsel);
+	} else {
+		wr32(&adapter->hw, TXGBE_PX_ITRSEL, 0);
+	}
+
+	/*
+	 * Populate the IVAR table and set the ITR values to the
+	 * corresponding register.
+	 */
+	for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
+		struct txgbe_q_vector *q_vector = adapter->q_vector[v_idx];
+		struct txgbe_ring *ring;
+
+		txgbe_for_each_ring(ring, q_vector->rx)
+			txgbe_set_ivar(adapter, 0, ring->reg_idx, v_idx);
+
+		txgbe_for_each_ring(ring, q_vector->tx)
+			txgbe_set_ivar(adapter, 1, ring->reg_idx, v_idx);
+
+		txgbe_write_eitr(q_vector);
+	}
+
+	txgbe_set_ivar(adapter, -1, 0, v_idx);
+
+	wr32(&adapter->hw, TXGBE_PX_ITR(v_idx), 1950);
+}
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+/**
+ * txgbe_update_itr - update the dynamic ITR value based on statistics
+ * @q_vector: structure containing interrupt and ring information
+ * @ring_container: structure containing ring performance data
+ *
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.
+ *      this functionality is controlled by the InterruptThrottleRate module
+ *      parameter (see txgbe_param.c)
+ **/
+static void txgbe_update_itr(struct txgbe_q_vector *q_vector,
+			     struct txgbe_ring_container *ring_container)
+{
+	int bytes = ring_container->total_bytes;
+	int packets = ring_container->total_packets;
+	u32 timepassed_us;
+	u64 bytes_perint;
+	u8 itr_setting = ring_container->itr;
+
+	if (packets == 0)
+		return;
+
+	/* simple throttlerate management
+	 *   0-10MB/s   lowest (100000 ints/s)
+	 *  10-20MB/s   low    (20000 ints/s)
+	 *  20-1249MB/s bulk   (12000 ints/s)
+	 */
+	/* what was last interrupt timeslice? */
+	timepassed_us = q_vector->itr >> 2;
+	if (timepassed_us == 0)
+		return;
+	bytes_perint = bytes / timepassed_us; /* bytes/usec */
+
+	switch (itr_setting) {
+	case lowest_latency:
+		if (bytes_perint > 10) {
+			itr_setting = low_latency;
+		}
+		break;
+	case low_latency:
+		if (bytes_perint > 20) {
+			itr_setting = bulk_latency;
+		} else if (bytes_perint <= 10) {
+			itr_setting = lowest_latency;
+		}
+		break;
+	case bulk_latency:
+		if (bytes_perint <= 20) {
+			itr_setting = low_latency;
+		}
+		break;
+	}
+
+	/* clear work counters since we have the values we need */
+	ring_container->total_bytes = 0;
+	ring_container->total_packets = 0;
+
+	/* write updated itr to ring container */
+	ring_container->itr = itr_setting;
+}
+
+/**
+ * txgbe_write_eitr - write EITR register in hardware specific way
+ * @q_vector: structure containing interrupt and ring information
+ *
+ * This function is made to be called by ethtool and by the driver
+ * when it needs to update EITR registers at runtime.  Hardware
+ * specific quirks/differences are taken care of here.
+ */
+void txgbe_write_eitr(struct txgbe_q_vector *q_vector)
+{
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	struct txgbe_hw *hw = &adapter->hw;
+	int v_idx = q_vector->v_idx;
+	u32 itr_reg = q_vector->itr & TXGBE_MAX_EITR;
+
+	itr_reg |= TXGBE_PX_ITR_CNT_WDIS;
+
+	wr32(hw, TXGBE_PX_ITR(v_idx), itr_reg);
+}
+
+static void txgbe_set_itr(struct txgbe_q_vector *q_vector)
+{
+	u16 new_itr = q_vector->itr;
+	u8 current_itr;
+
+	txgbe_update_itr(q_vector, &q_vector->tx);
+	txgbe_update_itr(q_vector, &q_vector->rx);
+
+	current_itr = max(q_vector->rx.itr, q_vector->tx.itr);
+
+	switch (current_itr) {
+	/* counts and packets in update_itr are dependent on these numbers */
+	case lowest_latency:
+		new_itr = TXGBE_100K_ITR;
+		break;
+	case low_latency:
+		new_itr = TXGBE_20K_ITR;
+		break;
+	case bulk_latency:
+		new_itr = TXGBE_12K_ITR;
+		break;
+	default:
+		break;
+	}
+
+	if (new_itr != q_vector->itr) {
+		/* do an exponential smoothing */
+		new_itr = (10 * new_itr * q_vector->itr) /
+			  ((9 * new_itr) + q_vector->itr);
+
+		/* save the algorithm value here */
+		q_vector->itr = new_itr;
+
+		txgbe_write_eitr(q_vector);
+	}
+}
+
+/**
+ * txgbe_check_overtemp_subtask - check for over temperature
+ * @adapter: pointer to adapter
+ **/
+static void txgbe_check_overtemp_subtask(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 eicr = adapter->interrupt_event;
+	s32 temp_state;
+#ifdef HAVE_VIRTUAL_STATION
+	struct net_device *upper;
+	struct list_head *iter;
+#endif
+
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return;
+	if (!(adapter->flags2 & TXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+		return;
+	if (!(adapter->flags2 & TXGBE_FLAG2_TEMP_SENSOR_EVENT))
+		return;
+
+	adapter->flags2 &= ~TXGBE_FLAG2_TEMP_SENSOR_EVENT;
+
+	/*
+	 * Since the warning interrupt is for both ports
+	 * we don't have to check if:
+	 *  - This interrupt wasn't for our port.
+	 *  - We may have missed the interrupt so always have to
+	 *    check if we  got a LSC
+	 */
+	if (!(eicr & TXGBE_PX_MISC_IC_OVER_HEAT))
+		return;
+
+	temp_state = TCALL(hw, phy.ops.check_overtemp);
+	if (!temp_state || temp_state == TXGBE_NOT_IMPLEMENTED)
+		return;
+
+	if (temp_state == TXGBE_ERR_UNDERTEMP &&
+		test_bit(__TXGBE_HANGING, &adapter->state)) {
+		e_crit(drv, "%s\n", txgbe_underheat_msg);
+		wr32m(&adapter->hw, TXGBE_RDB_PB_CTL,
+				TXGBE_RDB_PB_CTL_RXEN, TXGBE_RDB_PB_CTL_RXEN);
+		netif_carrier_on(adapter->netdev);
+#ifdef HAVE_VIRTUAL_STATION
+		netdev_for_each_all_upper_dev_rcu(adapter->netdev,
+						  upper, iter) {
+			if (!netif_is_macvlan(upper))
+				continue;
+			netif_carrier_on(upper);
+		}
+#endif
+		clear_bit(__TXGBE_HANGING, &adapter->state);
+	} else if (temp_state == TXGBE_ERR_OVERTEMP &&
+		!test_and_set_bit(__TXGBE_HANGING, &adapter->state)) {
+		e_crit(drv, "%s\n", txgbe_overheat_msg);
+		netif_carrier_off(adapter->netdev);
+#ifdef HAVE_VIRTUAL_STATION
+		netdev_for_each_all_upper_dev_rcu(adapter->netdev,
+						  upper, iter) {
+			if (!netif_is_macvlan(upper))
+				continue;
+			netif_carrier_off(upper);
+		}
+#endif
+		wr32m(&adapter->hw, TXGBE_RDB_PB_CTL,
+					TXGBE_RDB_PB_CTL_RXEN, 0);
+	}
+
+	adapter->interrupt_event = 0;
+}
+
+static void txgbe_check_overtemp_event(struct txgbe_adapter *adapter, u32 eicr)
+{
+	if (!(adapter->flags2 & TXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+		return;
+
+	if (!(eicr & TXGBE_PX_MISC_IC_OVER_HEAT))
+		return;
+
+	if (!test_bit(__TXGBE_DOWN, &adapter->state)) {
+		adapter->interrupt_event = eicr;
+		adapter->flags2 |= TXGBE_FLAG2_TEMP_SENSOR_EVENT;
+		txgbe_service_event_schedule(adapter);
+	}
+}
+
+static void txgbe_check_sfp_event(struct txgbe_adapter *adapter, u32 eicr)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 eicr_mask = TXGBE_PX_MISC_IC_GPIO;
+	u32 reg;
+
+	if (eicr & eicr_mask) {
+		if (!test_bit(__TXGBE_DOWN, &adapter->state)) {
+			wr32(hw, TXGBE_GPIO_INTMASK, 0xFF);
+			reg = rd32(hw, TXGBE_GPIO_INTSTATUS);
+			if (reg & TXGBE_GPIO_INTSTATUS_2) {
+				adapter->flags2 |= TXGBE_FLAG2_SFP_NEEDS_RESET;
+				wr32(hw, TXGBE_GPIO_EOI,
+						TXGBE_GPIO_EOI_2);
+				adapter->sfp_poll_time = 0;
+				txgbe_service_event_schedule(adapter);
+			} 
+			if (reg & TXGBE_GPIO_INTSTATUS_3) {
+				adapter->flags |= TXGBE_FLAG_NEED_LINK_CONFIG;
+				wr32(hw, TXGBE_GPIO_EOI,
+						TXGBE_GPIO_EOI_3);
+				txgbe_service_event_schedule(adapter);
+			}
+
+			if (reg & TXGBE_GPIO_INTSTATUS_6) {
+				wr32(hw, TXGBE_GPIO_EOI,
+						TXGBE_GPIO_EOI_6);
+				adapter->flags |=
+					TXGBE_FLAG_NEED_LINK_CONFIG;
+				txgbe_service_event_schedule(adapter);
+			}
+			wr32(hw, TXGBE_GPIO_INTMASK, 0x0);
+		}
+	}
+}
+
+static void txgbe_check_lsc(struct txgbe_adapter *adapter)
+{
+	adapter->lsc_int++;
+	adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+	adapter->link_check_timeout = jiffies;
+	if (!test_bit(__TXGBE_DOWN, &adapter->state)) {
+		txgbe_service_event_schedule(adapter);
+	}
+}
+
+/**
+ * txgbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+void txgbe_irq_enable(struct txgbe_adapter *adapter, bool queues, bool flush)
+{
+	u32 mask = 0;
+	struct txgbe_hw *hw = &adapter->hw;
+	u8 device_type = hw->subsystem_device_id & 0xF0;
+
+	/* enable gpio interrupt */
+	if(device_type != TXGBE_ID_MAC_XAUI &&
+		device_type != TXGBE_ID_MAC_SGMII) {
+		mask |= TXGBE_GPIO_INTEN_2;
+		mask |= TXGBE_GPIO_INTEN_3;
+		mask |= TXGBE_GPIO_INTEN_6;
+	}
+	wr32(&adapter->hw, TXGBE_GPIO_INTEN, mask);
+
+	if(device_type != TXGBE_ID_MAC_XAUI &&
+		device_type != TXGBE_ID_MAC_SGMII) {
+		mask = TXGBE_GPIO_INTTYPE_LEVEL_2 | TXGBE_GPIO_INTTYPE_LEVEL_3 |
+			TXGBE_GPIO_INTTYPE_LEVEL_6;
+	}
+	wr32(&adapter->hw, TXGBE_GPIO_INTTYPE_LEVEL, mask);
+
+	/* enable misc interrupt */
+	mask = TXGBE_PX_MISC_IEN_MASK;
+
+	if (adapter->flags2 & TXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
+		mask |= TXGBE_PX_MISC_IEN_OVER_HEAT;
+
+	if ((adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE) &&
+	    !(adapter->flags2 & TXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+		mask |= TXGBE_PX_MISC_IEN_FLOW_DIR;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	mask |= TXGBE_PX_MISC_IEN_TIMESYNC;
+#endif /* HAVE_PTP_1588_CLOCK */
+
+	wr32(&adapter->hw, TXGBE_PX_MISC_IEN, mask);
+
+	/* unmask interrupt */
+	txgbe_intr_enable(&adapter->hw, TXGBE_INTR_MISC(adapter));
+	if (queues)
+		txgbe_intr_enable(&adapter->hw, TXGBE_INTR_QALL(adapter));
+
+	/* flush configuration */
+	if (flush)
+		TXGBE_WRITE_FLUSH(&adapter->hw);
+}
+
+static irqreturn_t txgbe_msix_other(int __always_unused irq, void *data)
+{
+	struct txgbe_adapter *adapter = data;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 eicr;
+	u32 ecc;
+	u32 value = 0;
+
+	eicr = txgbe_misc_isb(adapter, TXGBE_ISB_MISC);
+
+	if(BOND_CHECK_LINK_MODE == 1){
+		if (eicr & (TXGBE_PX_MISC_IC_ETH_LKDN)){
+			value = rd32(hw, 0x14404);
+			value = value & 0x1;
+			if(value == 0){
+				adapter->link_up = false;
+				adapter->flags2 |= TXGBE_FLAG2_LINK_DOWN;
+				txgbe_service_event_schedule(adapter);
+			}
+		}
+	} else {
+		if (eicr & (TXGBE_PX_MISC_IC_ETH_LK | TXGBE_PX_MISC_IC_ETH_LKDN))
+			txgbe_check_lsc(adapter);
+	}
+	if (eicr & TXGBE_PX_MISC_IC_ETH_AN){
+		if(adapter->backplane_an == 1 && (KR_POLLING == 0)){
+			value = txgbe_rd32_epcs(hw, 0x78002);
+			value = value & 0x4;
+			if( value == 0x4){
+				txgbe_kr_intr_handle(adapter);
+				adapter->flags2 |= TXGBE_FLAG2_KR_TRAINING;
+				txgbe_service_event_schedule(adapter);
+			}
+		}
+	}
+
+	if (eicr & TXGBE_PX_MISC_IC_VF_MBOX)
+		txgbe_msg_task(adapter);
+
+	if (eicr & TXGBE_PX_MISC_IC_PCIE_REQ_ERR) {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			"lan id %d, PCIe request error founded.\n", hw->bus.lan_id);
+		if (hw->bus.lan_id == 0) {
+			adapter->flags2 |= TXGBE_FLAG2_PCIE_NEED_RECOVER;
+			txgbe_service_event_schedule(adapter);
+		} else
+			wr32(&adapter->hw, TXGBE_MIS_PF_SM, 1);
+	}
+
+	if (eicr & TXGBE_PX_MISC_IC_INT_ERR) {
+		e_info(link, "Received unrecoverable ECC Err,"
+		       "initiating reset.\n");
+		ecc = rd32(hw, TXGBE_MIS_ST);
+		if (((ecc & TXGBE_MIS_ST_LAN0_ECC) && (hw->bus.lan_id == 0)) ||
+		    ((ecc & TXGBE_MIS_ST_LAN1_ECC) && (hw->bus.lan_id == 1)))
+			adapter->flags2 |= TXGBE_FLAG2_PF_RESET_REQUESTED;
+
+		txgbe_service_event_schedule(adapter);
+	}
+	if (eicr & TXGBE_PX_MISC_IC_DEV_RST) {
+		adapter->flags2 |= TXGBE_FLAG2_RESET_INTR_RECEIVED;
+		txgbe_service_event_schedule(adapter);
+	}
+	if ((eicr & TXGBE_PX_MISC_IC_STALL) ||
+		(eicr & TXGBE_PX_MISC_IC_ETH_EVENT)) {
+		adapter->flags2 |= TXGBE_FLAG2_PF_RESET_REQUESTED;
+		txgbe_service_event_schedule(adapter);
+	}
+
+#ifdef HAVE_TX_MQ
+	/* Handle Flow Director Full threshold interrupt */
+	if (eicr & TXGBE_PX_MISC_IC_FLOW_DIR) {
+		int reinit_count = 0;
+		int i;
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			struct txgbe_ring *ring = adapter->tx_ring[i];
+			if (test_and_clear_bit(__TXGBE_TX_FDIR_INIT_DONE,
+					      &ring->state))
+				reinit_count++;
+		}
+		if (reinit_count) {
+			/* no more flow director interrupts until after init */
+			wr32m(hw, TXGBE_PX_MISC_IEN,
+				TXGBE_PX_MISC_IEN_FLOW_DIR, 0);
+			adapter->flags2 |=
+				TXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+			txgbe_service_event_schedule(adapter);
+		}
+	}
+#endif
+	txgbe_check_sfp_event(adapter, eicr);
+	txgbe_check_overtemp_event(adapter, eicr);
+
+#ifdef HAVE_PTP_1588_CLOCK
+	if (unlikely(eicr & TXGBE_PX_MISC_IC_TIMESYNC))
+		txgbe_ptp_check_pps_event(adapter);
+#endif
+
+	/* re-enable the original interrupt state, no lsc, no queues */
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_enable(adapter, false, false);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t txgbe_msix_clean_rings(int __always_unused irq, void *data)
+{
+	struct txgbe_q_vector *q_vector = data;
+
+	/* EIAM disabled interrupts (on this vector) for us */
+
+	if (q_vector->rx.ring || q_vector->tx.ring)
+		napi_schedule_irqoff(&q_vector->napi);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * txgbe_poll - NAPI polling RX/TX cleanup routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function will clean all queues associated with a q_vector.
+ **/
+int txgbe_poll(struct napi_struct *napi, int budget)
+{
+	struct txgbe_q_vector *q_vector =
+			       container_of(napi, struct txgbe_q_vector, napi);
+	struct txgbe_adapter *adapter = q_vector->adapter;
+	struct txgbe_ring *ring;
+	int per_ring_budget;
+	bool clean_complete = true;
+
+#if IS_ENABLED(CONFIG_TPH)
+	if (adapter->flags & TXGBE_FLAG_TPH_ENABLED)
+		txgbe_update_tph(q_vector);
+#endif
+
+	txgbe_for_each_ring(ring, q_vector->tx) {
+		if (!txgbe_clean_tx_irq(q_vector, ring))
+			clean_complete = false;
+	}
+
+#ifdef HAVE_NDO_BUSY_POLL
+	if (test_bit(NAPI_STATE_NPSVC, &napi->state))
+		return budget;
+
+	if (!txgbe_qv_lock_napi(q_vector))
+		return budget;
+#endif
+
+	/* attempt to distribute budget to each queue fairly, but don't allow
+	 * the budget to go below 1 because we'll exit polling */
+	if (q_vector->rx.count > 1)
+		per_ring_budget = max(budget/q_vector->rx.count, 1);
+	else
+		per_ring_budget = budget;
+
+	txgbe_for_each_ring(ring, q_vector->rx) {
+		int cleaned = txgbe_clean_rx_irq(q_vector, ring,
+						 per_ring_budget);
+
+		if (cleaned >= per_ring_budget)
+			clean_complete = false;
+	}
+#ifdef HAVE_NDO_BUSY_POLL
+	txgbe_qv_unlock_napi(q_vector);
+#endif
+
+#ifndef HAVE_NETDEV_NAPI_LIST
+	if (!netif_running(adapter->netdev))
+		clean_complete = true;
+
+#endif
+	/* If all work not completed, return budget and keep polling */
+	if (!clean_complete)
+		return budget;
+
+	/* all work done, exit the polling mode */
+	napi_complete(napi);
+	if (adapter->rx_itr_setting == 1)
+		txgbe_set_itr(q_vector);
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_intr_enable(&adapter->hw,
+			TXGBE_INTR_Q(q_vector->v_idx));
+
+	return 0;
+}
+
+/**
+ * txgbe_request_msix_irqs - Initialize MSI-X interrupts
+ * @adapter: board private structure
+ *
+ * txgbe_request_msix_irqs allocates MSI-X vectors and requests
+ * interrupts from the kernel.
+ **/
+static int txgbe_request_msix_irqs(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int vector, err;
+	int ri = 0, ti = 0;
+
+	for (vector = 0; vector < adapter->num_q_vectors; vector++) {
+		struct txgbe_q_vector *q_vector = adapter->q_vector[vector];
+		struct msix_entry *entry = &adapter->msix_entries[vector];
+
+		if (q_vector->tx.ring && q_vector->rx.ring) {
+			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+				 "%s-TxRx-%d", netdev->name, ri++);
+			ti++;
+		} else if (q_vector->rx.ring) {
+			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+				 "%s-rx-%d", netdev->name, ri++);
+		} else if (q_vector->tx.ring) {
+			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+				 "%s-tx-%d", netdev->name, ti++);
+		} else {
+			/* skip this unused q_vector */
+			continue;
+		}
+		err = request_irq(entry->vector, &txgbe_msix_clean_rings, 0,
+				  q_vector->name, q_vector);
+		if (err) {
+			e_err(probe, "request_irq failed for MSIX interrupt"
+			      " '%s' Error: %d\n", q_vector->name, err);
+			goto free_queue_irqs;
+		}
+#ifdef HAVE_IRQ_AFFINITY_HINT
+		/* If Flow Director is enabled, set interrupt affinity */
+		if (adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE) {
+			/* assign the mask for this irq */
+			irq_set_affinity_hint(entry->vector,
+					      &q_vector->affinity_mask);
+		}
+#endif /* HAVE_IRQ_AFFINITY_HINT */
+	}
+
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  txgbe_msix_other, 0, netdev->name, adapter);
+	if (err) {
+		e_err(probe, "request_irq for msix_other failed: %d\n", err);
+		goto free_queue_irqs;
+	}
+
+	return 0;
+
+free_queue_irqs:
+	while (vector) {
+		vector--;
+#ifdef HAVE_IRQ_AFFINITY_HINT
+		irq_set_affinity_hint(adapter->msix_entries[vector].vector,
+				      NULL);
+#endif
+		free_irq(adapter->msix_entries[vector].vector,
+			 adapter->q_vector[vector]);
+	}
+	adapter->flags &= ~TXGBE_FLAG_MSIX_ENABLED;
+	pci_disable_msix(adapter->pdev);
+	kfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+	return err;
+}
+
+/**
+ * txgbe_intr - legacy mode Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t txgbe_intr(int __always_unused irq, void *data)
+{
+	struct txgbe_adapter *adapter = data;
+	struct txgbe_q_vector *q_vector = adapter->q_vector[0];
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 eicr_misc;
+	u32 value ;
+	u16 pci_value;
+	
+	if (!(adapter->flags & TXGBE_FLAG_MSI_ENABLED)) {
+		pci_read_config_word(adapter->pdev, PCI_STATUS, &pci_value);
+		if (!(pci_value & PCI_STATUS_INTERRUPT))
+			return IRQ_HANDLED;        /* Not our interrupt */
+		wr32(&(adapter->hw), TXGBE_PX_INTA, 1);
+	}
+	
+	eicr_misc = txgbe_misc_isb(adapter, TXGBE_ISB_MISC);
+	if(BOND_CHECK_LINK_MODE == 1){
+		if (eicr_misc & (TXGBE_PX_MISC_IC_ETH_LKDN)){
+			value = rd32(hw, 0x14404);
+			value = value & 0x1;
+			if(value == 0){
+				adapter->link_up = false;
+				adapter->flags2 |= TXGBE_FLAG2_LINK_DOWN;
+				txgbe_service_event_schedule(adapter);
+			}
+		}
+	} else {
+		if (eicr_misc & (TXGBE_PX_MISC_IC_ETH_LK | TXGBE_PX_MISC_IC_ETH_LKDN))
+			txgbe_check_lsc(adapter);
+	}
+
+	if (eicr_misc & TXGBE_PX_MISC_IC_ETH_AN){
+		if(adapter->backplane_an == 1 && (KR_POLLING == 0)){
+			value = txgbe_rd32_epcs(hw, 0x78002);
+			value = value & 0x4;
+			if( value == 0x4){
+				txgbe_kr_intr_handle(adapter);
+				adapter->flags2 |= TXGBE_FLAG2_KR_TRAINING;
+				txgbe_service_event_schedule(adapter);
+			}
+		}
+	}
+
+	if (eicr_misc & TXGBE_PX_MISC_IC_INT_ERR) {
+		e_info(link, "Received unrecoverable ECC Err,"
+			"initiating reset.\n");
+		adapter->flags2 |= TXGBE_FLAG2_GLOBAL_RESET_REQUESTED;
+		txgbe_service_event_schedule(adapter);
+	}
+
+	if (eicr_misc & TXGBE_PX_MISC_IC_DEV_RST) {
+		adapter->flags2 |= TXGBE_FLAG2_RESET_INTR_RECEIVED;
+		txgbe_service_event_schedule(adapter);
+	}
+	txgbe_check_sfp_event(adapter, eicr_misc);
+	txgbe_check_overtemp_event(adapter, eicr_misc);
+
+#ifdef HAVE_PTP_1588_CLOCK
+	if (unlikely(eicr_misc & TXGBE_PX_MISC_IC_TIMESYNC))
+		txgbe_ptp_check_pps_event(adapter);
+#endif
+	adapter->isb_mem[TXGBE_ISB_MISC] = 0;
+	/* would disable interrupts here but it is auto disabled */
+	napi_schedule_irqoff(&q_vector->napi);
+
+	/*
+	 * re-enable link(maybe) and non-queue interrupts, no flush.
+	 * txgbe_poll will re-enable the queue interrupts
+	 */
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_enable(adapter, false, false);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * txgbe_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int txgbe_request_irq(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err;
+
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED)
+		err = txgbe_request_msix_irqs(adapter);
+	else if (adapter->flags & TXGBE_FLAG_MSI_ENABLED)
+		err = request_irq(adapter->pdev->irq, &txgbe_intr, 0,
+				  netdev->name, adapter);
+	else
+		err = request_irq(adapter->pdev->irq, &txgbe_intr, IRQF_SHARED,
+				  netdev->name, adapter);
+
+	if (err)
+		e_err(probe, "request_irq failed, Error %d\n", err);
+
+	return err;
+}
+
+static void txgbe_free_irq(struct txgbe_adapter *adapter)
+{
+	int vector;
+
+	if (!(adapter->flags & TXGBE_FLAG_MSIX_ENABLED)) {
+		free_irq(adapter->pdev->irq, adapter);
+		return;
+	}
+
+	for (vector = 0; vector < adapter->num_q_vectors; vector++) {
+		struct txgbe_q_vector *q_vector = adapter->q_vector[vector];
+		struct msix_entry *entry = &adapter->msix_entries[vector];
+
+		/* free only the irqs that were actually requested */
+		if (!q_vector->rx.ring && !q_vector->tx.ring)
+			continue;
+
+#ifdef HAVE_IRQ_AFFINITY_HINT
+		/* clear the affinity_mask in the IRQ descriptor */
+		irq_set_affinity_hint(entry->vector, NULL);
+
+#endif
+		free_irq(entry->vector, q_vector);
+	}
+
+	free_irq(adapter->msix_entries[vector++].vector, adapter);
+}
+
+/**
+ * txgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+void txgbe_irq_disable(struct txgbe_adapter *adapter)
+{
+	wr32(&adapter->hw, TXGBE_PX_MISC_IEN, 0);
+	txgbe_intr_disable(&adapter->hw, TXGBE_INTR_ALL);
+
+	TXGBE_WRITE_FLUSH(&adapter->hw);
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED) {
+		int vector;
+
+		for (vector = 0; vector < adapter->num_q_vectors; vector++)
+			synchronize_irq(adapter->msix_entries[vector].vector);
+
+		synchronize_irq(adapter->msix_entries[vector++].vector);
+	} else {
+		synchronize_irq(adapter->pdev->irq);
+	}
+}
+
+/**
+ * txgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
+ *
+ **/
+static void txgbe_configure_msi_and_legacy(struct txgbe_adapter *adapter)
+{
+	struct txgbe_q_vector *q_vector = adapter->q_vector[0];
+	struct txgbe_ring *ring;
+
+	txgbe_write_eitr(q_vector);
+
+	txgbe_for_each_ring(ring, q_vector->rx)
+		txgbe_set_ivar(adapter, 0, ring->reg_idx, 0);
+
+	txgbe_for_each_ring(ring, q_vector->tx)
+		txgbe_set_ivar(adapter, 1, ring->reg_idx, 0);
+
+	txgbe_set_ivar(adapter, -1, 0, 1);
+
+	e_info(hw, "Legacy interrupt IVAR setup done\n");
+}
+
+/**
+ * txgbe_configure_tx_ring - Configure Tx ring after Reset
+ * @adapter: board private structure
+ * @ring: structure containing ring specific data
+ *
+ * Configure the Tx descriptor ring after a reset.
+ **/
+void txgbe_configure_tx_ring(struct txgbe_adapter *adapter,
+			     struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u64 tdba = ring->dma;
+	int wait_loop = 10;
+	u32 txdctl = TXGBE_PX_TR_CFG_ENABLE;
+	u8 reg_idx = ring->reg_idx;
+
+	/* disable queue to avoid issues while updating state */
+	wr32(hw, TXGBE_PX_TR_CFG(reg_idx), TXGBE_PX_TR_CFG_SWFLSH);
+	TXGBE_WRITE_FLUSH(hw);
+
+	wr32(hw, TXGBE_PX_TR_BAL(reg_idx), tdba & DMA_BIT_MASK(32));
+	wr32(hw, TXGBE_PX_TR_BAH(reg_idx), tdba >> 32);
+
+	/* reset head and tail pointers */
+	wr32(hw, TXGBE_PX_TR_RP(reg_idx), 0);
+	wr32(hw, TXGBE_PX_TR_WP(reg_idx), 0);
+	ring->tail = adapter->io_addr + TXGBE_PX_TR_WP(reg_idx);
+
+	/* reset ntu and ntc to place SW in sync with hardwdare */
+	ring->next_to_clean = 0;
+	ring->next_to_use = 0;
+
+	txdctl |= TXGBE_RING_SIZE(ring) << TXGBE_PX_TR_CFG_TR_SIZE_SHIFT;
+
+	/*
+	 * set WTHRESH to encourage burst writeback, it should not be set
+	 * higher than 1 when:
+	 * - ITR is 0 as it could cause false TX hangs
+	 * - ITR is set to > 100k int/sec and BQL is enabled
+	 *
+	 * In order to avoid issues WTHRESH + PTHRESH should always be equal
+	 * to or less than the number of on chip descriptors, which is
+	 * currently 40.
+	 */
+
+	txdctl |= 0x20 << TXGBE_PX_TR_CFG_WTHRESH_SHIFT;
+
+	/* reinitialize flowdirector state */
+	if (adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE) {
+		ring->atr_sample_rate = adapter->atr_sample_rate;
+		ring->atr_count = 0;
+		set_bit(__TXGBE_TX_FDIR_INIT_DONE, &ring->state);
+	} else {
+		ring->atr_sample_rate = 0;
+	}
+
+	/* initialize XPS */
+	if (!test_and_set_bit(__TXGBE_TX_XPS_INIT_DONE, &ring->state)) {
+		struct txgbe_q_vector *q_vector = ring->q_vector;
+
+		if (q_vector)
+			netif_set_xps_queue(adapter->netdev,
+					    &q_vector->affinity_mask,
+					    ring->queue_index);
+	}
+
+	clear_bit(__TXGBE_HANG_CHECK_ARMED, &ring->state);
+
+	/* enable queue */
+	wr32(hw, TXGBE_PX_TR_CFG(reg_idx), txdctl);
+
+
+	/* poll to verify queue is enabled */
+	do {
+		msleep(1);
+		txdctl = rd32(hw, TXGBE_PX_TR_CFG(reg_idx));
+	} while (--wait_loop && !(txdctl & TXGBE_PX_TR_CFG_ENABLE));
+	if (!wait_loop)
+		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+}
+
+
+
+/**
+ * txgbe_configure_tx - Configure Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void txgbe_configure_tx(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i;
+
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+	if (adapter->num_tx_queues > 1)
+		adapter->netdev->features |= NETIF_F_MULTI_QUEUE;
+	else
+		adapter->netdev->features &= ~NETIF_F_MULTI_QUEUE;
+#endif
+
+	/* TDM_CTL.TE must be before Tx queues are enabled */
+	wr32m(hw, TXGBE_TDM_CTL,
+		TXGBE_TDM_CTL_TE, TXGBE_TDM_CTL_TE);
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		txgbe_configure_tx_ring(adapter, adapter->tx_ring[i]);
+
+	wr32m(hw, TXGBE_TSC_BUF_AE, 0x3FF, 0x10);
+	/* enable mac transmitter */
+	wr32m(hw, TXGBE_MAC_TX_CFG,
+		TXGBE_MAC_TX_CFG_TE, TXGBE_MAC_TX_CFG_TE);
+}
+
+static void txgbe_enable_rx_drop(struct txgbe_adapter *adapter,
+				 struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 reg_idx = ring->reg_idx;
+
+	u32 srrctl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+
+	srrctl |= TXGBE_PX_RR_CFG_DROP_EN;
+
+	wr32(hw, TXGBE_PX_RR_CFG(reg_idx), srrctl);
+}
+
+static void txgbe_disable_rx_drop(struct txgbe_adapter *adapter,
+				  struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 reg_idx = ring->reg_idx;
+
+	u32 srrctl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+
+	srrctl &= ~TXGBE_PX_RR_CFG_DROP_EN;
+
+	wr32(hw, TXGBE_PX_RR_CFG(reg_idx), srrctl);
+}
+
+void txgbe_set_rx_drop_en(struct txgbe_adapter *adapter)
+{
+	int i;
+	bool pfc_en = adapter->dcb_cfg.pfc_mode_enable;
+
+#ifdef HAVE_DCBNL_IEEE
+	if (adapter->txgbe_ieee_pfc)
+		pfc_en |= !!(adapter->txgbe_ieee_pfc->pfc_en);
+
+#endif
+	/*
+	 * We should set the drop enable bit if:
+	 *  SR-IOV is enabled
+	 *   or
+	 *  Number of Rx queues > 1 and flow control is disabled
+	 *
+	 *  This allows us to avoid head of line blocking for security
+	 *  and performance reasons.
+	 */
+	if (adapter->num_vfs || (adapter->num_rx_queues > 1 &&
+	    !(adapter->hw.fc.current_mode & txgbe_fc_tx_pause) && !pfc_en)) {
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			txgbe_enable_rx_drop(adapter, adapter->rx_ring[i]);
+	} else {
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			txgbe_disable_rx_drop(adapter, adapter->rx_ring[i]);
+	}
+}
+
+static void txgbe_configure_srrctl(struct txgbe_adapter *adapter,
+	struct txgbe_ring *rx_ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 srrctl;
+	u16 reg_idx = rx_ring->reg_idx;
+
+	srrctl = rd32m(hw, TXGBE_PX_RR_CFG(reg_idx),
+			~(TXGBE_PX_RR_CFG_RR_HDR_SZ |
+			  TXGBE_PX_RR_CFG_RR_BUF_SZ |
+			  TXGBE_PX_RR_CFG_SPLIT_MODE));
+	/* configure header buffer length, needed for RSC */
+	srrctl |= TXGBE_RX_HDR_SIZE << TXGBE_PX_RR_CFG_BSIZEHDRSIZE_SHIFT;
+
+	/* configure the packet buffer length */
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	srrctl |= ALIGN(rx_ring->rx_buf_len, 1024) >>
+		  TXGBE_PX_RR_CFG_BSIZEPKT_SHIFT;
+#else
+	srrctl |= txgbe_rx_bufsz(rx_ring) >> TXGBE_PX_RR_CFG_BSIZEPKT_SHIFT;
+	if (ring_is_hs_enabled(rx_ring))
+		srrctl |= TXGBE_PX_RR_CFG_SPLIT_MODE;
+#endif
+
+	wr32(hw, TXGBE_PX_RR_CFG(reg_idx), srrctl);
+}
+
+/**
+ * Return a number of entries in the RSS indirection table
+ *
+ * @adapter: device handle
+ *
+ */
+u32 txgbe_rss_indir_tbl_entries(struct txgbe_adapter *adapter)
+{
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED)
+		return 128;
+	else
+		return 128;
+}
+
+/**
+ * Write the RETA table to HW
+ *
+ * @adapter: device handle
+ *
+ * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
+ */
+void txgbe_store_reta(struct txgbe_adapter *adapter)
+{
+	u32 i, reta_entries = txgbe_rss_indir_tbl_entries(adapter);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 reta = 0;
+	u8 *indir_tbl = adapter->rss_indir_tbl;
+
+	/* Fill out the redirection table as follows:
+	 *  - 8 bit wide entries containing 4 bit RSS index
+	 */
+
+	/* Write redirection table to HW */
+	for (i = 0; i < reta_entries; i++) {
+		reta |= indir_tbl[i] << (i & 0x3) * 8;
+		if ((i & 3) == 3) {
+			wr32(hw, TXGBE_RDB_RSSTBL(i >> 2), reta);
+			reta = 0;
+		}
+	}
+}
+
+/**
+ * Write the RETA table to HW (for devices in SRIOV mode)
+ *
+ * @adapter: device handle
+ *
+ * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
+ */
+static void txgbe_store_vfreta(struct txgbe_adapter *adapter)
+{
+	u32 i, reta_entries = txgbe_rss_indir_tbl_entries(adapter);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 vfreta = 0;
+	unsigned int pf_pool = adapter->num_vfs;
+
+	/* Write redirection table to HW */
+	for (i = 0; i < reta_entries; i++) {
+		vfreta |= (u32)adapter->rss_indir_tbl[i] << (i & 0x3) * 8;
+		if ((i & 3) == 3) {
+			wr32(hw, TXGBE_RDB_VMRSSTBL(i >> 2, pf_pool),
+					vfreta);
+			vfreta = 0;
+		}
+	}
+}
+
+static void txgbe_setup_reta(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i, j;
+	u32 reta_entries = txgbe_rss_indir_tbl_entries(adapter);
+	u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+
+	/*
+	 * Program table for at least 4 queues w/ SR-IOV so that VFs can
+	 * make full use of any rings they may have.  We will use the
+	 * PSRTYPE register to control how many rings we use within the PF.
+	 */
+	if ((adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) && (rss_i < 2))
+		rss_i = 2;
+
+	/* Fill out hash function seeds */
+	for (i = 0; i < 10; i++)
+		wr32(hw, TXGBE_RDB_RSSRK(i), adapter->rss_key[i]);
+
+	/* Fill out redirection table */
+	memset(adapter->rss_indir_tbl, 0, sizeof(adapter->rss_indir_tbl));
+
+	for (i = 0, j = 0; i < reta_entries; i++, j++) {
+		if (j == rss_i)
+			j = 0;
+
+		adapter->rss_indir_tbl[i] = j;
+	}
+
+	txgbe_store_reta(adapter);
+}
+
+static void txgbe_setup_vfreta(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+	unsigned int pf_pool = adapter->num_vfs;
+	int i, j;
+
+	/* Fill out hash function seeds */
+	for (i = 0; i < 10; i++)
+		wr32(hw, TXGBE_RDB_VMRSSRK(i, pf_pool),
+				adapter->rss_key[i]);
+
+	/* Fill out the redirection table */
+	for (i = 0, j = 0; i < 64; i++, j++) {
+		if (j == rss_i)
+			j = 0;
+
+		adapter->rss_indir_tbl[i] = j;
+	}
+
+	txgbe_store_vfreta(adapter);
+}
+
+static void txgbe_setup_mrqc(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 rss_field = 0;
+
+	/* VT, DCB and RSS do not coexist at the same time */
+	if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED &&
+	    adapter->flags & TXGBE_FLAG_DCB_ENABLED)
+		return;
+
+	/* Disable indicating checksum in descriptor, enables RSS hash */
+	wr32m(hw, TXGBE_PSR_CTL,
+		TXGBE_PSR_CTL_PCSD, TXGBE_PSR_CTL_PCSD);
+
+	/* Perform hash on these packet types */
+	rss_field = TXGBE_RDB_RA_CTL_RSS_IPV4 |
+		    TXGBE_RDB_RA_CTL_RSS_IPV4_TCP |
+		    TXGBE_RDB_RA_CTL_RSS_IPV6 |
+		    TXGBE_RDB_RA_CTL_RSS_IPV6_TCP;
+
+	if (adapter->flags2 & TXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
+		rss_field |= TXGBE_RDB_RA_CTL_RSS_IPV4_UDP;
+	if (adapter->flags2 & TXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
+		rss_field |= TXGBE_RDB_RA_CTL_RSS_IPV6_UDP;
+
+	netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+	
+	if (0)
+		txgbe_setup_vfreta(adapter);
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+		/*wait to fix txgbe_setup_vfreta(adapter);*/
+		txgbe_setup_reta(adapter);
+	} else {
+		txgbe_setup_reta(adapter);
+	}
+
+	/* Consistent with the X710 that vf do not make its own receive-hash rules */
+	//rss_field |= TXGBE_RDB_RA_CTL_MULTI_RSS;
+
+	if (adapter->flags2 & TXGBE_FLAG2_RSS_ENABLED)
+		rss_field |= TXGBE_RDB_RA_CTL_RSS_EN;
+		
+	wr32(hw, TXGBE_RDB_RA_CTL, rss_field);
+}
+
+/**
+ * txgbe_clear_rscctl - disable RSC for the indicated ring
+ * @adapter: address of board private structure
+ * @ring: structure containing ring specific data
+ **/
+void txgbe_clear_rscctl(struct txgbe_adapter *adapter,
+			struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u8 reg_idx = ring->reg_idx;
+
+	wr32m(hw, TXGBE_PX_RR_CFG(reg_idx),
+		TXGBE_PX_RR_CFG_RSC, 0);
+
+	clear_ring_rsc_enabled(ring);
+}
+
+/**
+ * txgbe_configure_rscctl - enable RSC for the indicated ring
+ * @adapter:    address of board private structure
+ * @ring: structure containing ring specific data
+ **/
+void txgbe_configure_rscctl(struct txgbe_adapter *adapter,
+			    struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 rscctrl;
+	u8 reg_idx = ring->reg_idx;
+
+	if (!ring_is_rsc_enabled(ring))
+		return;
+
+	rscctrl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+	rscctrl |= TXGBE_PX_RR_CFG_RSC;
+	/*
+	 * we must limit the number of descriptors so that the
+	 * total size of max desc * buf_len is not greater
+	 * than 65536
+	 */
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+#if (MAX_SKB_FRAGS >= 16)
+	rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_16;
+#elif (MAX_SKB_FRAGS >= 8)
+	rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_8;
+#elif (MAX_SKB_FRAGS >= 4)
+	rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_4;
+#else
+	rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_1;
+#endif
+#else /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+	if (ring->rx_buf_len <= TXGBE_RXBUFFER_4K)
+		rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_16;
+	else if (ring->rx_buf_len <= TXGBE_RXBUFFER_8K)
+		rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_8;
+	else
+		rscctrl |= TXGBE_PX_RR_CFG_MAX_RSCBUF_4;
+#endif /* !CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+	wr32(hw, TXGBE_PX_RR_CFG(reg_idx), rscctrl);
+}
+
+static void txgbe_rx_desc_queue_enable(struct txgbe_adapter *adapter,
+				       struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int wait_loop = TXGBE_MAX_RX_DESC_POLL;
+	u32 rxdctl;
+	u8 reg_idx = ring->reg_idx;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return;
+
+	do {
+		msleep(1);
+		rxdctl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+	} while (--wait_loop && !(rxdctl & TXGBE_PX_RR_CFG_RR_EN));
+
+	if (!wait_loop) {
+		e_err(drv, "RXDCTL.ENABLE on Rx queue %d "
+		      "not set within the polling period\n", reg_idx);
+	}
+}
+
+/* disable the specified tx ring/queue */
+void txgbe_disable_tx_queue(struct txgbe_adapter *adapter,
+			    struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int wait_loop = TXGBE_MAX_RX_DESC_POLL;
+	u32 rxdctl, reg_offset, enable_mask;
+	u8 reg_idx = ring->reg_idx;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return;
+
+	reg_offset = TXGBE_PX_TR_CFG(reg_idx);
+	enable_mask = TXGBE_PX_TR_CFG_ENABLE;
+
+	/* write value back with TDCFG.ENABLE bit cleared */
+	wr32m(hw, reg_offset, enable_mask, 0);
+
+	/* the hardware may take up to 100us to really disable the tx queue */
+	do {
+		udelay(10);
+		rxdctl = rd32(hw, reg_offset);
+	} while (--wait_loop && (rxdctl & enable_mask));
+
+	if (!wait_loop) {
+		e_err(drv, "TDCFG.ENABLE on Tx queue %d not cleared within "
+			  "the polling period\n", reg_idx);
+	}
+}
+
+/* disable the specified rx ring/queue */
+void txgbe_disable_rx_queue(struct txgbe_adapter *adapter,
+			    struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int wait_loop = TXGBE_MAX_RX_DESC_POLL;
+	u32 rxdctl;
+	u8 reg_idx = ring->reg_idx;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return;
+
+	/* write value back with RXDCTL.ENABLE bit cleared */
+	wr32m(hw, TXGBE_PX_RR_CFG(reg_idx),
+		TXGBE_PX_RR_CFG_RR_EN, 0);
+
+	/* the hardware may take up to 100us to really disable the rx queue */
+	do {
+		udelay(10);
+		rxdctl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+	} while (--wait_loop && (rxdctl & TXGBE_PX_RR_CFG_RR_EN));
+
+	if (!wait_loop) {
+		e_err(drv, "RXDCTL.ENABLE on Rx queue %d not cleared within "
+		      "the polling period\n", reg_idx);
+	}
+}
+
+void txgbe_configure_rx_ring(struct txgbe_adapter *adapter,
+			     struct txgbe_ring *ring)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u64 rdba = ring->dma;
+	u32 rxdctl;
+	u16 reg_idx = ring->reg_idx;
+
+	/* disable queue to avoid issues while updating state */
+	rxdctl = rd32(hw, TXGBE_PX_RR_CFG(reg_idx));
+	txgbe_disable_rx_queue(adapter, ring);
+
+	wr32(hw, TXGBE_PX_RR_BAL(reg_idx), rdba & DMA_BIT_MASK(32));
+	wr32(hw, TXGBE_PX_RR_BAH(reg_idx), rdba >> 32);
+
+	if (ring->count == TXGBE_MAX_RXD)
+		rxdctl |= 0 << TXGBE_PX_RR_CFG_RR_SIZE_SHIFT;
+	else
+		rxdctl |= (ring->count / 128) << TXGBE_PX_RR_CFG_RR_SIZE_SHIFT;
+
+	rxdctl |= 0x1 << TXGBE_PX_RR_CFG_RR_THER_SHIFT;
+	wr32(hw, TXGBE_PX_RR_CFG(reg_idx), rxdctl);
+
+	/* reset head and tail pointers */
+	wr32(hw, TXGBE_PX_RR_RP(reg_idx), 0);
+	wr32(hw, TXGBE_PX_RR_WP(reg_idx), 0);
+	ring->tail = adapter->io_addr + TXGBE_PX_RR_WP(reg_idx);
+
+	/* reset ntu and ntc to place SW in sync with hardwdare */
+	ring->next_to_clean = 0;
+	ring->next_to_use = 0;
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	ring->next_to_alloc = 0;
+#endif
+
+	txgbe_configure_srrctl(adapter, ring);
+	/* In ESX, RSCCTL configuration is done by on demand */
+	txgbe_configure_rscctl(adapter, ring);
+
+	/* enable receive descriptor ring */
+	wr32m(hw, TXGBE_PX_RR_CFG(reg_idx),
+		TXGBE_PX_RR_CFG_RR_EN, TXGBE_PX_RR_CFG_RR_EN);
+
+	txgbe_rx_desc_queue_enable(adapter, ring);
+	txgbe_alloc_rx_buffers(ring, txgbe_desc_unused(ring));
+}
+
+static void txgbe_setup_psrtype(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int rss_i = adapter->ring_feature[RING_F_RSS].indices;
+	int pool;
+
+	/* PSRTYPE must be initialized in adapters */
+	u32 psrtype = TXGBE_RDB_PL_CFG_L4HDR |
+		      TXGBE_RDB_PL_CFG_L3HDR |
+		      TXGBE_RDB_PL_CFG_L2HDR |
+		      TXGBE_RDB_PL_CFG_TUN_OUTER_L2HDR |
+		      TXGBE_RDB_PL_CFG_TUN_TUNHDR;
+
+
+	if (rss_i > 3)
+		psrtype |= 2 << 29;
+	else if (rss_i > 1)
+		psrtype |= 1 << 29;
+
+	for_each_set_bit(pool, &adapter->fwd_bitmask, TXGBE_MAX_MACVLANS)
+		wr32(hw, TXGBE_RDB_PL_CFG(VMDQ_P(pool)), psrtype);
+}
+
+/**
+ * txgbe_configure_bridge_mode - common settings for configuring bridge mode
+ * @adapter - the private structure
+ *
+ * This function's purpose is to remove code duplication and configure some
+ * settings require to switch bridge modes.
+ **/
+static void txgbe_configure_bridge_mode(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	unsigned int p;
+
+	if (adapter->flags & TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE) {
+		/* disable Tx loopback, rely on switch hairpin mode */
+		wr32m(hw, TXGBE_PSR_CTL,
+			TXGBE_PSR_CTL_SW_EN, 0);
+
+		/* enable Rx source address pruning. Note, this requires
+		 * replication to be enabled or else it does nothing.
+		 */
+		for (p = 0; p < adapter->num_vfs; p++) {
+			TCALL(hw, mac.ops.set_source_address_pruning, true, p);
+		}
+
+		for_each_set_bit(p, &adapter->fwd_bitmask, TXGBE_MAX_MACVLANS) {
+			TCALL(hw, mac.ops.set_source_address_pruning, true, VMDQ_P(p));
+		}
+	} else {
+		/* enable Tx loopback for internal VF/PF communication */
+		wr32m(hw, TXGBE_PSR_CTL,
+			TXGBE_PSR_CTL_SW_EN, TXGBE_PSR_CTL_SW_EN);
+
+		/* disable Rx source address pruning, since we don't expect to
+		 * be receiving external loopback of our transmitted frames.
+		 */
+		for (p = 0; p < adapter->num_vfs; p++) {
+			TCALL(hw, mac.ops.set_source_address_pruning, false, p);
+		}
+
+		for_each_set_bit(p, &adapter->fwd_bitmask, TXGBE_MAX_MACVLANS) {
+			TCALL(hw, mac.ops.set_source_address_pruning, false, VMDQ_P(p));
+		}
+	}
+}
+
+static void txgbe_configure_virtualization(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 reg_offset, vf_shift;
+	u32 i;
+
+	if (!(adapter->flags & TXGBE_FLAG_VMDQ_ENABLED))
+		return;
+
+	wr32m(hw, TXGBE_PSR_VM_CTL,
+		TXGBE_PSR_VM_CTL_POOL_MASK |
+		TXGBE_PSR_VM_CTL_REPLEN,
+		VMDQ_P(0) << TXGBE_PSR_VM_CTL_POOL_SHIFT |
+		TXGBE_PSR_VM_CTL_REPLEN);
+
+	for_each_set_bit(i, &adapter->fwd_bitmask, TXGBE_MAX_MACVLANS) {
+		/* accept untagged packets until a vlan tag is
+		 * specifically set for the VMDQ queue/pool
+		 */
+		wr32m(hw, TXGBE_PSR_VM_L2CTL(i),
+			TXGBE_PSR_VM_L2CTL_AUPE, TXGBE_PSR_VM_L2CTL_AUPE);
+	}
+
+	vf_shift = VMDQ_P(0) % 32;
+	reg_offset = (VMDQ_P(0) >= 32) ? 1 : 0;
+
+	/* Enable only the PF pools for Tx/Rx */
+	wr32(hw, TXGBE_RDM_VF_RE(reg_offset), (~0) << vf_shift);
+	wr32(hw, TXGBE_RDM_VF_RE(reg_offset ^ 1), reg_offset - 1);
+	wr32(hw, TXGBE_TDM_VF_TE(reg_offset), (~0) << vf_shift);
+	wr32(hw, TXGBE_TDM_VF_TE(reg_offset ^ 1), reg_offset - 1);
+
+	if (!(adapter->flags & TXGBE_FLAG_SRIOV_ENABLED))
+		return;
+
+	/* configure default bridge settings */
+	txgbe_configure_bridge_mode(adapter);
+
+	/* Ensure LLDP and FC is set for Ethertype Antispoofing if we will be
+	 * calling set_ethertype_anti_spoofing for each VF in loop below.
+	 */
+	if (hw->mac.ops.set_ethertype_anti_spoofing) {
+		wr32(hw,
+			TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_LLDP),
+			(TXGBE_PSR_ETYPE_SWC_FILTER_EN    | /* enable filter */
+			 TXGBE_PSR_ETYPE_SWC_TX_ANTISPOOF |
+			 TXGBE_ETH_P_LLDP));       /* LLDP eth procotol type */
+
+		wr32(hw,
+			TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_FC),
+			(TXGBE_PSR_ETYPE_SWC_FILTER_EN    |
+			 TXGBE_PSR_ETYPE_SWC_TX_ANTISPOOF |
+			 ETH_P_PAUSE));
+	}
+
+	for (i = 0; i < adapter->num_vfs; i++) {
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+		if (!adapter->vfinfo[i].spoofchk_enabled)
+			txgbe_ndo_set_vf_spoofchk(adapter->netdev, i, false);
+#endif
+		/* enable ethertype anti spoofing if hw supports it */
+		TCALL(hw, mac.ops.set_ethertype_anti_spoofing, true, i);
+	}
+}
+
+static void txgbe_set_rx_buffer_len(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	u32 max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	struct txgbe_ring *rx_ring;
+	int i;
+	u32 mhadd;
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	u16 rx_buf_len;
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* adjust max frame to be able to do baby jumbo for FCoE */
+	if ((adapter->flags & TXGBE_FLAG_FCOE_ENABLED) &&
+	    (max_frame < TXGBE_FCOE_JUMBO_FRAME_SIZE))
+		max_frame = TXGBE_FCOE_JUMBO_FRAME_SIZE;
+#endif /* CONFIG_FCOE */
+
+	/* adjust max frame to be at least the size of a standard frame */
+	if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN))
+		max_frame = (ETH_FRAME_LEN + ETH_FCS_LEN);
+
+	mhadd = rd32(hw, TXGBE_PSR_MAX_SZ);
+	if (max_frame != mhadd) {
+		wr32(hw, TXGBE_PSR_MAX_SZ, max_frame);
+	}
+
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	/* MHADD will allow an extra 4 bytes past for vlan tagged frames */
+	max_frame += VLAN_HLEN;
+
+	if (!(adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED) &&
+	    (max_frame <= MAXIMUM_ETHERNET_VLAN_SIZE)) {
+		rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+	/*
+	 * Make best use of allocation by using all but 1K of a
+	 * power of 2 allocation that will be used for skb->head.
+	 */
+	} else if (max_frame <= TXGBE_RXBUFFER_3K) {
+		rx_buf_len = TXGBE_RXBUFFER_3K;
+	} else if (max_frame <= TXGBE_RXBUFFER_7K) {
+		rx_buf_len = TXGBE_RXBUFFER_7K;
+	} else if (max_frame <= TXGBE_RXBUFFER_15K) {
+		rx_buf_len = TXGBE_RXBUFFER_15K;
+	} else {
+		rx_buf_len = TXGBE_MAX_RXBUFFER;
+	}
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+
+	/*
+	 * Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring
+	 */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		rx_ring = adapter->rx_ring[i];
+
+		if (adapter->flags & TXGBE_FLAG_RX_HS_ENABLED) {
+			rx_ring->rx_buf_len = TXGBE_RX_HDR_SIZE;
+			set_ring_hs_enabled(rx_ring);
+		} else
+			clear_ring_hs_enabled(rx_ring);
+
+		if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)
+			set_ring_rsc_enabled(rx_ring);
+		else
+			clear_ring_rsc_enabled(rx_ring);
+#ifdef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+
+		rx_ring->rx_buf_len = rx_buf_len;
+
+#if IS_ENABLED(CONFIG_FCOE)
+		if (test_bit(__TXGBE_RX_FCOE, &rx_ring->state) &&
+		    (rx_buf_len < TXGBE_FCOE_JUMBO_FRAME_SIZE))
+			rx_ring->rx_buf_len = TXGBE_FCOE_JUMBO_FRAME_SIZE;
+#endif /* CONFIG_FCOE */
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+	}
+}
+
+/**
+ * txgbe_configure_rx - Configure Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void txgbe_configure_rx(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i;
+	u32 rxctrl, psrctl;
+
+	/* disable receives while setting up the descriptors */
+	TCALL(hw, mac.ops.disable_rx);
+
+	txgbe_setup_psrtype(adapter);
+
+	/* enable hw crc stripping */
+	wr32m(hw, TXGBE_RSC_CTL,
+		TXGBE_RSC_CTL_CRC_STRIP, TXGBE_RSC_CTL_CRC_STRIP);
+
+	/* RSC Setup */
+	psrctl = rd32m(hw, TXGBE_PSR_CTL, ~TXGBE_PSR_CTL_RSC_DIS);
+	psrctl |= TXGBE_PSR_CTL_RSC_ACK; /* Disable RSC for ACK packets */
+	if (!(adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED))
+		psrctl |= TXGBE_PSR_CTL_RSC_DIS;
+	wr32(hw, TXGBE_PSR_CTL, psrctl);
+
+	/* Program registers for the distribution of queues */
+	txgbe_setup_mrqc(adapter);
+
+	/* set_rx_buffer_len must be called before ring initialization */
+	txgbe_set_rx_buffer_len(adapter);
+
+	/*
+	 * Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring
+	 */
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		txgbe_configure_rx_ring(adapter, adapter->rx_ring[i]);
+
+	rxctrl = rd32(hw, TXGBE_RDB_PB_CTL);
+
+	/* enable all receives */
+	rxctrl |= TXGBE_RDB_PB_CTL_RXEN;
+	TCALL(hw, mac.ops.enable_rx_dma, rxctrl);
+}
+
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+#if  defined(NETIF_F_HW_VLAN_CTAG_TX) || defined(NETIF_F_HW_VLAN_STAG_TX)
+static int txgbe_vlan_rx_add_vid(struct net_device *netdev,
+				 __always_unused __be16 proto, u16 vid)
+#else
+static int txgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+#endif /* NETIF_F_HW_VLAN_CTAG_TX || NETIF_F_HW_VLAN_STAG_TX*/
+#else /* !HAVE_INT_NDO_VLAN_RX_ADD_VID */
+static void txgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+#endif /* HAVE_INT_NDO_VLAN_RX_ADD_VID */
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	int pool_ndx = VMDQ_P(0);
+
+	/* add VID to filter table */
+	if (hw->mac.ops.set_vfta) {
+#ifndef HAVE_VLAN_RX_REGISTER
+		if (vid < VLAN_N_VID)
+			set_bit(vid, adapter->active_vlans);
+#endif
+		TCALL(hw, mac.ops.set_vfta, vid, pool_ndx, true);
+		if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED) {
+			int i;
+			/* enable vlan id for all pools */
+			for_each_set_bit(i, &adapter->fwd_bitmask,
+					 TXGBE_MAX_MACVLANS)
+				TCALL(hw, mac.ops.set_vfta, vid,
+					   VMDQ_P(i), true);
+		}
+	}
+#ifndef HAVE_NETDEV_VLAN_FEATURES
+
+	/*
+	 * Copy feature flags from netdev to the vlan netdev for this vid.
+	 * This allows things like TSO to bubble down to our vlan device.
+	 * Some vlans, such as VLAN 0 for DCB will not have a v_netdev so
+	 * we will not have a netdev that needs updating.
+	 */
+	if (adapter->vlgrp) {
+		struct vlan_group *vlgrp = adapter->vlgrp;
+		struct net_device *v_netdev = vlan_group_get_device(vlgrp, vid);
+		if (v_netdev) {
+			v_netdev->features |= netdev->features;
+			vlan_group_set_device(vlgrp, vid, v_netdev);
+		}
+	}
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+	return 0;
+#endif
+}
+
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) || (defined NETIF_F_HW_VLAN_STAG_RX)
+static int txgbe_vlan_rx_kill_vid(struct net_device *netdev,
+				  __always_unused __be16 proto, u16 vid)
+#else /* !NETIF_F_HW_VLAN_CTAG_RX */
+static int txgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+#endif /* NETIF_F_HW_VLAN_CTAG_RX */
+#else
+static void txgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	int pool_ndx = VMDQ_P(0);
+
+	/* User is not allowed to remove vlan ID 0 */
+	if (!vid)
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+		return 0;
+#else
+		return;
+#endif
+
+#ifdef HAVE_VLAN_RX_REGISTER
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_disable(adapter);
+
+	vlan_group_set_device(adapter->vlgrp, vid, NULL);
+
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_enable(adapter, true, true);
+
+#endif /* HAVE_VLAN_RX_REGISTER */
+	/* remove VID from filter table */
+	if (hw->mac.ops.set_vfta) {
+		TCALL(hw, mac.ops.set_vfta, vid, pool_ndx, false);
+		if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED) {
+			int i;
+			/* remove vlan id from all pools */
+			for_each_set_bit(i, &adapter->fwd_bitmask,
+					 TXGBE_MAX_MACVLANS)
+				TCALL(hw, mac.ops.set_vfta, vid,
+					   VMDQ_P(i), false);
+		}
+	}
+#ifndef HAVE_VLAN_RX_REGISTER
+
+	clear_bit(vid, adapter->active_vlans);
+#endif
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+	return 0;
+#endif
+}
+
+#ifdef HAVE_8021P_SUPPORT
+/**
+ * txgbe_vlan_strip_disable - helper to disable vlan tag stripping
+ * @adapter: driver data
+ */
+void txgbe_vlan_strip_disable(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i, j;
+
+	/* leave vlan tag stripping enabled for DCB */
+	if (adapter->flags & TXGBE_FLAG_DCB_ENABLED)
+		return;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct txgbe_ring *ring = adapter->rx_ring[i];
+		if (ring->accel)
+			continue;
+		j = ring->reg_idx;
+		wr32m(hw, TXGBE_PX_RR_CFG(j),
+			TXGBE_PX_RR_CFG_VLAN, 0);
+	}
+}
+
+#endif
+/**
+ * txgbe_vlan_strip_enable - helper to enable vlan tag stripping
+ * @adapter: driver data
+ */
+void txgbe_vlan_strip_enable(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i, j;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct txgbe_ring *ring = adapter->rx_ring[i];
+		if (ring->accel)
+			continue;
+		j = ring->reg_idx;
+		wr32m(hw, TXGBE_PX_RR_CFG(j),
+			TXGBE_PX_RR_CFG_VLAN, TXGBE_PX_RR_CFG_VLAN);
+	}
+}
+
+#ifdef HAVE_VLAN_RX_REGISTER
+static void txgbe_vlan_mode(struct net_device *netdev, struct vlan_group *grp)
+#else
+void txgbe_vlan_mode(struct net_device *netdev, u32 features)
+#endif
+{
+#if defined(HAVE_VLAN_RX_REGISTER) || defined(HAVE_8021P_SUPPORT)
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#endif
+#ifdef HAVE_8021P_SUPPORT
+	bool enable;
+#endif
+
+#ifdef HAVE_VLAN_RX_REGISTER
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_disable(adapter);
+
+	adapter->vlgrp = grp;
+
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		txgbe_irq_enable(adapter, true, true);
+#endif
+#ifdef HAVE_8021P_SUPPORT
+#ifdef HAVE_VLAN_RX_REGISTER
+	enable = (grp || (adapter->flags & TXGBE_FLAG_DCB_ENABLED));
+#else
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+	enable = !!(features & (NETIF_F_HW_VLAN_CTAG_RX |
+		 NETIF_F_HW_VLAN_STAG_RX));
+#elif (defined NETIF_F_HW_VLAN_CTAG_RX)
+	enable = !!(features & (NETIF_F_HW_VLAN_CTAG_RX);
+#elif (defined NETIF_F_HW_VLAN_STAG_RX)
+	enable = !!(features & (NETIF_F_HW_VLAN_STAG_RX);
+#else
+	enable = !!(features & NETIF_F_HW_VLAN_RX);
+#endif /* NETIF_F_HW_VLAN_CTAG_RX */
+#endif /* HAVE_VLAN_RX_REGISTER */
+	if (enable)
+		/* enable VLAN tag insert/strip */
+		txgbe_vlan_strip_enable(adapter);
+	else
+		/* disable VLAN tag insert/strip */
+		txgbe_vlan_strip_disable(adapter);
+
+#endif /* HAVE_8021P_SUPPORT */
+}
+
+static void txgbe_restore_vlan(struct txgbe_adapter *adapter)
+{
+#ifdef HAVE_VLAN_RX_REGISTER
+	txgbe_vlan_mode(adapter->netdev, adapter->vlgrp);
+
+	/*
+	 * add vlan ID 0 and enable vlan tag stripping so we
+	 * always accept priority-tagged traffic
+	 */
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) || (defined NETIF_F_HW_VLAN_STAG_RX)
+	txgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), 0);
+#else
+	txgbe_vlan_rx_add_vid(adapter->netdev, 0);
+#endif
+#ifndef HAVE_8021P_SUPPORT
+	txgbe_vlan_strip_enable(adapter);
+#endif
+	if (adapter->vlgrp) {
+		u16 vid;
+		for (vid = 0; vid < VLAN_N_VID; vid++) {
+			if (!vlan_group_get_device(adapter->vlgrp, vid))
+				continue;
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) || (defined NETIF_F_HW_VLAN_STAG_RX)
+			txgbe_vlan_rx_add_vid(adapter->netdev,
+					      htons(ETH_P_8021Q), vid);
+#else
+			txgbe_vlan_rx_add_vid(adapter->netdev, vid);
+#endif
+		}
+	}
+#else
+	struct net_device *netdev = adapter->netdev;
+	u16 vid;
+
+	txgbe_vlan_mode(netdev, netdev->features);
+
+	for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) || (defined NETIF_F_HW_VLAN_STAG_RX)
+		txgbe_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
+#else
+		txgbe_vlan_rx_add_vid(netdev, vid);
+#endif
+#endif
+}
+
+#endif
+static u8 *txgbe_addr_list_itr(struct txgbe_hw __maybe_unused *hw,
+			       u8 **mc_addr_ptr, u32 *vmdq)
+{
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+	struct netdev_hw_addr *mc_ptr;
+#else
+	struct dev_mc_list *mc_ptr;
+#endif
+#ifdef CONFIG_PCI_IOV
+	struct txgbe_adapter *adapter = hw->back;
+#endif /* CONFIG_PCI_IOV */
+	u8 *addr = *mc_addr_ptr;
+
+	/* VMDQ_P implicitely uses the adapter struct when CONFIG_PCI_IOV is
+	 * defined, so we have to wrap the pointer above correctly to prevent
+	 * a warning.
+	 */
+	*vmdq = VMDQ_P(0);
+
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+	mc_ptr = container_of(addr, struct netdev_hw_addr, addr[0]);
+	if (mc_ptr->list.next) {
+		struct netdev_hw_addr *ha;
+
+		ha = list_entry(mc_ptr->list.next, struct netdev_hw_addr, list);
+		*mc_addr_ptr = ha->addr;
+	}
+#else
+	mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]);
+	if (mc_ptr->next)
+		*mc_addr_ptr = mc_ptr->next->dmi_addr;
+#endif
+	else
+		*mc_addr_ptr = NULL;
+
+	return addr;
+}
+
+/**
+ * txgbe_write_mc_addr_list - write multicast addresses to MTA
+ * @netdev: network interface device structure
+ *
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ *                0 on no addresses written
+ *                X on writing X addresses to MTA
+ **/
+int txgbe_write_mc_addr_list(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+	struct netdev_hw_addr *ha;
+#endif
+	u8  *addr_list = NULL;
+	int addr_count = 0;
+
+	if (!hw->mac.ops.update_mc_addr_list)
+		return -ENOMEM;
+
+	if (!netif_running(netdev))
+		return 0;
+
+
+	if (netdev_mc_empty(netdev)) {
+		TCALL(hw, mac.ops.update_mc_addr_list, NULL, 0,
+						txgbe_addr_list_itr, true);
+	} else {
+#ifdef NETDEV_HW_ADDR_T_MULTICAST
+		ha = list_first_entry(&netdev->mc.list,
+				      struct netdev_hw_addr, list);
+		addr_list = ha->addr;
+#else
+		addr_list = netdev->mc_list->dmi_addr;
+#endif
+		addr_count = netdev_mc_count(netdev);
+
+		TCALL(hw, mac.ops.update_mc_addr_list, addr_list, addr_count,
+						txgbe_addr_list_itr, true);
+	}
+
+#ifdef CONFIG_PCI_IOV
+	txgbe_restore_vf_multicasts(adapter);
+#endif
+	return addr_count;
+}
+
+
+void txgbe_full_sync_mac_table(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i;
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+		if (adapter->mac_table[i].state & TXGBE_MAC_STATE_IN_USE) {
+			TCALL(hw, mac.ops.set_rar, i,
+				adapter->mac_table[i].addr,
+				adapter->mac_table[i].pools,
+				TXGBE_PSR_MAC_SWC_AD_H_AV);
+		} else {
+			TCALL(hw, mac.ops.clear_rar, i);
+		}
+		adapter->mac_table[i].state &= ~(TXGBE_MAC_STATE_MODIFIED);
+	}
+}
+
+static void txgbe_sync_mac_table(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i;
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+		if (adapter->mac_table[i].state & TXGBE_MAC_STATE_MODIFIED) {
+			if (adapter->mac_table[i].state &
+					TXGBE_MAC_STATE_IN_USE) {
+				TCALL(hw, mac.ops.set_rar, i,
+						adapter->mac_table[i].addr,
+						adapter->mac_table[i].pools,
+						TXGBE_PSR_MAC_SWC_AD_H_AV);
+			} else {
+				TCALL(hw, mac.ops.clear_rar, i);
+			}
+			adapter->mac_table[i].state &=
+				~(TXGBE_MAC_STATE_MODIFIED);
+		}
+	}
+}
+
+int txgbe_available_rars(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i, count = 0;
+
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+		if (adapter->mac_table[i].state == 0)
+			count++;
+	}
+	return count;
+}
+
+/* this function destroys the first RAR entry */
+static void txgbe_mac_set_default_filter(struct txgbe_adapter *adapter,
+					 u8 *addr)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
+	adapter->mac_table[0].pools = 1ULL << VMDQ_P(0);
+	adapter->mac_table[0].state = (TXGBE_MAC_STATE_DEFAULT |
+				       TXGBE_MAC_STATE_IN_USE);
+	TCALL(hw, mac.ops.set_rar, 0, adapter->mac_table[0].addr,
+			    adapter->mac_table[0].pools,
+			    TXGBE_PSR_MAC_SWC_AD_H_AV);
+}
+
+int txgbe_add_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 pool)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 i;
+
+	if (is_zero_ether_addr(addr))
+		return -EINVAL;
+
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+
+		if (adapter->mac_table[i].state & TXGBE_MAC_STATE_IN_USE)
+		{
+			if (ether_addr_equal(addr, adapter->mac_table[i].addr)) {
+				if (adapter->mac_table[i].pools != (1ULL << pool)) {
+					memcpy(adapter->mac_table[i].addr, addr, ETH_ALEN);
+					adapter->mac_table[i].pools |= (1ULL << pool);
+					txgbe_sync_mac_table(adapter);
+					return i;
+				}
+			}
+		}
+
+		if (adapter->mac_table[i].state & TXGBE_MAC_STATE_IN_USE) {
+			continue;
+		}
+		adapter->mac_table[i].state |= (TXGBE_MAC_STATE_MODIFIED |
+						TXGBE_MAC_STATE_IN_USE);
+		memcpy(adapter->mac_table[i].addr, addr, ETH_ALEN);
+		adapter->mac_table[i].pools |= (1ULL << pool);
+		txgbe_sync_mac_table(adapter);
+		return i;
+	}
+	return -ENOMEM;
+}
+
+static void txgbe_flush_sw_mac_table(struct txgbe_adapter *adapter)
+{
+	u32 i;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+		adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
+		adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
+		memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
+		adapter->mac_table[i].pools = 0;
+	}
+	txgbe_sync_mac_table(adapter);
+}
+
+int txgbe_del_mac_filter(struct txgbe_adapter *adapter, u8 *addr, u16 pool)
+{
+	/* search table for addr, if found, set to 0 and sync */
+	u32 i;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (is_zero_ether_addr(addr))
+		return -EINVAL;
+
+	for (i = 0; i < hw->mac.num_rar_entries; i++) {
+		if (ether_addr_equal(addr, adapter->mac_table[i].addr)){
+			if (adapter->mac_table[i].pools & (1ULL << pool)) {
+				adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
+				adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
+
+				adapter->mac_table[i].pools &= ~(1ULL << pool) ;
+				txgbe_sync_mac_table(adapter);
+			}
+			return 0;
+		}
+
+		if (adapter->mac_table[i].pools != (1 << pool))
+			continue;
+		if ( !ether_addr_equal(addr, adapter->mac_table[i].addr))
+			continue;
+
+		adapter->mac_table[i].state |= TXGBE_MAC_STATE_MODIFIED;
+		adapter->mac_table[i].state &= ~TXGBE_MAC_STATE_IN_USE;
+		memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
+		adapter->mac_table[i].pools = 0;
+		txgbe_sync_mac_table(adapter);
+		return 0;
+
+
+	}
+	return -ENOMEM;
+}
+
+#ifdef HAVE_SET_RX_MODE
+/**
+ * txgbe_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ *                0 on no addresses written
+ *                X on writing X addresses to the RAR table
+ **/
+int txgbe_write_uc_addr_list(struct net_device *netdev, int pool)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int count = 0;
+
+	/* return ENOMEM indicating insufficient memory for addresses */
+	if (netdev_uc_count(netdev) > txgbe_available_rars(adapter))
+		return -ENOMEM;
+
+	if (!netdev_uc_empty(netdev)) {
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+		struct netdev_hw_addr *ha;
+#else
+		struct dev_mc_list *ha;
+#endif
+		netdev_for_each_uc_addr(ha, netdev) {
+#ifdef NETDEV_HW_ADDR_T_UNICAST
+			txgbe_del_mac_filter(adapter, ha->addr, pool);
+			txgbe_add_mac_filter(adapter, ha->addr, pool);
+#else
+			txgbe_del_mac_filter(adapter, ha->da_addr, pool);
+			txgbe_add_mac_filter(adapter, ha->da_addr, pool);
+#endif
+			count++;
+		}
+	}
+	return count;
+}
+
+#endif
+
+int txgbe_add_cloud_switcher(struct txgbe_adapter *adapter, u32 key, u16 pool)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	UNREFERENCED_PARAMETER(pool);
+
+	wr32(hw, TXGBE_PSR_CL_SWC_IDX, 0);
+	wr32(hw, TXGBE_PSR_CL_SWC_KEY, key);
+	wr32(hw, TXGBE_PSR_CL_SWC_CTL,
+		TXGBE_PSR_CL_SWC_CTL_VLD | TXGBE_PSR_CL_SWC_CTL_DST_MSK);
+	wr32(hw, TXGBE_PSR_CL_SWC_VM_L, 0x1);
+	wr32(hw, TXGBE_PSR_CL_SWC_VM_H, 0x0);
+
+	return 0;
+}
+
+
+int txgbe_del_cloud_switcher(struct txgbe_adapter *adapter, u32 key, u16 pool)
+{
+	/* search table for addr, if found, set to 0 and sync */
+	struct txgbe_hw *hw = &adapter->hw;
+
+	UNREFERENCED_PARAMETER(key);
+	UNREFERENCED_PARAMETER(pool);
+
+	wr32(hw, TXGBE_PSR_CL_SWC_IDX, 0);
+	wr32(hw, TXGBE_PSR_CL_SWC_CTL, 0);
+
+	return 0;
+}
+
+/**
+ * txgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_rx_method entry point is called whenever the unicast/multicast
+ * address list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper unicast, multicast and
+ * promiscuous mode.
+ **/
+void txgbe_set_rx_mode(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 fctrl, vmolr, vlnctrl;
+	int count;
+
+	/* Check for Promiscuous and All Multicast modes */
+	fctrl = rd32m(hw, TXGBE_PSR_CTL,
+			~(TXGBE_PSR_CTL_UPE | TXGBE_PSR_CTL_MPE));
+	vmolr = rd32m(hw, TXGBE_PSR_VM_L2CTL(VMDQ_P(0)),
+			~(TXGBE_PSR_VM_L2CTL_UPE |
+			  TXGBE_PSR_VM_L2CTL_MPE |
+			  TXGBE_PSR_VM_L2CTL_ROPE |
+			  TXGBE_PSR_VM_L2CTL_ROMPE));
+	vlnctrl = rd32m(hw, TXGBE_PSR_VLAN_CTL,
+			~(TXGBE_PSR_VLAN_CTL_VFE |
+			  TXGBE_PSR_VLAN_CTL_CFIEN));
+
+	/* set all bits that we expect to always be set */
+	fctrl |= TXGBE_PSR_CTL_BAM | TXGBE_PSR_CTL_MFE;
+	vmolr |= TXGBE_PSR_VM_L2CTL_BAM |
+		 TXGBE_PSR_VM_L2CTL_AUPE |
+		 TXGBE_PSR_VM_L2CTL_VACC;
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	vlnctrl |= TXGBE_PSR_VLAN_CTL_VFE;
+#endif
+
+	hw->addr_ctrl.user_set_promisc = false;
+	if (netdev->flags & IFF_PROMISC) {
+		hw->addr_ctrl.user_set_promisc = true;
+		fctrl |= (TXGBE_PSR_CTL_UPE | TXGBE_PSR_CTL_MPE);
+		/* pf don't want packets routing to vf, so clear UPE */
+		vmolr |= TXGBE_PSR_VM_L2CTL_MPE;
+		vlnctrl &= ~TXGBE_PSR_VLAN_CTL_VFE;
+	}
+
+	if (netdev->flags & IFF_ALLMULTI) {
+		fctrl |= TXGBE_PSR_CTL_MPE;
+		vmolr |= TXGBE_PSR_VM_L2CTL_MPE;
+	}
+
+	/* This is useful for sniffing bad packets. */
+	if (netdev->features & NETIF_F_RXALL) {
+		vmolr |= (TXGBE_PSR_VM_L2CTL_UPE | TXGBE_PSR_VM_L2CTL_MPE);
+		vlnctrl &= ~TXGBE_PSR_VLAN_CTL_VFE;
+		/* receive bad packets */
+		wr32m(hw, TXGBE_RSC_CTL,
+			TXGBE_RSC_CTL_SAVE_MAC_ERR,
+			TXGBE_RSC_CTL_SAVE_MAC_ERR);
+	} else {
+		vmolr |= TXGBE_PSR_VM_L2CTL_ROPE | TXGBE_PSR_VM_L2CTL_ROMPE;
+	}
+
+	/*
+	 * Write addresses to available RAR registers, if there is not
+	 * sufficient space to store all the addresses then enable
+	 * unicast promiscuous mode
+	 */
+	count = txgbe_write_uc_addr_list(netdev, VMDQ_P(0));
+	if (count < 0) {
+		vmolr &= ~TXGBE_PSR_VM_L2CTL_ROPE;
+		vmolr |= TXGBE_PSR_VM_L2CTL_UPE;
+	}
+
+	/*
+	 * Write addresses to the MTA, if the attempt fails
+	 * then we should just turn on promiscuous mode so
+	 * that we can at least receive multicast traffic
+	 */
+	count = txgbe_write_mc_addr_list(netdev);
+	if (count < 0) {
+		vmolr &= ~TXGBE_PSR_VM_L2CTL_ROMPE;
+		vmolr |= TXGBE_PSR_VM_L2CTL_MPE;
+	}
+
+	wr32(hw, TXGBE_PSR_VLAN_CTL, vlnctrl);
+	wr32(hw, TXGBE_PSR_CTL, fctrl);
+	wr32(hw, TXGBE_PSR_VM_L2CTL(VMDQ_P(0)), vmolr);
+
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+	if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+		(netdev->features & NETIF_F_HW_VLAN_STAG_RX))
+#elif (defined NETIF_F_HW_VLAN_CTAG_RX)
+	if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
+#elif (defined NETIF_F_HW_VLAN_STAG_RX)
+	if (netdev->features & NETIF_F_HW_VLAN_STAG_RX)
+#else
+	if (netdev->features & NETIF_F_HW_VLAN_RX)
+#endif
+		txgbe_vlan_strip_enable(adapter);
+	else
+		txgbe_vlan_strip_disable(adapter);
+
+	/* enable cloud switch */
+	if (adapter->flags2 & TXGBE_FLAG2_CLOUD_SWITCH_ENABLED) {
+		txgbe_add_cloud_switcher(adapter, 0x10, 0);
+	}
+}
+
+static void txgbe_napi_enable_all(struct txgbe_adapter *adapter)
+{
+	struct txgbe_q_vector *q_vector;
+	int q_idx;
+
+	for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++) {
+		q_vector = adapter->q_vector[q_idx];
+#ifdef HAVE_NDO_BUSY_POLL
+		txgbe_qv_init_lock(adapter->q_vector[q_idx]);
+#endif
+		napi_enable(&q_vector->napi);
+	}
+}
+
+static void txgbe_napi_disable_all(struct txgbe_adapter *adapter)
+{
+	struct txgbe_q_vector *q_vector;
+	int q_idx;
+
+	for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++) {
+		q_vector = adapter->q_vector[q_idx];
+		napi_disable(&q_vector->napi);
+#ifdef HAVE_NDO_BUSY_POLL
+		while (!txgbe_qv_disable(adapter->q_vector[q_idx])) {
+			pr_info("QV %d locked\n", q_idx);
+			usleep_range(1000, 20000);
+		}
+#endif
+	}
+}
+
+#ifdef HAVE_DCBNL_IEEE
+s32 txgbe_dcb_hw_ets(struct txgbe_hw *hw, struct ieee_ets *ets, int max_frame)
+{
+	__u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS];
+	__u8 prio_type[IEEE_8021QAZ_MAX_TCS];
+	int i;
+
+	/* naively give each TC a bwg to map onto CEE hardware */
+	__u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+	/* Map TSA onto CEE prio type */
+	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+		switch (ets->tc_tsa[i]) {
+		case IEEE_8021QAZ_TSA_STRICT:
+			prio_type[i] = 2;
+			break;
+		case IEEE_8021QAZ_TSA_ETS:
+			prio_type[i] = 0;
+			break;
+		default:
+			/* Hardware only supports priority strict or
+			 * ETS transmission selection algorithms if
+			 * we receive some other value from dcbnl
+			 * throw an error
+			 */
+			return -EINVAL;
+		}
+	}
+
+	txgbe_dcb_calculate_tc_credits(ets->tc_tx_bw, refill, max, max_frame);
+	return txgbe_dcb_hw_config(hw, refill, max,
+				   bwg_id, prio_type, ets->prio_tc);
+}
+#endif
+
+void txgbe_clear_vxlan_port(struct txgbe_adapter *adapter)
+{
+#ifdef HAVE_VXLAN_CHECKS
+	adapter->vxlan_port = 0;
+#endif /* HAVE_VXLAN_CHECKS */
+	if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+		return;
+	/* Do not need to clear vxlan_port reg*/
+	//wr32(&adapter->hw, TXGBE_CFG_VXLAN, 0);
+}
+
+
+/* NETIF_F_GSO_IPXIP4/6 may not be defined in all distributions */
+
+#ifndef NETIF_F_GSO_GRE
+#define NETIF_F_GSO_GRE 0
+#endif
+
+#ifndef NETIF_F_GSO_GRE_CSUM
+#define NETIF_F_GSO_GRE_CSUM 0
+#endif
+#ifndef NETIF_F_GSO_UDP_TUNNEL
+#define NETIF_F_GSO_UDP_TUNNEL 0
+#endif
+
+#ifndef NETIF_F_GSO_IPXIP4
+#define NETIF_F_GSO_IPXIP4 0
+#endif
+#ifndef NETIF_F_GSO_IPXIP6
+#define NETIF_F_GSO_IPXIP6 0
+#endif
+#define TXGBE_GSO_PARTIAL_FEATURES (NETIF_F_GSO_GRE | \
+				    NETIF_F_GSO_GRE_CSUM | \
+				    NETIF_F_GSO_IPXIP4 | \
+				    NETIF_F_GSO_IPXIP6 | \
+				    NETIF_F_GSO_UDP_TUNNEL | \
+				    NETIF_F_GSO_UDP_TUNNEL_CSUM)
+
+
+static inline unsigned long txgbe_tso_features(void)
+{
+	unsigned long features = 0;
+
+#ifdef NETIF_F_TSO
+	features |= NETIF_F_TSO;
+#endif /* NETIF_F_TSO */
+#ifdef NETIF_F_TSO6
+	features |= NETIF_F_TSO6;
+#endif /* NETIF_F_TSO6 */
+#ifdef NETIF_F_GSO_PARTIAL
+	features |= NETIF_F_GSO_PARTIAL | TXGBE_GSO_PARTIAL_FEATURES;
+#else
+	features |= TXGBE_GSO_PARTIAL_FEATURES;
+#endif
+
+
+	return features;
+}
+
+/*
+ * txgbe_configure_dcb - Configure DCB hardware support
+ * @adapter: txgbe adapter struct
+ *
+ * Called when the driver opens or needs to reconfigure DCB related bits.
+ */
+static void txgbe_configure_dcb(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+
+	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	u32 msb = 0;
+	u16 rss_i = adapter->ring_feature[RING_F_RSS].indices - 1;
+
+	if (!(adapter->flags & TXGBE_FLAG_DCB_ENABLED))
+		return;
+
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (netdev->features & NETIF_F_FCOE_MTU)
+		max_frame = max_t(int, max_frame,
+				  TXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif /* CONFIG_FCOE */
+
+#ifdef HAVE_DCBNL_IEEE
+	if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) {
+		if (adapter->txgbe_ieee_ets)
+			txgbe_dcb_hw_ets(&adapter->hw,
+					 adapter->txgbe_ieee_ets,
+					 max_frame);
+
+		if (adapter->txgbe_ieee_pfc && adapter->txgbe_ieee_ets) {
+			struct ieee_pfc *pfc = adapter->txgbe_ieee_pfc;
+			u8 *tc = adapter->txgbe_ieee_ets->prio_tc;
+
+			txgbe_dcb_config_pfc(&adapter->hw, pfc->pfc_en, tc);
+		}
+	} else
+#endif /* HAVE_DCBNL_IEEE */
+	{
+		txgbe_dcb_calculate_tc_credits_cee(hw,
+						   &adapter->dcb_cfg,
+						   max_frame,
+						   TXGBE_DCB_TX_CONFIG);
+		txgbe_dcb_calculate_tc_credits_cee(hw,
+						   &adapter->dcb_cfg,
+						   max_frame,
+						   TXGBE_DCB_RX_CONFIG);
+		txgbe_dcb_hw_config_cee(hw, &adapter->dcb_cfg);
+	}
+
+	/* Enable RSS Hash per TC */
+	while (rss_i) {
+		msb++;
+		rss_i >>= 1;
+	}
+
+	/* write msb to all 8 TCs in one write */
+	wr32(hw, TXGBE_RDB_RSS_TC, msb * 0x11111111);
+}
+
+#ifndef TXGBE_NO_LLI
+static void txgbe_configure_lli(struct txgbe_adapter *adapter)
+{
+	/* lli should only be enabled with MSI-X and MSI */
+	if (!(adapter->flags & TXGBE_FLAG_MSI_ENABLED) &&
+	    !(adapter->flags & TXGBE_FLAG_MSIX_ENABLED))
+		return;
+
+	if (adapter->lli_etype) {
+		wr32(&adapter->hw, TXGBE_RDB_5T_CTL1(0),
+				(TXGBE_RDB_5T_CTL1_LLI |
+				 TXGBE_RDB_5T_CTL1_SIZE_BP));
+		wr32(&adapter->hw, TXGBE_RDB_ETYPE_CLS(0),
+				TXGBE_RDB_ETYPE_CLS_LLI);
+		wr32(&adapter->hw, TXGBE_PSR_ETYPE_SWC(0),
+				(adapter->lli_etype |
+				 TXGBE_PSR_ETYPE_SWC_FILTER_EN));
+	}
+
+	if (adapter->lli_port) {
+		wr32(&adapter->hw, TXGBE_RDB_5T_CTL1(0),
+				(TXGBE_RDB_5T_CTL1_LLI |
+				 TXGBE_RDB_5T_CTL1_SIZE_BP));
+		wr32(&adapter->hw, TXGBE_RDB_5T_CTL0(0),
+				(TXGBE_RDB_5T_CTL0_POOL_MASK_EN |
+				 (TXGBE_RDB_5T_CTL0_PRIORITY_MASK <<
+				  TXGBE_RDB_5T_CTL0_PRIORITY_SHIFT) |
+				 (TXGBE_RDB_5T_CTL0_DEST_PORT_MASK <<
+				  TXGBE_RDB_5T_CTL0_5TUPLE_MASK_SHIFT)));
+
+		wr32(&adapter->hw, TXGBE_RDB_5T_SDP(0),
+			(adapter->lli_port << 16));
+	}
+
+	if (adapter->lli_size) {
+		wr32(&adapter->hw, TXGBE_RDB_5T_CTL1(0),
+				TXGBE_RDB_5T_CTL1_LLI);
+		wr32m(&adapter->hw, TXGBE_RDB_LLI_THRE,
+				TXGBE_RDB_LLI_THRE_SZ(~0), adapter->lli_size);
+		wr32(&adapter->hw, TXGBE_RDB_5T_CTL0(0),
+				(TXGBE_RDB_5T_CTL0_POOL_MASK_EN |
+				 (TXGBE_RDB_5T_CTL0_PRIORITY_MASK <<
+				  TXGBE_RDB_5T_CTL0_PRIORITY_SHIFT) |
+				 (TXGBE_RDB_5T_CTL0_5TUPLE_MASK_MASK <<
+				  TXGBE_RDB_5T_CTL0_5TUPLE_MASK_SHIFT)));
+	}
+
+	if (adapter->lli_vlan_pri) {
+		wr32m(&adapter->hw, TXGBE_RDB_LLI_THRE,
+			TXGBE_RDB_LLI_THRE_PRIORITY_EN |
+			TXGBE_RDB_LLI_THRE_UP(~0),
+			TXGBE_RDB_LLI_THRE_PRIORITY_EN |
+			(adapter->lli_vlan_pri << TXGBE_RDB_LLI_THRE_UP_SHIFT));
+	}
+}
+
+#endif /* TXGBE_NO_LLI */
+/* Additional bittime to account for TXGBE framing */
+#define TXGBE_ETH_FRAMING 20
+
+/*
+ * txgbe_hpbthresh - calculate high water mark for flow control
+ *
+ * @adapter: board private structure to calculate for
+ * @pb - packet buffer to calculate
+ */
+static int txgbe_hpbthresh(struct txgbe_adapter *adapter, int pb)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct net_device *dev = adapter->netdev;
+	int link, tc, kb, marker;
+	u32 dv_id, rx_pba;
+
+	/* Calculate max LAN frame size */
+	tc = link = dev->mtu + ETH_HLEN + ETH_FCS_LEN + TXGBE_ETH_FRAMING;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* FCoE traffic class uses FCOE jumbo frames */
+	if ((dev->features & NETIF_F_FCOE_MTU) &&
+	    (tc < TXGBE_FCOE_JUMBO_FRAME_SIZE) &&
+	    (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up)))
+		tc = TXGBE_FCOE_JUMBO_FRAME_SIZE;
+#endif /* CONFIG_FCOE */
+
+	/* Calculate delay value for device */
+	dv_id = TXGBE_DV(link, tc);
+
+	/* Loopback switch introduces additional latency */
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED)
+		dv_id += TXGBE_B2BT(tc);
+
+	/* Delay value is calculated in bit times convert to KB */
+	kb = TXGBE_BT2KB(dv_id);
+	rx_pba = rd32(hw, TXGBE_RDB_PB_SZ(pb))
+			>> TXGBE_RDB_PB_SZ_SHIFT;
+
+	marker = rx_pba - kb;
+
+	/* It is possible that the packet buffer is not large enough
+	 * to provide required headroom. In this case throw an error
+	 * to user and a do the best we can.
+	 */
+	if (marker < 0) {
+		e_warn(drv, "Packet Buffer(%i) can not provide enough"
+			    "headroom to suppport flow control."
+			    "Decrease MTU or number of traffic classes\n", pb);
+		marker = tc + 1;
+	}
+
+	return marker;
+}
+
+/*
+ * txgbe_lpbthresh - calculate low water mark for for flow control
+ *
+ * @adapter: board private structure to calculate for
+ * @pb - packet buffer to calculate
+ */
+static int txgbe_lpbthresh(struct txgbe_adapter *adapter, int __maybe_unused pb)
+{
+	struct net_device *dev = adapter->netdev;
+	int tc;
+	u32 dv_id;
+
+	/* Calculate max LAN frame size */
+	tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* FCoE traffic class uses FCOE jumbo frames */
+	if ((dev->features & NETIF_F_FCOE_MTU) &&
+	    (tc < TXGBE_FCOE_JUMBO_FRAME_SIZE) &&
+	    (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up)))
+		tc = TXGBE_FCOE_JUMBO_FRAME_SIZE;
+#endif /* CONFIG_FCOE */
+
+	/* Calculate delay value for device */
+	dv_id = TXGBE_LOW_DV(tc);
+
+	/* Delay value is calculated in bit times convert to KB */
+	return TXGBE_BT2KB(dv_id);
+}
+
+/*
+ * txgbe_pbthresh_setup - calculate and setup high low water marks
+ */
+static void txgbe_pbthresh_setup(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int num_tc = netdev_get_num_tc(adapter->netdev);
+	int i;
+
+	if (!num_tc)
+		num_tc = 1;
+
+
+	for (i = 0; i < num_tc; i++) {
+		hw->fc.high_water[i] = txgbe_hpbthresh(adapter, i);
+		hw->fc.low_water[i] = txgbe_lpbthresh(adapter, i);
+
+		/* Low water marks must not be larger than high water marks */
+		if (hw->fc.low_water[i] > hw->fc.high_water[i])
+			hw->fc.low_water[i] = 0;
+	}
+
+	for (; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++)
+		hw->fc.high_water[i] = 0;
+}
+
+static void txgbe_configure_pb(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int hdrm;
+	int tc = netdev_get_num_tc(adapter->netdev);
+
+	if (adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE ||
+	    adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+		hdrm = 32 << adapter->fdir_pballoc;
+	else
+		hdrm = 0;
+
+	TCALL(hw, mac.ops.setup_rxpba, tc, hdrm, PBA_STRATEGY_EQUAL);
+	txgbe_pbthresh_setup(adapter);
+}
+
+static void txgbe_fdir_filter_restore(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct hlist_node *node;
+	struct txgbe_fdir_filter *filter;
+	u8 queue = 0;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+
+	if (!hlist_empty(&adapter->fdir_filter_list))
+		txgbe_fdir_set_input_mask(hw, &adapter->fdir_mask,
+				adapter->cloud_mode);
+
+	hlist_for_each_entry_safe(filter, node,
+				  &adapter->fdir_filter_list, fdir_node) {
+		if (filter->action == TXGBE_RDB_FDIR_DROP_QUEUE) {
+			queue = TXGBE_RDB_FDIR_DROP_QUEUE;
+		} else {
+			u32 ring = ethtool_get_flow_spec_ring(filter->action);
+			u8 vf = ethtool_get_flow_spec_ring_vf(filter->action);
+
+			if (!vf && ring >= adapter->num_rx_queues) {
+				e_err(drv,
+				      "FDIR restore failed w/o vf, ring:%u\n",
+				      ring);
+				continue;
+			} else if (vf &&
+				   ((vf > adapter->num_vfs) ||
+				   ring >= adapter->num_rx_queues_per_pool)) {
+				e_err(drv,
+				      "FDIR restore failed vf:%hhu, ring:%u\n",
+				      vf, ring);
+				continue;
+			}
+
+			/* Map the ring onto the absolute queue index */
+			if (!vf)
+				queue = adapter->rx_ring[ring]->reg_idx;
+			else
+				queue = ((vf - 1) *
+					adapter->num_rx_queues_per_pool) + ring;
+		}
+		
+		txgbe_fdir_write_perfect_filter(hw,
+				&filter->filter,
+				filter->sw_idx,
+				queue,
+				adapter->cloud_mode);
+	}
+
+	spin_unlock(&adapter->fdir_perfect_lock);
+}
+
+void txgbe_configure_isb(struct txgbe_adapter *adapter)
+{
+	/* set ISB Address */
+	struct txgbe_hw *hw = &adapter->hw;
+
+	wr32(hw, TXGBE_PX_ISB_ADDR_L,
+			adapter->isb_dma & DMA_BIT_MASK(32));
+	wr32(hw, TXGBE_PX_ISB_ADDR_H, adapter->isb_dma >> 32);
+}
+
+void txgbe_configure_port(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 value, i;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED) {
+		if (tcs > 4)
+			/* 8 TCs */
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_8 |
+			      TXGBE_CFG_PORT_CTL_NUM_VT_16 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (tcs > 1)
+			/* 4 TCs */
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_4 |
+			      TXGBE_CFG_PORT_CTL_NUM_VT_32 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (adapter->ring_feature[RING_F_RSS].indices == 4)
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_32;
+		else /* adapter->ring_feature[RING_F_RSS].indices <= 2 */
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_64;
+	} else {
+		if (tcs > 4)
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_8 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else if (tcs > 1)
+			value = TXGBE_CFG_PORT_CTL_NUM_TC_4 |
+			      TXGBE_CFG_PORT_CTL_DCB_EN;
+		else
+			value = 0;
+	}
+
+	value |= TXGBE_CFG_PORT_CTL_D_VLAN | TXGBE_CFG_PORT_CTL_QINQ;
+	wr32m(hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_NUM_TC_MASK |
+		TXGBE_CFG_PORT_CTL_NUM_VT_MASK |
+		TXGBE_CFG_PORT_CTL_DCB_EN |
+		TXGBE_CFG_PORT_CTL_D_VLAN |
+		TXGBE_CFG_PORT_CTL_QINQ,
+		value);
+
+	wr32(hw, TXGBE_CFG_TAG_TPID(0),
+			ETH_P_8021Q | ETH_P_8021AD << 16);
+	adapter->hw.tpid[0] = ETH_P_8021Q;
+	adapter->hw.tpid[1] = ETH_P_8021AD;
+	for (i = 1; i < 4; i++)
+		wr32(hw, TXGBE_CFG_TAG_TPID(i),
+			ETH_P_8021Q | ETH_P_8021Q << 16);
+	for (i = 2; i < 8; i++)
+		adapter->hw.tpid[i] = ETH_P_8021Q;
+}
+
+#ifdef HAVE_VIRTUAL_STATION
+static void txgbe_macvlan_set_rx_mode(struct net_device *dev, unsigned int pool,
+				      struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 vmolr;
+
+	/* No unicast promiscuous support for VMDQ devices. */
+	vmolr = rd32m(hw, TXGBE_PSR_VM_L2CTL(pool),
+			~(TXGBE_PSR_VM_L2CTL_UPE |
+			  TXGBE_PSR_VM_L2CTL_MPE |
+			  TXGBE_PSR_VM_L2CTL_ROPE |
+			  TXGBE_PSR_VM_L2CTL_ROMPE));
+
+	/* set all bits that we expect to always be set */
+	vmolr |= TXGBE_PSR_VM_L2CTL_ROPE |
+		 TXGBE_PSR_VM_L2CTL_BAM | TXGBE_PSR_VM_L2CTL_AUPE;
+
+	if (dev->flags & IFF_ALLMULTI) {
+		vmolr |= TXGBE_PSR_VM_L2CTL_MPE;
+	} else {
+		vmolr |= TXGBE_PSR_VM_L2CTL_ROMPE;
+		txgbe_write_mc_addr_list(dev);
+	}
+
+	txgbe_write_uc_addr_list(adapter->netdev, pool);
+	wr32(hw, TXGBE_PSR_VM_L2CTL(pool), vmolr);
+}
+
+static void txgbe_fwd_psrtype(struct txgbe_fwd_adapter *accel)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+	int rss_i = adapter->queues_per_pool;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 psrtype = TXGBE_RDB_PL_CFG_L4HDR |
+		      TXGBE_RDB_PL_CFG_L3HDR |
+		      TXGBE_RDB_PL_CFG_L2HDR |
+		      TXGBE_RDB_PL_CFG_TUN_OUTER_L2HDR |
+		      TXGBE_RDB_PL_CFG_TUN_TUNHDR;
+
+	if (rss_i > 3)
+		psrtype |= 2 << 29;
+	else if (rss_i > 1)
+		psrtype |= 1 << 29;
+
+	wr32(hw, TXGBE_RDB_PL_CFG(VMDQ_P(accel->index)), psrtype);
+}
+
+static void txgbe_disable_fwd_ring(struct txgbe_fwd_adapter *accel,
+				   struct txgbe_ring *rx_ring)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+	int index = rx_ring->queue_index + accel->rx_base_queue;
+
+	/* shutdown specific queue receive and wait for dma to settle */
+	txgbe_disable_rx_queue(adapter, rx_ring);
+	usleep_range(10000, 20000);
+	txgbe_intr_disable(&adapter->hw, TXGBE_INTR_Q(index));
+	txgbe_clean_rx_ring(rx_ring);
+	rx_ring->accel = NULL;
+}
+
+static void txgbe_enable_fwd_ring(struct txgbe_fwd_adapter *accel,
+				   struct txgbe_ring *rx_ring)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+	int index = rx_ring->queue_index + accel->rx_base_queue;
+
+	txgbe_intr_enable(&adapter->hw, TXGBE_INTR_Q(index));
+}
+
+static int txgbe_fwd_ring_down(struct net_device *vdev,
+			       struct txgbe_fwd_adapter *accel)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+	unsigned int rxbase = accel->rx_base_queue;
+	unsigned int txbase = accel->tx_base_queue;
+	int i;
+
+	netif_tx_stop_all_queues(vdev);
+
+	for (i = 0; i < adapter->queues_per_pool; i++) {
+		txgbe_disable_fwd_ring(accel, adapter->rx_ring[rxbase + i]);
+		adapter->rx_ring[rxbase + i]->netdev = adapter->netdev;
+	}
+
+	for (i = 0; i < adapter->queues_per_pool; i++) {
+		adapter->tx_ring[txbase + i]->accel = NULL;
+		adapter->tx_ring[txbase + i]->netdev = adapter->netdev;
+	}
+
+	return 0;
+}
+
+static int txgbe_fwd_ring_up(struct net_device *vdev,
+			     struct txgbe_fwd_adapter *accel)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+	unsigned int rxbase, txbase, queues;
+	int i, baseq, err = 0;
+
+	if (!test_bit(accel->index, &adapter->fwd_bitmask))
+		return 0;
+
+	baseq = VMDQ_P(accel->index) * adapter->queues_per_pool;
+	netdev_dbg(vdev, "pool %i:%i queues %i:%i VSI bitmask %lx\n",
+		   accel->index, adapter->num_vmdqs,
+		   baseq, baseq + adapter->queues_per_pool,
+		   adapter->fwd_bitmask);
+
+	accel->vdev = vdev;
+	accel->rx_base_queue = rxbase = baseq;
+	accel->tx_base_queue = txbase = baseq;
+
+	for (i = 0; i < adapter->queues_per_pool; i++)
+		txgbe_disable_fwd_ring(accel, adapter->rx_ring[rxbase + i]);
+
+	for (i = 0; i < adapter->queues_per_pool; i++) {
+		adapter->rx_ring[rxbase + i]->netdev = vdev;
+		adapter->rx_ring[rxbase + i]->accel = accel;
+		txgbe_configure_rx_ring(adapter, adapter->rx_ring[rxbase + i]);
+	}
+
+	for (i = 0; i < adapter->queues_per_pool; i++) {
+		adapter->tx_ring[txbase + i]->netdev = vdev;
+		adapter->tx_ring[txbase + i]->accel = accel;
+	}
+
+	queues = min_t(unsigned int,
+		       adapter->queues_per_pool, vdev->num_tx_queues);
+	err = netif_set_real_num_tx_queues(vdev, queues);
+	if (err)
+		goto fwd_queue_err;
+
+	err = netif_set_real_num_rx_queues(vdev, queues);
+	if (err)
+		goto fwd_queue_err;
+
+	if (is_valid_ether_addr(vdev->dev_addr))
+		txgbe_add_mac_filter(adapter, vdev->dev_addr,
+				     VMDQ_P(accel->index));
+
+	txgbe_fwd_psrtype(accel);
+	txgbe_macvlan_set_rx_mode(vdev, VMDQ_P(accel->index), adapter);
+
+	for (i = 0; i < adapter->queues_per_pool; i++)
+		txgbe_enable_fwd_ring(accel, adapter->rx_ring[rxbase + i]);
+
+	return err;
+fwd_queue_err:
+	txgbe_fwd_ring_down(vdev, accel);
+	return err;
+}
+
+static void txgbe_configure_dfwd(struct txgbe_adapter *adapter)
+{
+	struct net_device *upper;
+	struct list_head *iter;
+	int err;
+
+	netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+		if (netif_is_macvlan(upper)) {
+			struct macvlan_dev *dfwd = netdev_priv(upper);
+			struct txgbe_fwd_adapter *accel = dfwd->fwd_priv;
+
+			if (accel) {
+				err = txgbe_fwd_ring_up(upper, accel);
+				if (err)
+					continue;
+			}
+		}
+	}
+}
+#endif /*HAVE_VIRTUAL_STATION*/
+
+static void txgbe_configure(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	txgbe_configure_pb(adapter);
+	txgbe_configure_dcb(adapter);
+
+	/*
+	 * We must restore virtualization before VLANs or else
+	 * the VLVF registers will not be populated
+	 */
+	txgbe_configure_virtualization(adapter);
+	txgbe_configure_port(adapter);
+
+	txgbe_set_rx_mode(adapter->netdev);
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	txgbe_restore_vlan(adapter);
+#endif
+
+	TCALL(hw, mac.ops.disable_sec_rx_path);
+
+	if (adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE) {
+		txgbe_init_fdir_signature(&adapter->hw,
+						   adapter->fdir_pballoc);
+	} else if (adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
+		txgbe_init_fdir_perfect(&adapter->hw,
+								adapter->fdir_pballoc,
+								adapter->cloud_mode);
+		txgbe_fdir_filter_restore(adapter);
+	}
+
+	TCALL(hw, mac.ops.enable_sec_rx_path);
+
+	TCALL(hw, mac.ops.setup_eee,
+		(adapter->flags2 & TXGBE_FLAG2_EEE_CAPABLE) &&
+		(adapter->flags2 & TXGBE_FLAG2_EEE_ENABLED));
+
+#if IS_ENABLED(CONFIG_TPH)
+	/* configure TPH */
+	if (adapter->flags & TXGBE_FLAG_TPH_CAPABLE)
+		txgbe_setup_tph(adapter);
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* configure FCoE L2 filters, redirection table, and Rx control */
+	txgbe_configure_fcoe(adapter);
+#endif /* CONFIG_FCOE */
+
+	txgbe_configure_tx(adapter);
+	txgbe_configure_rx(adapter);
+	txgbe_configure_isb(adapter);
+#ifdef HAVE_VIRTUAL_STATION
+	txgbe_configure_dfwd(adapter);
+#endif
+}
+
+static bool txgbe_is_sfp(struct txgbe_hw *hw)
+{
+	switch (TCALL(hw, mac.ops.get_media_type)) {
+	case txgbe_media_type_fiber:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool txgbe_is_backplane(struct txgbe_hw *hw)
+{
+	switch (TCALL(hw, mac.ops.get_media_type)) {
+	case txgbe_media_type_backplane:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/**
+ * txgbe_sfp_link_config - set up SFP+ link
+ * @adapter: pointer to private adapter struct
+ **/
+static void txgbe_sfp_link_config(struct txgbe_adapter *adapter)
+{
+	/*
+	 * We are assuming the worst case scenerio here, and that
+	 * is that an SFP was inserted/removed after the reset
+	 * but before SFP detection was enabled.  As such the best
+	 * solution is to just start searching as soon as we start
+	 */
+
+	adapter->flags2 |= TXGBE_FLAG2_SFP_NEEDS_RESET;
+	adapter->sfp_poll_time = 0;
+}
+
+/**
+ * txgbe_non_sfp_link_config - set up non-SFP+ link
+ * @hw: pointer to private hardware struct
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int txgbe_non_sfp_link_config(struct txgbe_hw *hw)
+{
+	u32 speed;
+	bool autoneg, link_up = false;
+	u32 ret = TXGBE_ERR_LINK_SETUP;
+
+	ret = TCALL(hw, mac.ops.check_link, &speed, &link_up, false);
+
+	if (ret)
+		goto link_cfg_out;
+
+	if (link_up)
+		return 0;
+	
+	if ((hw->subsystem_device_id & 0xF0) != TXGBE_ID_SFI_XAUI) {
+		/* setup external PHY Mac Interface */
+		mtdSetMacInterfaceControl(&hw->phy_dev, hw->phy.addr, MTD_MAC_TYPE_XAUI,
+			MTD_FALSE, MTD_MAC_SNOOP_OFF,
+			0, MTD_MAC_SPEED_1000_MBPS,
+			MTD_MAX_MAC_SPEED_LEAVE_UNCHANGED,
+			MTD_TRUE, MTD_TRUE);
+
+		speed = hw->phy.autoneg_advertised;
+		if (!speed)
+			ret = TCALL(hw, mac.ops.get_link_capabilities, &speed,
+								&autoneg);
+		if (ret)
+			goto link_cfg_out;
+	} else {
+		speed = TXGBE_LINK_SPEED_10GB_FULL;
+		autoneg = false;
+	}
+
+	ret = TCALL(hw, mac.ops.setup_link, speed, false);
+
+link_cfg_out:
+	return ret;
+}
+
+static void txgbe_setup_gpie(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 gpie = 0;
+
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED) {
+		gpie = TXGBE_PX_GPIE_MODEL;
+		/*
+		 * use EIAM to auto-mask when MSI-X interrupt is asserted
+		 * this saves a register write for every interrupt
+		 */
+	} else {
+		/* legacy interrupts, use EIAM to auto-mask when reading EICR,
+		 * specifically only auto mask tx and rx interrupts */
+	}
+
+	wr32(hw, TXGBE_PX_GPIE, gpie);
+}
+
+static void txgbe_up_complete(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int err;
+	u32 links_reg;
+	u16 value;
+
+	txgbe_get_hw_control(adapter);
+	txgbe_setup_gpie(adapter);
+
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED)
+		txgbe_configure_msix(adapter);
+	else
+		txgbe_configure_msi_and_legacy(adapter);
+
+	/* enable the optics for SFP+ fiber */
+	TCALL(hw, mac.ops.enable_tx_laser);
+
+	smp_mb__before_atomic();
+	clear_bit(__TXGBE_DOWN, &adapter->state);
+	txgbe_napi_enable_all(adapter);
+#ifndef TXGBE_NO_LLI
+	txgbe_configure_lli(adapter);
+#endif
+	if (txgbe_is_sfp(hw)) {
+		txgbe_sfp_link_config(adapter);
+	} else if (txgbe_is_backplane(hw)) {
+		adapter->flags |= TXGBE_FLAG_NEED_LINK_CONFIG;
+		txgbe_service_event_schedule(adapter);
+	} else {
+		err = txgbe_non_sfp_link_config(hw);
+		if (err)
+			e_err(probe, "link_config FAILED %d\n", err);
+	}
+
+	links_reg = rd32(hw, TXGBE_CFG_PORT_ST);
+	if (links_reg & TXGBE_CFG_PORT_ST_LINK_UP) {
+		if (links_reg & TXGBE_CFG_PORT_ST_LINK_10G) {
+			wr32(hw, TXGBE_MAC_TX_CFG,
+				(rd32(hw, TXGBE_MAC_TX_CFG) &
+				~TXGBE_MAC_TX_CFG_SPEED_MASK) |
+				TXGBE_MAC_TX_CFG_SPEED_10G);
+		} else if (links_reg & (TXGBE_CFG_PORT_ST_LINK_1G | TXGBE_CFG_PORT_ST_LINK_100M)) {
+			wr32(hw, TXGBE_MAC_TX_CFG,
+				(rd32(hw, TXGBE_MAC_TX_CFG) &
+				~TXGBE_MAC_TX_CFG_SPEED_MASK) |
+				TXGBE_MAC_TX_CFG_SPEED_1G);
+		}
+	}
+
+	/* clear any pending interrupts, may auto mask */
+	rd32(hw, TXGBE_PX_IC(0));
+	rd32(hw, TXGBE_PX_IC(1));
+	rd32(hw, TXGBE_PX_MISC_IC);
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) 
+		wr32(hw, TXGBE_GPIO_EOI, TXGBE_GPIO_EOI_6);
+	txgbe_irq_enable(adapter, true, true);
+
+	/* enable external PHY interrupt */
+	if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_XAUI) {
+		txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 0x03, 0x8011, &value);
+		/* only enable T unit int */
+		txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xf043, 0x1); 
+		/* active high */
+		txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 31, 0xf041, 0x0); 
+		/* enable AN complete and link status change int */
+		txgbe_write_mdio(&hw->phy_dev, hw->phy.addr, 0x03, 0x8010, 0xc00);
+	}
+
+	/* enable transmits */
+	netif_tx_start_all_queues(adapter->netdev);
+
+	/* bring the link up in the watchdog, this could race with our first
+	 * link up interrupt but shouldn't be a problem */
+	adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+	adapter->link_check_timeout = jiffies;
+	hw->f2c_mod_status = false;
+
+	mod_timer(&adapter->service_timer, jiffies);
+#ifdef POLL_LINK_STATUS
+	mod_timer(&adapter->link_check_timer,jiffies);
+#endif
+
+	/* PCIE recovery: record lan status */
+	if (hw->bus.lan_id == 0) {
+		wr32m(hw, TXGBE_MIS_PRB_CTL,
+			TXGBE_MIS_PRB_CTL_LAN0_UP, TXGBE_MIS_PRB_CTL_LAN0_UP);
+	}
+	else if (hw->bus.lan_id == 1) {
+		wr32m(hw, TXGBE_MIS_PRB_CTL,
+			TXGBE_MIS_PRB_CTL_LAN1_UP, TXGBE_MIS_PRB_CTL_LAN1_UP);
+	}
+	else
+		e_err(probe, "txgbe_up_complete:invalid bus lan id %d\n", hw->bus.lan_id);
+
+	/* Set PF Reset Done bit so PF/VF Mail Ops can work */
+	wr32m(hw, TXGBE_CFG_PORT_CTL,
+		TXGBE_CFG_PORT_CTL_PFRSTD, TXGBE_CFG_PORT_CTL_PFRSTD);
+
+	/* update setting rx tx for all active vfs */
+	txgbe_set_all_vfs(adapter);
+}
+
+void txgbe_reinit_locked(struct txgbe_adapter *adapter)
+{
+	if (adapter->flags2 & TXGBE_FLAG2_KR_PRO_REINIT) {
+		return;
+	}
+
+	adapter->flags2 |=  TXGBE_FLAG2_KR_PRO_REINIT;
+	WARN_ON(in_interrupt());
+	/* put off any impending NetWatchDogTimeout */
+#ifdef HAVE_NETIF_TRANS_UPDATE
+	netif_trans_update(adapter->netdev);
+#else
+	adapter->netdev->trans_start = jiffies;
+#endif
+
+	while (test_and_set_bit(__TXGBE_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
+	txgbe_down(adapter);
+	/*
+	 * If SR-IOV enabled then wait a bit before bringing the adapter
+	 * back up to give the VFs time to respond to the reset.  The
+	 * two second wait is based upon the watchdog timer cycle in
+	 * the VF driver.
+	 */
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED)
+		msleep(2000);
+	txgbe_up(adapter);
+	clear_bit(__TXGBE_RESETTING, &adapter->state);
+	adapter->flags2 &= ~TXGBE_FLAG2_KR_PRO_REINIT;
+}
+
+void txgbe_up(struct txgbe_adapter *adapter)
+{
+	/* hardware has been reset, we need to reload some things */
+	txgbe_configure(adapter);
+
+	txgbe_up_complete(adapter);
+}
+
+void txgbe_reset(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int err;
+	u8 old_addr[ETH_ALEN];
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return;
+	/* lock SFP init bit to prevent race conditions with the watchdog */
+	while (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+		usleep_range(1000, 2000);
+
+	/* clear all SFP and link config related flags while holding SFP_INIT */
+	adapter->flags2 &= ~(TXGBE_FLAG2_SEARCH_FOR_SFP |
+			     TXGBE_FLAG2_SFP_NEEDS_RESET);
+	adapter->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG;
+
+	err = TCALL(hw, mac.ops.init_hw);
+	switch (err) {
+	case 0:
+	case TXGBE_ERR_SFP_NOT_PRESENT:
+	case TXGBE_ERR_SFP_NOT_SUPPORTED:
+		break;
+	case TXGBE_ERR_MASTER_REQUESTS_PENDING:
+		e_dev_err("master disable timed out\n");
+		break;
+	case TXGBE_ERR_EEPROM_VERSION:
+		/* We are running on a pre-production device, log a warning */
+		e_dev_warn("This device is a pre-production adapter/LOM. "
+			   "Please be aware there may be issues associated "
+			   "with your hardware.  If you are experiencing "
+			   "problems please contact your hardware "
+			   "representative who provided you with this "
+			   "hardware.\n");
+		break;
+	default:
+		e_dev_err("Hardware Error: %d\n", err);
+	}
+
+	clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+	/* do not flush user set addresses */
+	memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len);
+	txgbe_flush_sw_mac_table(adapter);
+	txgbe_mac_set_default_filter(adapter, old_addr);
+
+	/* update SAN MAC vmdq pool selection */
+	TCALL(hw, mac.ops.set_vmdq_san_mac, VMDQ_P(0));
+
+	/* Clear saved DMA coalescing values except for watchdog_timer */
+	hw->mac.dmac_config.fcoe_en = false;
+	hw->mac.dmac_config.link_speed = 0;
+	hw->mac.dmac_config.fcoe_tc = 0;
+	hw->mac.dmac_config.num_tcs = 0;
+	if(txgbe_is_lldp(hw)) adapter->eth_priv_flags |= TXGBE_ETH_PRIV_FLAG_LLDP;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	if (test_bit(__TXGBE_PTP_RUNNING, &adapter->state))
+		txgbe_ptp_reset(adapter);
+#endif
+}
+
+/**
+ * txgbe_clean_rx_ring - Free Rx Buffers per Queue
+ * @rx_ring: ring to free buffers from
+ **/
+static void txgbe_clean_rx_ring(struct txgbe_ring *rx_ring)
+{
+	struct device *dev = rx_ring->dev;
+	unsigned long size;
+	u16 i;
+
+	/* ring already cleared, nothing to do */
+	if (!rx_ring->rx_buffer_info)
+		return;
+
+	/* Free all the Rx ring sk_buffs */
+	for (i = 0; i < rx_ring->count; i++) {
+		struct txgbe_rx_buffer *rx_buffer = &rx_ring->rx_buffer_info[i];
+		if (rx_buffer->dma) {
+			dma_unmap_single(dev,
+					 rx_buffer->dma,
+					 rx_ring->rx_buf_len,
+					 DMA_FROM_DEVICE);
+			rx_buffer->dma = 0;
+		}
+
+		if (rx_buffer->skb) {
+			struct sk_buff *skb = rx_buffer->skb;
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+			if (TXGBE_CB(skb)->dma_released) {
+				dma_unmap_single(dev,
+						TXGBE_CB(skb)->dma,
+						rx_ring->rx_buf_len,
+						DMA_FROM_DEVICE);
+				TXGBE_CB(skb)->dma = 0;
+				TXGBE_CB(skb)->dma_released = false;
+			}
+
+			if (TXGBE_CB(skb)->page_released)
+				dma_unmap_page(dev,
+					       TXGBE_CB(skb)->dma,
+					       txgbe_rx_bufsz(rx_ring),
+					       DMA_FROM_DEVICE);
+#else
+			/* We need to clean up RSC frag lists */
+			skb = txgbe_merge_active_tail(skb);
+			if (txgbe_close_active_frag_list(skb))
+				dma_unmap_single(dev,
+						 TXGBE_CB(skb)->dma,
+						 rx_ring->rx_buf_len,
+						 DMA_FROM_DEVICE);
+			TXGBE_CB(skb)->dma = 0;
+#endif /* CONFIG_TXGBE_DISABLE_PACKET_SPLIT */
+			dev_kfree_skb(skb);
+			rx_buffer->skb = NULL;
+		}
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+		if (!rx_buffer->page)
+			continue;
+
+		dma_unmap_page(dev, rx_buffer->page_dma,
+			       txgbe_rx_pg_size(rx_ring),
+			       DMA_FROM_DEVICE);
+
+		__free_pages(rx_buffer->page,
+				     txgbe_rx_pg_order(rx_ring));
+		rx_buffer->page = NULL;
+#endif
+	}
+
+	size = sizeof(struct txgbe_rx_buffer) * rx_ring->count;
+	memset(rx_ring->rx_buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(rx_ring->desc, 0, rx_ring->size);
+
+#ifndef CONFIG_TXGBE_DISABLE_PACKET_SPLIT
+	rx_ring->next_to_alloc = 0;
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+#endif
+}
+
+/**
+ * txgbe_clean_tx_ring - Free Tx Buffers
+ * @tx_ring: ring to be cleaned
+ **/
+static void txgbe_clean_tx_ring(struct txgbe_ring *tx_ring)
+{
+	struct txgbe_tx_buffer *tx_buffer_info;
+	unsigned long size;
+	u16 i;
+
+	/* ring already cleared, nothing to do */
+	if (!tx_ring->tx_buffer_info)
+		return;
+
+	/* Free all the Tx ring sk_buffs */
+	for (i = 0; i < tx_ring->count; i++) {
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		txgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
+	}
+
+	netdev_tx_reset_queue(txring_txq(tx_ring));
+
+	size = sizeof(struct txgbe_tx_buffer) * tx_ring->count;
+	memset(tx_ring->tx_buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(tx_ring->desc, 0, tx_ring->size);
+}
+
+/**
+ * txgbe_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void txgbe_clean_all_rx_rings(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		txgbe_clean_rx_ring(adapter->rx_ring[i]);
+}
+
+/**
+ * txgbe_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void txgbe_clean_all_tx_rings(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		txgbe_clean_tx_ring(adapter->tx_ring[i]);
+}
+
+static void txgbe_fdir_filter_exit(struct txgbe_adapter *adapter)
+{
+	struct hlist_node *node;
+	struct txgbe_fdir_filter *filter;
+
+	spin_lock(&adapter->fdir_perfect_lock);
+
+	hlist_for_each_entry_safe(filter, node,
+				  &adapter->fdir_filter_list, fdir_node) {
+		hlist_del(&filter->fdir_node);
+		kfree(filter);
+	}
+	adapter->fdir_filter_count = 0;
+
+	spin_unlock(&adapter->fdir_perfect_lock);
+}
+
+void txgbe_disable_device(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct txgbe_hw *hw = &adapter->hw;
+#ifdef HAVE_VIRTUAL_STATION
+	struct net_device *upper;
+	struct list_head *iter;
+#endif
+	u32 i;
+
+	/* signal that we are down to the interrupt handler */
+	if (test_and_set_bit(__TXGBE_DOWN, &adapter->state))
+		return; /* do nothing if already down */
+
+	txgbe_disable_pcie_master(hw);
+	/* disable receives */
+	TCALL(hw, mac.ops.disable_rx);
+
+	/* disable all enabled rx queues */
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		/* this call also flushes the previous write */
+		txgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
+
+	netif_tx_stop_all_queues(netdev);
+
+	/* call carrier off first to avoid false dev_watchdog timeouts */
+	netif_carrier_off(netdev);
+	netif_tx_disable(netdev);
+#ifdef HAVE_VIRTUAL_STATION
+	/* disable any upper devices */
+	netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+		if (netif_is_macvlan(upper)) {
+			struct macvlan_dev *vlan = netdev_priv(upper);
+
+			if (vlan->fwd_priv) {
+				netif_tx_stop_all_queues(upper);
+				netif_carrier_off(upper);
+				netif_tx_disable(upper);
+			}
+		}
+	}
+#endif
+	txgbe_irq_disable(adapter);
+
+	txgbe_napi_disable_all(adapter);
+
+	adapter->flags2 &= ~(TXGBE_FLAG2_FDIR_REQUIRES_REINIT |
+			     TXGBE_FLAG2_PF_RESET_REQUESTED |
+			     TXGBE_FLAG2_DEV_RESET_REQUESTED |
+			     TXGBE_FLAG2_GLOBAL_RESET_REQUESTED);
+	adapter->flags &= ~TXGBE_FLAG_NEED_LINK_UPDATE;
+
+	del_timer_sync(&adapter->service_timer);
+#ifdef POLL_LINK_STATUS
+	del_timer_sync(&adapter->link_check_timer);
+#endif
+
+	hw->f2c_mod_status = false;
+	cancel_work_sync(&adapter->sfp_sta_task);
+
+	/* PCIE recovery: record lan status, clear */
+	if (hw->bus.lan_id == 0)
+		wr32m(hw, TXGBE_MIS_PRB_CTL,
+			TXGBE_MIS_PRB_CTL_LAN0_UP, 0);
+	else if (hw->bus.lan_id == 1)
+		wr32m(hw, TXGBE_MIS_PRB_CTL,
+			TXGBE_MIS_PRB_CTL_LAN1_UP, 0);
+	else
+		e_dev_err("txgbe_disable_device:invalid bus lan id %d\n", hw->bus.lan_id);
+
+	if (adapter->num_vfs) {
+		/* Clear EITR Select mapping */
+		wr32(&adapter->hw, TXGBE_PX_ITRSEL, 0);
+
+		/* Mark all the VFs as inactive */
+		for (i = 0 ; i < adapter->num_vfs; i++)
+			adapter->vfinfo[i].clear_to_send = 0;
+
+		/* ping all the active vfs to let them know we are going down */
+		txgbe_ping_all_vfs(adapter);
+
+		/* Disable all VFTE/VFRE TX/RX */
+		//txgbe_disable_tx_rx(adapter);
+		txgbe_set_all_vfs(adapter);
+	}
+
+	if (!(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)||
+		((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP))){
+		/* disable mac transmiter */
+		wr32m(hw, TXGBE_MAC_TX_CFG,
+			TXGBE_MAC_TX_CFG_TE, 0);
+	}
+	/* disable transmits in the hardware now that interrupts are off */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		u8 reg_idx = adapter->tx_ring[i]->reg_idx;
+		wr32(hw, TXGBE_PX_TR_CFG(reg_idx),
+				TXGBE_PX_TR_CFG_SWFLSH);
+	}
+
+	/* Disable the Tx DMA engine */
+	wr32m(hw, TXGBE_TDM_CTL, TXGBE_TDM_CTL_TE, 0);
+}
+
+
+void txgbe_down(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	txgbe_disable_device(adapter);
+
+#ifdef HAVE_PCI_ERS
+	if (!pci_channel_offline(adapter->pdev))
+#endif
+		txgbe_reset(adapter);
+
+	if(!(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)))
+		/* power down the optics for SFP+ fiber */
+		TCALL(&adapter->hw, mac.ops.disable_tx_laser);
+
+	txgbe_clean_all_tx_rings(adapter);
+	txgbe_clean_all_rx_rings(adapter);
+}
+
+/**
+ *  txgbe_init_shared_code - Initialize the shared code
+ *  @hw: pointer to hardware structure
+ *
+ *  This will assign function pointers and assign the MAC type and PHY code.
+ *  Does not touch the hardware. This function must be called prior to any
+ *  other function in the shared code. The txgbe_hw structure should be
+ *  memset to 0 prior to calling this function.  The following fields in
+ *  hw structure should be filled in prior to calling this function:
+ *  hw_addr, back, device_id, vendor_id, subsystem_device_id,
+ *  subsystem_vendor_id, and revision_id
+ **/
+s32 txgbe_init_shared_code(struct txgbe_hw *hw)
+{
+	s32 status;
+
+	status = txgbe_init_ops(hw);
+	return status;
+}
+
+/**
+ * txgbe_sw_init - Initialize general software structures (struct txgbe_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * txgbe_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static const u32 def_rss_key[10] = {
+	0xE291D73D, 0x1805EC6C, 0x2A94B30D,
+	0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
+	0x6A3E67EA, 0x14364D17, 0x3BED200D
+};
+
+static int __devinit txgbe_sw_init(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+	int err;
+	unsigned int fdir;
+#if IS_ENABLED(CONFIG_DCB)
+	struct txgbe_dcb_tc_config *tc;
+	int j, bwg_pct;
+#endif /* CONFIG_DCB */
+	u32 ssid = 0;
+
+	/* PCI config space info */
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+	if (hw->revision_id == TXGBE_FAILED_READ_CFG_BYTE &&
+	    txgbe_check_cfg_remove(hw, pdev)) {
+		e_err(probe, "read of revision id failed\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	hw->oem_svid = pdev->subsystem_vendor;
+	hw->oem_ssid = pdev->subsystem_device;	
+	if (pdev->subsystem_vendor == 0x8088) {
+		hw->subsystem_vendor_id = pdev->subsystem_vendor;
+		hw->subsystem_device_id = pdev->subsystem_device;
+	} else {
+		ssid = txgbe_flash_read_dword(hw, 0xfffdc);
+		if (ssid == 0x1) {
+			e_err(probe, "read of internel subsystem device id failed\n");
+			err = -ENODEV;
+			goto out;
+		}
+		hw->subsystem_device_id = (u16)ssid;
+		hw->subsystem_device_id = hw->subsystem_device_id >> 8 | 
+								hw->subsystem_device_id << 8;
+	}
+
+	err = txgbe_init_shared_code(hw);
+	if (err) {
+		e_err(probe, "init_shared_code failed: %d\n", err);
+		goto out;
+	}
+	adapter->mac_table = kzalloc(sizeof(struct txgbe_mac_addr) *
+				     hw->mac.num_rar_entries,
+				     GFP_ATOMIC);
+	if (!adapter->mac_table) {
+		err = TXGBE_ERR_OUT_OF_MEM;
+		e_err(probe, "mac_table allocation failed: %d\n", err);
+		goto out;
+	}
+
+	memcpy(adapter->rss_key, def_rss_key, sizeof(def_rss_key));
+
+	/* Set common capability flags and settings */
+#if IS_ENABLED(CONFIG_TPH)
+	adapter->flags |= TXGBE_FLAG_TPH_CAPABLE;
+#endif
+#if IS_ENABLED(CONFIG_FCOE)
+	adapter->flags |= TXGBE_FLAG_FCOE_CAPABLE;
+	adapter->flags &= ~TXGBE_FLAG_FCOE_ENABLED;
+#if IS_ENABLED(CONFIG_DCB)
+	/* Default traffic class to use for FCoE */
+	adapter->fcoe.up = TXGBE_FCOE_DEFUP;
+	adapter->fcoe.up_set = TXGBE_FCOE_DEFUP;
+#endif /* CONFIG_DCB */
+#endif /* CONFIG_FCOE */
+	adapter->flags |= TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE;
+	adapter->flags2 |= TXGBE_FLAG2_RSC_CAPABLE;
+	fdir = min_t(int, TXGBE_MAX_FDIR_INDICES, num_online_cpus());
+	adapter->ring_feature[RING_F_FDIR].limit = fdir;
+	adapter->max_q_vectors = TXGBE_MAX_MSIX_Q_VECTORS_SAPPHIRE;
+
+	/* Set MAC specific capability flags and exceptions */
+	adapter->flags |= TXGBE_FLAGS_SP_INIT;
+	adapter->flags2 |= TXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
+	hw->phy.smart_speed = txgbe_smart_speed_off;
+	adapter->flags2 |= TXGBE_FLAG2_EEE_CAPABLE;
+	if(txgbe_is_lldp(hw)) {
+		adapter->eth_priv_flags |= TXGBE_ETH_PRIV_FLAG_LLDP;
+		}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* FCoE support exists, always init the FCoE lock */
+	spin_lock_init(&adapter->fcoe.lock);
+#endif /* CONFIG_FCOE */
+
+	/* n-tuple support exists, always init our spinlock */
+	spin_lock_init(&adapter->fdir_perfect_lock);
+
+#if IS_ENABLED(CONFIG_DCB)
+
+	adapter->dcb_cfg.num_tcs.pg_tcs = 8;
+	adapter->dcb_cfg.num_tcs.pfc_tcs = 8;
+
+
+	/* Configure DCB traffic classes */
+	bwg_pct = 100 / adapter->dcb_cfg.num_tcs.pg_tcs;
+	for (j = 0; j < adapter->dcb_cfg.num_tcs.pg_tcs; j++) {
+		tc = &adapter->dcb_cfg.tc_config[j];
+		tc->path[TXGBE_DCB_TX_CONFIG].bwg_id = 0;
+		tc->path[TXGBE_DCB_TX_CONFIG].bwg_percent = bwg_pct;
+		tc->path[TXGBE_DCB_RX_CONFIG].bwg_id = 0;
+		tc->path[TXGBE_DCB_RX_CONFIG].bwg_percent = bwg_pct;
+		tc->pfc = txgbe_dcb_pfc_disabled;
+	}
+
+	/* reset back to TC 0 */
+	tc = &adapter->dcb_cfg.tc_config[0];
+
+	/* total of all TCs bandwidth needs to be 100 */
+	bwg_pct += 100 % adapter->dcb_cfg.num_tcs.pg_tcs;
+	tc->path[TXGBE_DCB_TX_CONFIG].bwg_percent = bwg_pct;
+	tc->path[TXGBE_DCB_RX_CONFIG].bwg_percent = bwg_pct;
+
+	/* Initialize default user to priority mapping, UPx->TC0 */
+	tc->path[TXGBE_DCB_TX_CONFIG].up_to_tc_bitmap = 0xFF;
+	tc->path[TXGBE_DCB_RX_CONFIG].up_to_tc_bitmap = 0xFF;
+
+	adapter->dcb_cfg.bw_percentage[TXGBE_DCB_TX_CONFIG][0] = 100;
+	adapter->dcb_cfg.bw_percentage[TXGBE_DCB_RX_CONFIG][0] = 100;
+	adapter->dcb_cfg.rx_pba_cfg = txgbe_dcb_pba_equal;
+	adapter->dcb_cfg.pfc_mode_enable = false;
+	adapter->dcb_cfg.round_robin_enable = false;
+	adapter->dcb_set_bitmap = 0x00;
+	adapter->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_CEE;
+	memcpy(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
+	       sizeof(adapter->temp_dcb_cfg));
+#endif /* CONFIG_DCB */
+
+	TCALL(hw, mbx.ops.init_params);
+
+	/* default flow control settings */
+	hw->fc.requested_mode = txgbe_fc_full;
+	hw->fc.current_mode = txgbe_fc_full;    /* init for ethtool output */
+
+	adapter->last_lfc_mode = hw->fc.current_mode;
+	hw->fc.pause_time = TXGBE_DEFAULT_FCPAUSE;
+	hw->fc.send_xon = true;
+	hw->fc.disable_fc_autoneg = false;
+
+	/* set default ring sizes */
+	adapter->tx_ring_count = TXGBE_DEFAULT_TXD;
+	adapter->rx_ring_count = TXGBE_DEFAULT_RXD;
+
+	/* set default work limits */
+	adapter->tx_work_limit = TXGBE_DEFAULT_TX_WORK;
+	adapter->rx_work_limit = TXGBE_DEFAULT_RX_WORK;
+
+	adapter->tx_timeout_recovery_level = 0;
+
+	/* PF holds first pool slot */
+	adapter->num_vmdqs = 1;
+	set_bit(0, &adapter->fwd_bitmask);
+	set_bit(__TXGBE_DOWN, &adapter->state);
+out:
+	return err;
+}
+
+/**
+ * txgbe_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @tx_ring:    tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int txgbe_setup_tx_resources(struct txgbe_ring *tx_ring)
+{
+	struct device *dev = tx_ring->dev;
+	int orig_node = dev_to_node(dev);
+	int numa_node = -1;
+	int size;
+
+	size = sizeof(struct txgbe_tx_buffer) * tx_ring->count;
+
+	if (tx_ring->q_vector)
+		numa_node = tx_ring->q_vector->numa_node;
+
+	tx_ring->tx_buffer_info = vzalloc_node(size, numa_node);
+	if (!tx_ring->tx_buffer_info)
+		tx_ring->tx_buffer_info = vzalloc(size);
+	if (!tx_ring->tx_buffer_info)
+		goto err;
+
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(union txgbe_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+	set_dev_node(dev, numa_node);
+	tx_ring->desc = dma_alloc_coherent(dev,
+					   tx_ring->size,
+					   &tx_ring->dma,
+					   GFP_KERNEL);
+	set_dev_node(dev, orig_node);
+	if (!tx_ring->desc)
+		tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
+						   &tx_ring->dma, GFP_KERNEL);
+	if (!tx_ring->desc)
+		goto err;
+
+	return 0;
+
+err:
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+	dev_err(dev, "Unable to allocate memory for the Tx descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * txgbe_setup_all_tx_resources - allocate all queues Tx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int txgbe_setup_all_tx_resources(struct txgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		err = txgbe_setup_tx_resources(adapter->tx_ring[i]);
+		if (!err)
+			continue;
+
+		e_err(probe, "Allocation for Tx Queue %u failed\n", i);
+		goto err_setup_tx;
+	}
+
+	return 0;
+err_setup_tx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		txgbe_free_tx_resources(adapter->tx_ring[i]);
+	return err;
+}
+
+/**
+ * txgbe_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @rx_ring:    rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int txgbe_setup_rx_resources(struct txgbe_ring *rx_ring)
+{
+	struct device *dev = rx_ring->dev;
+	int orig_node = dev_to_node(dev);
+	int numa_node = -1;
+	int size;
+
+	size = sizeof(struct txgbe_rx_buffer) * rx_ring->count;
+
+	if (rx_ring->q_vector)
+		numa_node = rx_ring->q_vector->numa_node;
+
+	rx_ring->rx_buffer_info = vzalloc_node(size, numa_node);
+	if (!rx_ring->rx_buffer_info)
+		rx_ring->rx_buffer_info = vzalloc(size);
+	if (!rx_ring->rx_buffer_info)
+		goto err;
+
+	/* Round up to nearest 4K */
+	rx_ring->size = rx_ring->count * sizeof(union txgbe_rx_desc);
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+	set_dev_node(dev, numa_node);
+	rx_ring->desc = dma_alloc_coherent(dev,
+					   rx_ring->size,
+					   &rx_ring->dma,
+					   GFP_KERNEL);
+	set_dev_node(dev, orig_node);
+	if (!rx_ring->desc)
+		rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
+						   &rx_ring->dma, GFP_KERNEL);
+	if (!rx_ring->desc)
+		goto err;
+
+	return 0;
+err:
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+	dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * txgbe_setup_all_rx_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int txgbe_setup_all_rx_resources(struct txgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		err = txgbe_setup_rx_resources(adapter->rx_ring[i]);
+		if (!err) {
+			continue;
+		}
+
+		e_err(probe, "Allocation for Rx Queue %u failed\n", i);
+		goto err_setup_rx;
+	}
+
+#if IS_ENABLED(CONFIG_FCOE)
+	err = txgbe_setup_fcoe_ddp_resources(adapter);
+	if (!err)
+#endif
+		return 0;
+err_setup_rx:
+	/* rewind the index freeing the rings as we go */
+	while (i--)
+		txgbe_free_rx_resources(adapter->rx_ring[i]);
+	return err;
+}
+
+/**
+ * txgbe_setup_isb_resources - allocate interrupt status resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+int txgbe_setup_isb_resources(struct txgbe_adapter *adapter)
+{
+	struct device *dev = pci_dev_to_dev(adapter->pdev);
+
+	adapter->isb_mem = dma_alloc_coherent(dev,
+					   sizeof(u32) * TXGBE_ISB_MAX,
+					   &adapter->isb_dma,
+					   GFP_KERNEL);
+	if (!adapter->isb_mem)
+		return -ENOMEM;
+	memset(adapter->isb_mem, 0, sizeof(u32) * TXGBE_ISB_MAX);
+	return 0;
+}
+
+/**
+ * txgbe_free_isb_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+void txgbe_free_isb_resources(struct txgbe_adapter *adapter)
+{
+	struct device *dev = pci_dev_to_dev(adapter->pdev);
+
+	dma_free_coherent(dev, sizeof(u32) * TXGBE_ISB_MAX,
+			  adapter->isb_mem, adapter->isb_dma);
+	adapter->isb_mem = NULL;
+}
+
+/**
+ * txgbe_free_tx_resources - Free Tx Resources per Queue
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+void txgbe_free_tx_resources(struct txgbe_ring *tx_ring)
+{
+	txgbe_clean_tx_ring(tx_ring);
+
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!tx_ring->desc)
+		return;
+
+	dma_free_coherent(tx_ring->dev, tx_ring->size,
+			  tx_ring->desc, tx_ring->dma);
+	tx_ring->desc = NULL;
+}
+
+/**
+ * txgbe_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void txgbe_free_all_tx_resources(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		txgbe_free_tx_resources(adapter->tx_ring[i]);
+}
+
+/**
+ * txgbe_free_rx_resources - Free Rx Resources
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+void txgbe_free_rx_resources(struct txgbe_ring *rx_ring)
+{
+	txgbe_clean_rx_ring(rx_ring);
+
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+
+	/* if not set, then don't free */
+	if (!rx_ring->desc)
+		return;
+
+	dma_free_coherent(rx_ring->dev, rx_ring->size,
+			  rx_ring->desc, rx_ring->dma);
+
+	rx_ring->desc = NULL;
+}
+
+/**
+ * txgbe_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void txgbe_free_all_rx_resources(struct txgbe_adapter *adapter)
+{
+	int i;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	txgbe_free_fcoe_ddp_resources(adapter);
+#endif
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		txgbe_free_rx_resources(adapter->rx_ring[i]);
+}
+
+/**
+ * txgbe_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int txgbe_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#ifndef HAVE_NETDEVICE_MIN_MAX_MTU
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+#endif
+
+#ifndef HAVE_NETDEVICE_MIN_MAX_MTU
+	/* MTU < 68 is an error and causes problems on some kernels */
+	if ((new_mtu < 68) || (max_frame > TXGBE_MAX_JUMBO_FRAME_SIZE))
+		return -EINVAL;
+#else
+	if ((new_mtu < 68) || (new_mtu > 9414))
+		return -EINVAL;
+#endif
+
+	/*
+	 * we cannot allow legacy VFs to enable their receive
+	 * paths when MTU greater than 1500 is configured.  So display a
+	 * warning that legacy VFs will be disabled.
+	 */
+	if ((adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) &&
+#ifndef HAVE_NETDEVICE_MIN_MAX_MTU
+	    (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)))
+#else
+	    (new_mtu > ETH_DATA_LEN))
+#endif
+		e_warn(probe, "Setting MTU > 1500 will disable legacy VFs\n");
+
+	e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
+
+	/* must set new MTU before calling down or up */
+	netdev->mtu = new_mtu;
+
+	if (netif_running(netdev))
+		txgbe_reinit_locked(adapter);
+
+	return 0;
+}
+
+/**
+ * txgbe_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+int txgbe_open(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int err;
+
+	/*special for backplane flow*/
+	adapter->flags2 &= ~TXGBE_FLAG2_KR_PRO_DOWN;
+	
+	/* disallow open during test */
+	if (test_bit(__TXGBE_TESTING, &adapter->state))
+		return -EBUSY;
+
+	netif_carrier_off(netdev);
+
+	/* allocate transmit descriptors */
+	err = txgbe_setup_all_tx_resources(adapter);
+	if (err)
+		goto err_setup_tx;
+
+	/* allocate receive descriptors */
+	err = txgbe_setup_all_rx_resources(adapter);
+	if (err)
+		goto err_setup_rx;
+
+	err = txgbe_setup_isb_resources(adapter);
+	if (err)
+		goto err_req_isb;
+
+	txgbe_configure(adapter);
+
+	err = txgbe_request_irq(adapter);
+	if (err)
+		goto err_req_irq;
+
+	/* Notify the stack of the actual queue counts. */
+	err = netif_set_real_num_tx_queues(netdev, adapter->num_vmdqs > 1
+					   ? adapter->queues_per_pool
+					   : adapter->num_tx_queues);
+	if (err)
+		goto err_set_queues;
+
+	err = netif_set_real_num_rx_queues(netdev, adapter->num_vmdqs > 1
+					   ? adapter->queues_per_pool
+					   : adapter->num_rx_queues);
+	if (err)
+		goto err_set_queues;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	txgbe_ptp_init(adapter);
+#endif
+
+	txgbe_up_complete(adapter);
+
+#if defined(HAVE_UDP_ENC_RX_OFFLOAD) && defined(HAVE_UDP_TUNNEL_NIC_INFO)
+	udp_tunnel_nic_reset_ntf(netdev);
+#else
+#if defined(HAVE_UDP_ENC_RX_OFFLOAD) || defined(HAVE_VXLAN_RX_OFFLOAD)
+	txgbe_clear_vxlan_port(adapter);
+#endif
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+	udp_tunnel_get_rx_info(netdev);
+#elif defined(HAVE_VXLAN_RX_OFFLOAD)
+	vxlan_get_rx_port(netdev);
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD */
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD && HAVE_UDP_TUNNEL_NIC_INFO */
+	return 0;
+
+err_set_queues:
+	txgbe_free_irq(adapter);
+err_req_irq:
+	txgbe_free_isb_resources(adapter);
+err_req_isb:
+	txgbe_free_all_rx_resources(adapter);
+
+err_setup_rx:
+	txgbe_free_all_tx_resources(adapter);
+err_setup_tx:
+	txgbe_reset(adapter);
+
+	return err;
+}
+
+/**
+ * txgbe_close_suspend - actions necessary to both suspend and close flows
+ * @adapter: the private adapter struct
+ *
+ * This function should contain the necessary work common to both suspending
+ * and closing of the device.
+ */
+static void txgbe_close_suspend(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	txgbe_ptp_suspend(adapter);
+#endif
+	txgbe_disable_device(adapter);
+	if(!((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP))
+		TCALL(hw, mac.ops.disable_tx_laser);
+	txgbe_clean_all_tx_rings(adapter);
+	txgbe_clean_all_rx_rings(adapter);
+
+	txgbe_free_irq(adapter);
+
+	txgbe_free_isb_resources(adapter);
+	txgbe_free_all_rx_resources(adapter);
+	txgbe_free_all_tx_resources(adapter);
+}
+
+/**
+ * txgbe_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+int txgbe_close(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if ( hw->subsystem_device_id == TXGBE_ID_WX1820_KR_KX_KX4 ||
+		hw->subsystem_device_id == TXGBE_ID_SP1000_KR_KX_KX4 ){
+		txgbe_bp_close_protect(adapter);
+	}
+
+#ifdef HAVE_PTP_1588_CLOCK
+	txgbe_ptp_stop(adapter);
+#endif
+
+	txgbe_down(adapter);
+	txgbe_free_irq(adapter);
+
+	txgbe_free_isb_resources(adapter);
+	txgbe_free_all_rx_resources(adapter);
+	txgbe_free_all_tx_resources(adapter);
+
+	txgbe_fdir_filter_exit(adapter);
+
+	txgbe_release_hw_control(adapter);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+#ifndef USE_LEGACY_PM_SUPPORT
+static int txgbe_resume(struct device *dev)
+#else
+static int txgbe_resume(struct pci_dev *pdev)
+#endif /* USE_LEGACY_PM_SUPPORT */
+{
+	struct txgbe_adapter *adapter;
+	struct net_device *netdev;
+	u32 err;
+#ifndef USE_LEGACY_PM_SUPPORT
+	struct pci_dev *pdev = to_pci_dev(dev);
+#endif
+
+	adapter = pci_get_drvdata(pdev);
+	netdev = adapter->netdev;
+	adapter->hw.hw_addr = adapter->io_addr;
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	/*
+	 * pci_restore_state clears dev->state_saved so call
+	 * pci_save_state to restore it.
+	 */
+	pci_save_state(pdev);
+
+	err = pci_enable_device_mem(pdev);
+	if (err) {
+		e_dev_err("Cannot enable PCI device from suspend\n");
+		return err;
+	}
+	smp_mb__before_atomic();
+	clear_bit(__TXGBE_DISABLED, &adapter->state);
+	pci_set_master(pdev);
+
+	pci_wake_from_d3(pdev, false);
+
+	txgbe_reset(adapter);
+
+	rtnl_lock();
+
+	err = txgbe_init_interrupt_scheme(adapter);
+	if (!err && netif_running(netdev))
+		err = txgbe_open(netdev);
+
+	rtnl_unlock();
+
+	if (err)
+		return err;
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+
+#ifndef USE_LEGACY_PM_SUPPORT
+/**
+ * txgbe_freeze - quiesce the device (no IRQ's or DMA)
+ * @dev: The port's netdev
+ */
+static int txgbe_freeze(struct device *dev)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(to_pci_dev(dev));
+	struct net_device *netdev = adapter->netdev;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		txgbe_down(adapter);
+		txgbe_free_irq(adapter);
+	}
+
+	txgbe_reset_interrupt_capability(adapter);
+
+	return 0;
+}
+
+/**
+ * txgbe_thaw - un-quiesce the device
+ * @dev: The port's netdev
+ */
+static int txgbe_thaw(struct device *dev)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(to_pci_dev(dev));
+	struct net_device *netdev = adapter->netdev;
+
+	txgbe_set_interrupt_capability(adapter);
+
+	if (netif_running(netdev)) {
+		u32 err = txgbe_request_irq(adapter);
+		if (err)
+			return err;
+
+		txgbe_up(adapter);
+	}
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+#endif /* USE_LEGACY_PM_SUPPORT */
+#endif /* CONFIG_PM */
+
+/*
+ * __txgbe_shutdown is not used when power management
+ * is disabled on older kernels (<2.6.12). causes a compile
+ * warning/error, because it is defined and not used.
+ */
+#if defined(CONFIG_PM) || !defined(USE_REBOOT_NOTIFIER)
+static int __txgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 wufc = adapter->wol;
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	netif_device_detach(netdev);
+
+	rtnl_lock();
+	if (netif_running(netdev))
+		txgbe_close_suspend(adapter);
+	rtnl_unlock();
+
+	txgbe_clear_interrupt_scheme(adapter);
+
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+
+	/* this won't stop link of managebility or WoL is enabled */
+	txgbe_stop_mac_link_on_d3(hw);
+
+	if (wufc) {
+		txgbe_set_rx_mode(netdev);
+		txgbe_configure_rx(adapter);
+		/* enable the optics for SFP+ fiber as we can WoL */
+		TCALL(hw, mac.ops.enable_tx_laser);
+
+		/* turn on all-multi mode if wake on multicast is enabled */
+		if (wufc & TXGBE_PSR_WKUP_CTL_MC) {
+			wr32m(hw, TXGBE_PSR_CTL,
+				TXGBE_PSR_CTL_MPE, TXGBE_PSR_CTL_MPE);
+		}
+
+		pci_clear_master(adapter->pdev);
+		wr32(hw, TXGBE_PSR_WKUP_CTL, wufc);
+	} else {
+		wr32(hw, TXGBE_PSR_WKUP_CTL, 0);
+	}
+
+	pci_wake_from_d3(pdev, !!wufc);
+
+	*enable_wake = !!wufc;
+	txgbe_release_hw_control(adapter);
+
+	if (!test_and_set_bit(__TXGBE_DISABLED, &adapter->state))
+		pci_disable_device(pdev);
+
+	return 0;
+}
+#endif /* defined(CONFIG_PM) || !defined(USE_REBOOT_NOTIFIER) */
+
+#ifdef CONFIG_PM
+#ifndef USE_LEGACY_PM_SUPPORT
+static int txgbe_suspend(struct device *dev)
+#else
+static int txgbe_suspend(struct pci_dev *pdev,
+			 pm_message_t __always_unused state)
+#endif /* USE_LEGACY_PM_SUPPORT */
+{
+	int retval;
+	bool wake;
+#ifndef USE_LEGACY_PM_SUPPORT
+	struct pci_dev *pdev = to_pci_dev(dev);
+#endif
+
+	retval = __txgbe_shutdown(pdev, &wake);
+	if (retval)
+		return retval;
+
+	if (wake) {
+		pci_prepare_to_sleep(pdev);
+	} else {
+		pci_wake_from_d3(pdev, false);
+		pci_set_power_state(pdev, PCI_D3hot);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifndef USE_REBOOT_NOTIFIER
+static void txgbe_shutdown(struct pci_dev *pdev)
+{
+	bool wake;
+
+	__txgbe_shutdown(pdev, &wake);
+
+	if (system_state == SYSTEM_POWER_OFF) {
+		pci_wake_from_d3(pdev, wake);
+		pci_set_power_state(pdev, PCI_D3hot);
+	}
+}
+
+#endif
+#ifdef HAVE_NDO_GET_STATS64
+/**
+ * txgbe_get_stats64 - Get System Network Statistics
+ * @netdev: network interface device structure
+ * @stats: storage space for 64bit statistics
+ *
+ * Returns 64bit statistics, for use in the ndo_get_stats64 callback. This
+ * function replaces txgbe_get_stats for kernels which support it.
+ */
+#ifdef HAVE_VOID_NDO_GET_STATS64
+static void txgbe_get_stats64(struct net_device *netdev,
+			      struct rtnl_link_stats64 *stats)
+#else
+static struct rtnl_link_stats64 *txgbe_get_stats64(struct net_device *netdev,
+						   struct rtnl_link_stats64 *stats)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	rcu_read_lock();
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct txgbe_ring *ring = READ_ONCE(adapter->rx_ring[i]);
+		u64 bytes, packets;
+		unsigned int start;
+
+		if (ring) {
+			do {
+				start = u64_stats_fetch_begin_irq(&ring->syncp);
+				packets = ring->stats.packets;
+				bytes   = ring->stats.bytes;
+			} while (u64_stats_fetch_retry_irq(&ring->syncp,
+				 start));
+			stats->rx_packets += packets;
+			stats->rx_bytes   += bytes;
+		}
+	}
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct txgbe_ring *ring = READ_ONCE(adapter->tx_ring[i]);
+		u64 bytes, packets;
+		unsigned int start;
+
+		if (ring) {
+			do {
+				start = u64_stats_fetch_begin_irq(&ring->syncp);
+				packets = ring->stats.packets;
+				bytes   = ring->stats.bytes;
+			} while (u64_stats_fetch_retry_irq(&ring->syncp,
+				 start));
+			stats->tx_packets += packets;
+			stats->tx_bytes   += bytes;
+		}
+	}
+	rcu_read_unlock();
+	/* following stats updated by txgbe_watchdog_task() */
+	stats->multicast        = netdev->stats.multicast;
+	stats->rx_errors        = netdev->stats.rx_errors;
+	stats->rx_length_errors = netdev->stats.rx_length_errors;
+	stats->rx_crc_errors    = netdev->stats.rx_crc_errors;
+	stats->rx_missed_errors = netdev->stats.rx_missed_errors;
+#ifndef HAVE_VOID_NDO_GET_STATS64
+	return stats;
+#endif
+}
+#else
+/**
+ * txgbe_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *txgbe_get_stats(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* update the stats data */
+	txgbe_update_stats(adapter);
+
+#ifdef HAVE_NETDEV_STATS_IN_NETDEV
+	/* only return the current stats */
+	return &netdev->stats;
+#else
+	/* only return the current stats */
+	return &adapter->net_stats;
+#endif /* HAVE_NETDEV_STATS_IN_NETDEV */
+}
+#endif
+
+/**
+ * txgbe_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void txgbe_update_stats(struct txgbe_adapter *adapter)
+{
+#ifdef HAVE_NETDEV_STATS_IN_NETDEV
+	struct net_device_stats *net_stats = &adapter->netdev->stats;
+#else
+	struct net_device_stats *net_stats = &adapter->net_stats;
+#endif /* HAVE_NETDEV_STATS_IN_NETDEV */
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_hw_stats *hwstats = &adapter->stats;
+	u64 total_mpc = 0;
+	u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff;
+	u64 non_eop_descs = 0, restart_queue = 0, tx_busy = 0;
+	u64 alloc_rx_page_failed = 0, alloc_rx_buff_failed = 0;
+	u64 bytes = 0, packets = 0, hw_csum_rx_error = 0;
+	u64 hw_csum_rx_good = 0;
+#ifndef TXGBE_NO_LRO
+	u32 flushed = 0, coal = 0;
+#endif
+
+	if (test_bit(__TXGBE_DOWN, &adapter->state) ||
+	    test_bit(__TXGBE_RESETTING, &adapter->state))
+		return;
+
+	if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED) {
+		u64 rsc_count = 0;
+		u64 rsc_flush = 0;
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			rsc_count += adapter->rx_ring[i]->rx_stats.rsc_count;
+			rsc_flush += adapter->rx_ring[i]->rx_stats.rsc_flush;
+		}
+		adapter->rsc_total_count = rsc_count;
+		adapter->rsc_total_flush = rsc_flush;
+	}
+
+#ifndef TXGBE_NO_LRO
+	for (i = 0; i < adapter->num_q_vectors; i++) {
+		struct txgbe_q_vector *q_vector = adapter->q_vector[i];
+		if (!q_vector)
+			continue;
+		flushed += q_vector->lrolist.stats.flushed;
+		coal += q_vector->lrolist.stats.coal;
+	}
+	adapter->lro_stats.flushed = flushed;
+	adapter->lro_stats.coal = coal;
+
+#endif
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct txgbe_ring *rx_ring = adapter->rx_ring[i];
+		non_eop_descs += rx_ring->rx_stats.non_eop_descs;
+		alloc_rx_page_failed += rx_ring->rx_stats.alloc_rx_page_failed;
+		alloc_rx_buff_failed += rx_ring->rx_stats.alloc_rx_buff_failed;
+		hw_csum_rx_error += rx_ring->rx_stats.csum_err;
+		hw_csum_rx_good += rx_ring->rx_stats.csum_good_cnt;
+		bytes += rx_ring->stats.bytes;
+		packets += rx_ring->stats.packets;
+
+	}
+	adapter->non_eop_descs = non_eop_descs;
+	adapter->alloc_rx_page_failed = alloc_rx_page_failed;
+	adapter->alloc_rx_buff_failed = alloc_rx_buff_failed;
+	adapter->hw_csum_rx_error = hw_csum_rx_error;
+	adapter->hw_csum_rx_good = hw_csum_rx_good;
+	net_stats->rx_bytes = bytes;
+	net_stats->rx_packets = packets;
+
+	bytes = 0;
+	packets = 0;
+	/* gather some stats to the adapter struct that are per queue */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct txgbe_ring *tx_ring = adapter->tx_ring[i];
+		restart_queue += tx_ring->tx_stats.restart_queue;
+		tx_busy += tx_ring->tx_stats.tx_busy;
+		bytes += tx_ring->stats.bytes;
+		packets += tx_ring->stats.packets;
+	}
+	adapter->restart_queue = restart_queue;
+	adapter->tx_busy = tx_busy;
+	net_stats->tx_bytes = bytes;
+	net_stats->tx_packets = packets;
+
+	hwstats->crcerrs += rd32(hw, TXGBE_RX_CRC_ERROR_FRAMES_LOW);
+
+	/* 8 register reads */
+	for (i = 0; i < 8; i++) {
+		/* for packet buffers not used, the register should read 0 */
+		mpc = rd32(hw, TXGBE_RDB_MPCNT(i));
+		missed_rx += mpc;
+		hwstats->mpc[i] += mpc;
+		total_mpc += hwstats->mpc[i];
+		hwstats->pxontxc[i] += rd32(hw, TXGBE_RDB_PXONTXC(i));
+		hwstats->pxofftxc[i] +=
+				rd32(hw, TXGBE_RDB_PXOFFTXC(i));
+		hwstats->pxonrxc[i] += rd32(hw, TXGBE_MAC_PXONRXC(i));
+	}
+
+	hwstats->gprc += rd32(hw, TXGBE_PX_GPRC);
+
+	txgbe_update_xoff_received(adapter);
+
+	hwstats->o2bgptc += rd32(hw, TXGBE_TDM_OS2BMC_CNT);
+	if (txgbe_check_mng_access(&adapter->hw)) {
+		hwstats->o2bspc += rd32(hw, TXGBE_MNG_OS2BMC_CNT);
+		hwstats->b2ospc += rd32(hw, TXGBE_MNG_BMC2OS_CNT);
+	}
+	hwstats->b2ogprc += rd32(hw, TXGBE_RDM_BMC2OS_CNT);
+	hwstats->gorc += rd32(hw, TXGBE_PX_GORC_LSB);
+	hwstats->gorc += (u64)rd32(hw, TXGBE_PX_GORC_MSB) << 32;
+
+	hwstats->gotc += rd32(hw, TXGBE_PX_GOTC_LSB);
+	hwstats->gotc += (u64)rd32(hw, TXGBE_PX_GOTC_MSB) << 32;
+
+
+	adapter->hw_rx_no_dma_resources +=
+				     rd32(hw, TXGBE_RDM_DRP_PKT);
+	hwstats->lxonrxc += rd32(hw, TXGBE_MAC_LXONRXC);
+#ifdef HAVE_TX_MQ
+	hwstats->fdirmatch += rd32(hw, TXGBE_RDB_FDIR_MATCH);
+	hwstats->fdirmiss += rd32(hw, TXGBE_RDB_FDIR_MISS);
+#endif /* HAVE_TX_MQ */
+#if IS_ENABLED(CONFIG_FCOE)
+	hwstats->fccrc += rd32(hw, TXGBE_FCCRC);
+	hwstats->fclast += rd32(hw, TXGBE_FCLAST);
+	hwstats->fcoerpdc += rd32(hw, TXGBE_FCOERPDC);
+	hwstats->fcoeprc += rd32(hw, TXGBE_FCOEPRC);
+	hwstats->fcoeptc += rd32(hw, TXGBE_FCOEPTC);
+	hwstats->fcoedwrc += rd32(hw, TXGBE_FCOEDWRC);
+	hwstats->fcoedwtc += rd32(hw, TXGBE_FCOEDWTC);
+	/* Add up per cpu counters for total ddp alloc fail */
+	if (adapter->fcoe.ddp_pool) {
+		struct txgbe_fcoe *fcoe = &adapter->fcoe;
+		struct txgbe_fcoe_ddp_pool *ddp_pool;
+		unsigned int cpu;
+		u64 noddp = 0, noddp_ext_buff = 0;
+		for_each_possible_cpu(cpu) {
+			ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu);
+			noddp += ddp_pool->noddp;
+			noddp_ext_buff += ddp_pool->noddp_ext_buff;
+		}
+		hwstats->fcoe_noddp = noddp;
+		hwstats->fcoe_noddp_ext_buff = noddp_ext_buff;
+	}
+
+#endif /* CONFIG_FCOE */
+
+	bprc = rd32(hw, TXGBE_RX_BC_FRAMES_GOOD_LOW);
+	hwstats->bprc += bprc;
+	hwstats->mprc = 0;
+
+	for (i = 0; i < 128; i++)
+		hwstats->mprc += rd32(hw, TXGBE_PX_MPRC(i));
+
+
+	hwstats->roc += rd32(hw, TXGBE_RX_OVERSIZE_FRAMES_GOOD);
+	hwstats->rlec += rd32(hw, TXGBE_RX_LEN_ERROR_FRAMES_LOW);
+	lxon = rd32(hw, TXGBE_RDB_LXONTXC);
+	hwstats->lxontxc += lxon;
+	lxoff = rd32(hw, TXGBE_RDB_LXOFFTXC);
+	hwstats->lxofftxc += lxoff;
+
+	hwstats->gptc += rd32(hw, TXGBE_PX_GPTC);
+	hwstats->mptc += rd32(hw, TXGBE_TX_MC_FRAMES_GOOD_LOW);
+	hwstats->ruc += rd32(hw, TXGBE_RX_UNDERSIZE_FRAMES_GOOD);
+	hwstats->tpr += rd32(hw, TXGBE_RX_FRAME_CNT_GOOD_BAD_LOW);
+	hwstats->bptc += rd32(hw, TXGBE_TX_BC_FRAMES_GOOD_LOW);
+	/* Fill out the OS statistics structure */
+	net_stats->multicast = hwstats->mprc;
+
+	/* Rx Errors */
+	net_stats->rx_errors = hwstats->crcerrs +
+				       hwstats->rlec;
+	net_stats->rx_dropped = 0;
+	net_stats->rx_length_errors = hwstats->rlec;
+	net_stats->rx_crc_errors = hwstats->crcerrs;
+	net_stats->rx_missed_errors = total_mpc;
+
+}
+
+#ifdef HAVE_TX_MQ
+/**
+ * txgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table
+ * @adapter - pointer to the device adapter structure
+ **/
+static void txgbe_fdir_reinit_subtask(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int i;
+
+	if (!(adapter->flags2 & TXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+		return;
+
+	adapter->flags2 &= ~TXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+
+	/* if interface is down do nothing */
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return;
+
+	/* do nothing if we are not using signature filters */
+	if (!(adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE))
+		return;
+
+	adapter->fdir_overflow++;
+
+	if (txgbe_reinit_fdir_tables(hw) == 0) {
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			set_bit(__TXGBE_TX_FDIR_INIT_DONE,
+				&(adapter->tx_ring[i]->state));
+		/* re-enable flow director interrupts */
+		wr32m(hw, TXGBE_PX_MISC_IEN,
+			TXGBE_PX_MISC_IEN_FLOW_DIR, TXGBE_PX_MISC_IEN_FLOW_DIR);
+	} else {
+		e_err(probe, "failed to finish FDIR re-initialization, "
+		      "ignored adding FDIR ATR filters\n");
+	}
+}
+#endif /* HAVE_TX_MQ */
+
+/**
+ * txgbe_check_hang_subtask - check for hung queues and dropped interrupts
+ * @adapter - pointer to the device adapter structure
+ *
+ * This function serves two purposes.  First it strobes the interrupt lines
+ * in order to make certain interrupts are occurring.  Secondly it sets the
+ * bits needed to check for TX hangs.  As a result we should immediately
+ * determine if a hang has occurred.
+ */
+static void txgbe_check_hang_subtask(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	/* If we're down or resetting, just bail */
+	if (test_bit(__TXGBE_DOWN, &adapter->state) ||
+	    test_bit(__TXGBE_REMOVING, &adapter->state) ||
+	    test_bit(__TXGBE_RESETTING, &adapter->state))
+		return;
+
+	/* Force detection of hung controller */
+	if (netif_carrier_ok(adapter->netdev)) {
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			set_check_for_tx_hang(adapter->tx_ring[i]);
+	}
+
+}
+
+/**
+ * txgbe_watchdog_update_link - update the link status
+ * @adapter - pointer to the device adapter structure
+ * @link_speed - pointer to a u32 to store the link_speed
+ **/
+static void txgbe_watchdog_update_link(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 link_speed = adapter->link_speed;
+	bool link_up = adapter->link_up;
+	bool pfc_en = adapter->dcb_cfg.pfc_mode_enable;
+	u32 reg;
+	u32 __maybe_unused i = 1;
+
+#ifndef POLL_LINK_STATUS
+	if (!(adapter->flags & TXGBE_FLAG_NEED_LINK_UPDATE))
+		return;
+#endif
+
+	link_speed = TXGBE_LINK_SPEED_10GB_FULL;
+	link_up = true;
+	TCALL(hw, mac.ops.check_link, &link_speed, &link_up, false);
+
+#ifndef POLL_LINK_STATUS
+	if (link_up || time_after(jiffies, (adapter->link_check_timeout +
+		TXGBE_TRY_LINK_TIMEOUT))) {
+		adapter->flags &= ~TXGBE_FLAG_NEED_LINK_UPDATE;
+	}
+
+	for(i=0;i<3;i++){
+		TCALL(hw, mac.ops.check_link, &link_speed, &link_up, false);
+		msleep(1);
+	}
+#endif
+
+	adapter->link_up = link_up;
+	adapter->link_speed = link_speed;
+
+#ifdef HAVE_DCBNL_IEEE
+	if (adapter->txgbe_ieee_pfc)
+		pfc_en |= !!(adapter->txgbe_ieee_pfc->pfc_en);
+
+#endif
+	if (link_up && !((adapter->flags & TXGBE_FLAG_DCB_ENABLED) && pfc_en)) {
+		TCALL(hw, mac.ops.fc_enable);
+		txgbe_set_rx_drop_en(adapter);
+	}
+
+	if (link_up) {
+
+#ifdef HAVE_PTP_1588_CLOCK
+		adapter->last_rx_ptp_check = jiffies;
+
+		if (test_bit(__TXGBE_PTP_RUNNING, &adapter->state))
+			txgbe_ptp_start_cyclecounter(adapter);
+
+#endif
+		if (link_speed & TXGBE_LINK_SPEED_10GB_FULL) {
+			wr32(hw, TXGBE_MAC_TX_CFG,
+				(rd32(hw, TXGBE_MAC_TX_CFG) &
+				~TXGBE_MAC_TX_CFG_SPEED_MASK) | TXGBE_MAC_TX_CFG_TE |
+				TXGBE_MAC_TX_CFG_SPEED_10G);
+		} else if (link_speed & (TXGBE_LINK_SPEED_1GB_FULL |
+				TXGBE_LINK_SPEED_100_FULL | TXGBE_LINK_SPEED_10_FULL)) {
+			wr32(hw, TXGBE_MAC_TX_CFG,
+				(rd32(hw, TXGBE_MAC_TX_CFG) &
+				~TXGBE_MAC_TX_CFG_SPEED_MASK) | TXGBE_MAC_TX_CFG_TE |
+				TXGBE_MAC_TX_CFG_SPEED_1G);
+		}
+
+		/* Re configure MAC RX */
+		reg = rd32(hw, TXGBE_MAC_RX_CFG);
+		wr32(hw, TXGBE_MAC_RX_CFG, reg);
+		wr32(hw, TXGBE_MAC_PKT_FLT, TXGBE_MAC_PKT_FLT_PR);
+		reg = rd32(hw, TXGBE_MAC_WDG_TIMEOUT);
+		wr32(hw, TXGBE_MAC_WDG_TIMEOUT, reg);
+	}
+
+	if (hw->mac.ops.dmac_config && hw->mac.dmac_config.watchdog_timer) {
+		u8 num_tcs = netdev_get_num_tc(adapter->netdev);
+#if IS_ENABLED(CONFIG_FCOE)
+		u8 fcoe_tc = txgbe_fcoe_get_tc(adapter);
+		bool fcoe_en = !!(adapter->flags & TXGBE_FLAG_FCOE_ENABLED);
+#endif /* CONFIG_FCOE */
+
+		if (hw->mac.dmac_config.link_speed != link_speed ||
+#if IS_ENABLED(CONFIG_FCOE)
+		    hw->mac.dmac_config.fcoe_tc != fcoe_tc ||
+		    hw->mac.dmac_config.fcoe_en != fcoe_en ||
+#endif /* CONFIG_FCOE */
+		    hw->mac.dmac_config.num_tcs != num_tcs) {
+			hw->mac.dmac_config.link_speed = link_speed;
+			hw->mac.dmac_config.num_tcs = num_tcs;
+#if IS_ENABLED(CONFIG_FCOE)
+			hw->mac.dmac_config.fcoe_en = fcoe_en;
+			hw->mac.dmac_config.fcoe_tc = fcoe_tc;
+#endif /* CONFIG_FCOE */
+			TCALL(hw, mac.ops.dmac_config);
+		}
+	}
+}
+
+static void txgbe_update_default_up(struct txgbe_adapter *adapter)
+{
+	u8 up = 0;
+#ifdef HAVE_DCBNL_IEEE
+	struct net_device *netdev = adapter->netdev;
+	struct dcb_app app = {
+			      .selector = DCB_APP_IDTYPE_ETHTYPE,
+			      .protocol = 0,
+			     };
+	up = dcb_getapp(netdev, &app);
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+	adapter->default_up = (up > 1) ? (ffs(up) - 1) : 0;
+#else
+	adapter->default_up = up;
+#endif
+}
+
+/**
+ * txgbe_watchdog_link_is_up - update netif_carrier status and
+ *                             print link up message
+ * @adapter - pointer to the device adapter structure
+ **/
+static void txgbe_watchdog_link_is_up(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 link_speed = adapter->link_speed;
+	bool flow_rx, flow_tx;
+#ifdef HAVE_VIRTUAL_STATION
+	struct net_device *upper;
+	struct list_head *iter;
+#endif
+
+	/* only continue if link was previously down */
+	if (netif_carrier_ok(netdev))
+		return;
+
+	adapter->flags2 &= ~TXGBE_FLAG2_SEARCH_FOR_SFP;
+
+	/* flow_rx, flow_tx report link flow control status */
+	flow_rx = (rd32(hw, TXGBE_MAC_RX_FLOW_CTRL) & 0x101) == 0x1;
+	flow_tx = !!(TXGBE_RDB_RFCC_RFCE_802_3X &
+		     rd32(hw, TXGBE_RDB_RFCC));
+
+	e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
+	       (link_speed == TXGBE_LINK_SPEED_10GB_FULL ?
+	       "10 Gbps" :
+	       (link_speed == TXGBE_LINK_SPEED_1GB_FULL ?
+	       "1 Gbps" :
+	       (link_speed == TXGBE_LINK_SPEED_100_FULL ?
+	       "100 Mbps" :
+	       (link_speed == TXGBE_LINK_SPEED_10_FULL ?
+	       "10 Mbps" :
+	       "unknown speed")))),
+	       ((flow_rx && flow_tx) ? "RX/TX" :
+	       (flow_rx ? "RX" :
+	       (flow_tx ? "TX" : "None"))));
+
+	netif_carrier_on(netdev);
+
+
+
+	netif_tx_wake_all_queues(netdev);
+#ifdef HAVE_VIRTUAL_STATION
+	/* enable any upper devices */
+	rtnl_lock();
+	netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+		if (netif_is_macvlan(upper)) {
+			struct macvlan_dev *vlan = netdev_priv(upper);
+
+			if (vlan->fwd_priv)
+				netif_tx_wake_all_queues(upper);
+		}
+	}
+	rtnl_unlock();
+#endif
+	/* update the default user priority for VFs */
+	txgbe_update_default_up(adapter);
+
+	/* ping all the active vfs to let them know link has changed */
+	txgbe_ping_all_vfs(adapter);
+}
+
+/**
+ * txgbe_watchdog_link_is_down - update netif_carrier status and
+ *                               print link down message
+ * @adapter - pointer to the adapter structure
+ **/
+static void txgbe_watchdog_link_is_down(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct txgbe_hw *hw = &adapter->hw;
+	adapter->link_up = false;
+	adapter->link_speed = 0;
+
+	if ( hw->subsystem_device_id == TXGBE_ID_WX1820_KR_KX_KX4 ||
+		hw->subsystem_device_id == TXGBE_ID_SP1000_KR_KX_KX4 ){
+		txgbe_bp_down_event(adapter);
+	}
+
+	/* only continue if link was up previously */
+	if (!netif_carrier_ok(netdev))
+		return;
+
+#ifdef HAVE_PTP_1588_CLOCK
+	if (test_bit(__TXGBE_PTP_RUNNING, &adapter->state))
+		txgbe_ptp_start_cyclecounter(adapter);
+
+#endif
+	e_info(drv, "NIC Link is Down\n");
+	netif_carrier_off(netdev);
+	netif_tx_stop_all_queues(netdev);
+
+	/* ping all the active vfs to let them know link has changed */
+	txgbe_ping_all_vfs(adapter);
+}
+
+static bool txgbe_ring_tx_pending(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct txgbe_ring *tx_ring = adapter->tx_ring[i];
+
+		if (tx_ring->next_to_use != tx_ring->next_to_clean)
+			return true;
+	}
+
+	return false;
+}
+
+static bool txgbe_vf_tx_pending(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+
+	u32 i, j;
+
+	if (!adapter->num_vfs)
+		return false;
+
+	for (i = 0; i < adapter->num_vfs; i++) {
+		for (j = 0; j < q_per_pool; j++) {
+			u32 h, t;
+
+			h = rd32(hw,
+					   TXGBE_PX_TR_RPn(q_per_pool, i, j));
+			t = rd32(hw,
+					   TXGBE_PX_TR_WPn(q_per_pool, i, j));
+
+			if (h != t)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * txgbe_watchdog_flush_tx - flush queues on link down
+ * @adapter - pointer to the device adapter structure
+ **/
+static void txgbe_watchdog_flush_tx(struct txgbe_adapter *adapter)
+{
+	if (!netif_carrier_ok(adapter->netdev)) {
+		if (txgbe_ring_tx_pending(adapter) ||
+		    txgbe_vf_tx_pending(adapter)) {
+			/* We've lost link, so the controller stops DMA,
+			 * but we've got queued Tx work that's never going
+			 * to get done, so reset controller to flush Tx.
+			 * (Do the reset outside of interrupt context).
+			 */
+			e_warn(drv, "initiating reset due to lost link with "
+				"pending Tx work\n");
+			adapter->flags2 |= TXGBE_FLAG2_PF_RESET_REQUESTED;
+		}
+	}
+}
+
+#ifdef CONFIG_PCI_IOV
+static inline void txgbe_issue_vf_flr(struct txgbe_adapter *adapter,
+				      struct pci_dev *vfdev)
+{
+	int pos, i;
+	u16 status;
+
+	/* wait for pending transactions on the bus */
+	for (i = 0; i < 4; i++) {
+		if (i)
+			msleep((1 << (i - 1)) * 100);
+
+		pcie_capability_read_word(vfdev, PCI_EXP_DEVSTA, &status);
+		if (!(status & PCI_EXP_DEVSTA_TRPND))
+			goto clear;
+	}
+
+	e_dev_warn("Issuing VFLR with pending transactions\n");
+
+clear:
+	pos = pci_find_capability(vfdev, PCI_CAP_ID_EXP);
+	if (!pos)
+		return;
+
+	e_dev_err("Issuing VFLR for VF %s\n", pci_name(vfdev));
+	pci_write_config_word(vfdev, pos + PCI_EXP_DEVCTL,
+			      PCI_EXP_DEVCTL_BCR_FLR);
+	msleep(100);
+}
+
+
+static void txgbe_spoof_check(struct txgbe_adapter *adapter)
+{
+	u32 ssvpc;
+
+	/* Do not perform spoof check if in non-IOV mode */
+	if (adapter->num_vfs == 0)
+		return;
+	ssvpc = rd32(&adapter->hw, TXGBE_TDM_SEC_DRP);
+
+	/*
+	 * ssvpc register is cleared on read, if zero then no
+	 * spoofed packets in the last interval.
+	 */
+	if (!ssvpc)
+		return;
+
+	e_warn(drv, "%d Spoofed packets detected\n", ssvpc);
+}
+
+#endif /* CONFIG_PCI_IOV */
+
+/**
+ * txgbe_watchdog_subtask - check and bring link up
+ * @adapter - pointer to the device adapter structure
+ **/
+static void txgbe_watchdog_subtask(struct txgbe_adapter *adapter)
+{
+	u32 __maybe_unused value = 0;
+	struct txgbe_hw *hw = &adapter->hw;
+
+	/* if interface is down do nothing */
+	if (test_bit(__TXGBE_DOWN, &adapter->state) ||
+	    test_bit(__TXGBE_REMOVING, &adapter->state) ||
+	    test_bit(__TXGBE_RESETTING, &adapter->state))
+		return;
+
+	if ( hw->subsystem_device_id == TXGBE_ID_WX1820_KR_KX_KX4 ||
+		 hw->subsystem_device_id == TXGBE_ID_SP1000_KR_KX_KX4 ){
+		txgbe_bp_watchdog_event(adapter);
+	}
+#ifndef POLL_LINK_STATUS
+	if(BOND_CHECK_LINK_MODE == 1){
+		value = rd32(hw, 0x14404);
+		value = value & 0x1;
+		if(value == 1)
+			adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+	}
+	if (!(adapter->flags2 & TXGBE_FLAG2_LINK_DOWN))
+		txgbe_watchdog_update_link(adapter);
+	
+	if (adapter->link_up)
+		txgbe_watchdog_link_is_up(adapter);
+	else
+		txgbe_watchdog_link_is_down(adapter);
+#endif
+
+#ifdef CONFIG_PCI_IOV
+	txgbe_spoof_check(adapter);
+#endif /* CONFIG_PCI_IOV */
+
+	txgbe_update_stats(adapter);
+
+	txgbe_watchdog_flush_tx(adapter);
+}
+
+/**
+ * txgbe_sfp_detection_subtask - poll for SFP+ cable
+ * @adapter - the txgbe adapter structure
+ **/
+static void txgbe_sfp_detection_subtask(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_mac_info *mac = &hw->mac;
+	s32 err;
+
+	/* not searching for SFP so there is nothing to do here */
+	if (!(adapter->flags2 & TXGBE_FLAG2_SEARCH_FOR_SFP) &&
+	    !(adapter->flags2 & TXGBE_FLAG2_SFP_NEEDS_RESET))
+		return;
+
+	if (adapter->sfp_poll_time &&
+	    time_after(adapter->sfp_poll_time, jiffies))
+		return; /* If not yet time to poll for SFP */
+
+	/* someone else is in init, wait until next service event */
+	if (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+		return;
+
+	adapter->sfp_poll_time = jiffies + TXGBE_SFP_POLL_JIFFIES - 1;
+
+	err = TCALL(hw, phy.ops.identify_sfp);
+	if (err == TXGBE_ERR_SFP_NOT_SUPPORTED)
+		goto sfp_out;
+
+	if (err == TXGBE_ERR_SFP_NOT_PRESENT) {
+		/* If no cable is present, then we need to reset
+		 * the next time we find a good cable. */
+		adapter->flags2 |= TXGBE_FLAG2_SFP_NEEDS_RESET;
+	}
+
+	/* exit on error */
+	if (err)
+		goto sfp_out;
+
+	/* exit if reset not needed */
+	if (!(adapter->flags2 & TXGBE_FLAG2_SFP_NEEDS_RESET))
+		goto sfp_out;
+
+	adapter->flags2 &= ~TXGBE_FLAG2_SFP_NEEDS_RESET;
+
+	if (hw->phy.multispeed_fiber) {
+		/* Set up dual speed SFP+ support */
+		mac->ops.setup_link = txgbe_setup_mac_link_multispeed_fiber;
+		mac->ops.setup_mac_link = txgbe_setup_mac_link;
+		mac->ops.set_rate_select_speed =
+					       txgbe_set_hard_rate_select_speed;
+	} else {
+		mac->ops.setup_link = txgbe_setup_mac_link;
+		mac->ops.set_rate_select_speed =
+					       txgbe_set_hard_rate_select_speed;
+		hw->phy.autoneg_advertised = 0;
+	}
+
+	adapter->flags |= TXGBE_FLAG_NEED_LINK_CONFIG;
+	e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
+
+sfp_out:
+	clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+
+	if ((err == TXGBE_ERR_SFP_NOT_SUPPORTED) &&
+	    adapter->netdev_registered) {
+		e_dev_err("failed to initialize because an unsupported "
+			  "SFP+ module type was detected.\n");
+	}
+}
+
+/**
+ * txgbe_sfp_link_config_subtask - set up link SFP after module install
+ * @adapter - the txgbe adapter structure
+ **/
+static void txgbe_sfp_link_config_subtask(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 speed;
+	bool autoneg = false;
+	u16 value;
+	u8 device_type = hw->subsystem_device_id & 0xF0;
+
+	if (!(adapter->flags & TXGBE_FLAG_NEED_LINK_CONFIG))
+		return;
+
+	/* someone else is in init, wait until next service event */
+	if (test_and_set_bit(__TXGBE_IN_SFP_INIT, &adapter->state))
+		return;
+
+	adapter->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG;
+
+	if (device_type == TXGBE_ID_XAUI) {
+		/* clear ext phy int status */
+		txgbe_read_mdio(&hw->phy_dev, hw->phy.addr, 0x03, 0x8011, &value);
+		if (value & 0x400)
+			adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+		if (!(value & 0x800)) {
+			clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+			return;
+		}
+	}
+
+    if(device_type == TXGBE_ID_MAC_XAUI ||
+		(txgbe_get_media_type(hw) == txgbe_media_type_copper &&
+		device_type == TXGBE_ID_SFI_XAUI)) {
+        speed = TXGBE_LINK_SPEED_10GB_FULL;
+    } else if (device_type == TXGBE_ID_MAC_SGMII) {
+    	speed = TXGBE_LINK_SPEED_1GB_FULL;
+    }else {
+        speed = hw->phy.autoneg_advertised;
+        if ((!speed) && (hw->mac.ops.get_link_capabilities)) {
+                TCALL(hw, mac.ops.get_link_capabilities, &speed, &autoneg);
+                /* setup the highest link when no autoneg */
+                if (!autoneg) {
+                        if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+                                speed = TXGBE_LINK_SPEED_10GB_FULL;
+                }
+        }
+    }
+
+	TCALL(hw, mac.ops.setup_link, speed, false);
+
+	adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+	adapter->link_check_timeout = jiffies;
+	clear_bit(__TXGBE_IN_SFP_INIT, &adapter->state);
+}
+
+static void txgbe_sfp_reset_eth_phy_subtask(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 speed;
+	bool linkup = true;
+	u32 i = 0;
+
+	if (!(adapter->flags2 & TXGBE_FLAG_NEED_ETH_PHY_RESET))
+		return;
+
+	adapter->flags2 &= ~TXGBE_FLAG_NEED_ETH_PHY_RESET;
+
+	TCALL(hw, mac.ops.check_link, &speed, &linkup, false);
+	if (!linkup) {
+		txgbe_wr32_epcs(hw, TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1,
+					0xA000);
+		/* wait phy initialization done */
+		for (i = 0; i < TXGBE_PHY_INIT_DONE_POLLING_TIME; i++) {
+			if ((txgbe_rd32_epcs(hw,
+				TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1) &
+				TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST) == 0)
+				break;
+			msleep(100);
+		}
+	}
+}
+
+/**
+ * txgbe_service_timer - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void txgbe_service_timer(struct timer_list *t)
+{
+	struct txgbe_adapter *adapter = from_timer(adapter, t, service_timer);
+	unsigned long next_event_offset;
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 val = 0;
+
+	/* poll faster when waiting for link */
+	if (adapter->flags & TXGBE_FLAG_NEED_LINK_UPDATE) {
+		if ((hw->subsystem_device_id & 0xF0) == TXGBE_ID_KR_KX_KX4)
+			next_event_offset = HZ ;
+		else if (BOND_CHECK_LINK_MODE == 1)
+			next_event_offset = HZ / 100;
+		else
+			next_event_offset = HZ / 10;
+	} else
+		next_event_offset = HZ * 2;
+
+	/* record which func to provoke PCIE recovery */
+	if (rd32(&adapter->hw, TXGBE_MIS_PF_SM) == 1) {
+		val = rd32m(&adapter->hw, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN0_UP |
+												   TXGBE_MIS_PRB_CTL_LAN1_UP);
+		if (val & TXGBE_MIS_PRB_CTL_LAN0_UP) {
+			if (hw->bus.lan_id == 0) {
+				adapter->flags2 |= TXGBE_FLAG2_PCIE_NEED_RECOVER;
+				e_info(probe, "txgbe_service_timer: set recover on Lan0\n");
+				}
+		} else if (val & TXGBE_MIS_PRB_CTL_LAN1_UP) {
+			if (hw->bus.lan_id == 1) {
+				adapter->flags2 |= TXGBE_FLAG2_PCIE_NEED_RECOVER;
+				e_info(probe, "txgbe_service_timer: set recover on Lan1\n");
+			}
+		}
+	}
+
+	/* Reset the timer */
+	mod_timer(&adapter->service_timer, next_event_offset + jiffies);
+
+	txgbe_service_event_schedule(adapter);
+	if ((hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0) ||
+		(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1)) {
+		next_event_offset = HZ/10;
+		queue_work(txgbe_wq, &adapter->sfp_sta_task);
+	}
+}
+
+static void txgbe_sfp_phy_status_work(struct work_struct *work)
+{
+	struct txgbe_adapter *adapter = container_of(work,
+						     struct txgbe_adapter,
+						     sfp_sta_task);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 data = 0;
+	bool status;
+	s32 i2c_status;
+	
+	if ((hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0) ||
+		(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1)){
+		i2c_status = TCALL(hw, phy.ops.read_i2c_sfp_phy,
+					 0x0a,
+					 &data);
+		if (i2c_status != 0)
+			return;
+
+		/* Avoid read module info and read f2c module internal phy
+		 * may cause i2c controller read reg data err
+		 */
+		if ((data & 0x83ff) != 0 || data == 0)
+			return;
+		
+		if ((data & TXGBE_I2C_PHY_LOCAL_RX_STATUS) && 
+			(data & TXGBE_I2C_PHY_REMOTE_RX_STATUS))
+			status = true;
+		else
+			status = false;
+
+		if (hw->f2c_mod_status != status) {
+			hw->f2c_mod_status = status;
+			adapter->flags |= TXGBE_FLAG_NEED_LINK_UPDATE;
+		}	
+	}
+}
+
+#ifdef POLL_LINK_STATUS
+/**
+ * txgbe_service_timer - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void txgbe_link_check_timer(struct timer_list *t)
+{
+	struct txgbe_adapter *adapter = from_timer(adapter, t, link_check_timer);
+	unsigned long next_event_offset = HZ/100;
+	struct txgbe_hw __maybe_unused *hw = &adapter->hw;
+
+	mod_timer(&adapter->link_check_timer, next_event_offset + jiffies);
+	if(test_bit(__TXGBE_DOWN, &adapter->state) ||
+		test_bit(__TXGBE_REMOVING, &adapter->state) ||
+		test_bit(__TXGBE_RESETTING, &adapter->state))
+		return;
+
+	txgbe_watchdog_update_link(adapter);
+
+	if (adapter->link_up)
+		txgbe_watchdog_link_is_up(adapter);
+	else
+		txgbe_watchdog_link_is_down(adapter);
+
+}
+#endif
+
+static void txgbe_reset_subtask(struct txgbe_adapter *adapter)
+{
+	u32 reset_flag = 0;
+	u32 value = 0;
+
+	if (!(adapter->flags2 & (TXGBE_FLAG2_PF_RESET_REQUESTED |
+		TXGBE_FLAG2_DEV_RESET_REQUESTED |
+		TXGBE_FLAG2_GLOBAL_RESET_REQUESTED |
+		TXGBE_FLAG2_RESET_INTR_RECEIVED)))
+		return;
+
+	/* If we're already down, just bail */
+	if (test_bit(__TXGBE_DOWN, &adapter->state) ||
+	    test_bit(__TXGBE_REMOVING, &adapter->state))
+		return;
+
+	netdev_err(adapter->netdev, "Reset adapter\n");
+	adapter->tx_timeout_count++;
+
+	rtnl_lock();
+	if (adapter->flags2 & TXGBE_FLAG2_GLOBAL_RESET_REQUESTED) {
+		reset_flag |= TXGBE_FLAG2_GLOBAL_RESET_REQUESTED;
+		adapter->flags2 &= ~TXGBE_FLAG2_GLOBAL_RESET_REQUESTED;
+	}
+	if (adapter->flags2 & TXGBE_FLAG2_DEV_RESET_REQUESTED) {
+		reset_flag |= TXGBE_FLAG2_DEV_RESET_REQUESTED;
+		adapter->flags2 &= ~TXGBE_FLAG2_DEV_RESET_REQUESTED;
+	}
+	if (adapter->flags2 & TXGBE_FLAG2_PF_RESET_REQUESTED) {
+		reset_flag |= TXGBE_FLAG2_PF_RESET_REQUESTED;
+		adapter->flags2 &= ~TXGBE_FLAG2_PF_RESET_REQUESTED;
+	}
+
+	if (adapter->flags2 & TXGBE_FLAG2_RESET_INTR_RECEIVED) {
+		/* If there's a recovery already waiting, it takes
+		* precedence before starting a new reset sequence.
+		*/
+		adapter->flags2 &= ~TXGBE_FLAG2_RESET_INTR_RECEIVED;
+		value = rd32m(&adapter->hw, TXGBE_MIS_RST_ST,
+				TXGBE_MIS_RST_ST_DEV_RST_TYPE_MASK) >>
+				TXGBE_MIS_RST_ST_DEV_RST_TYPE_SHIFT;
+		if (value == TXGBE_MIS_RST_ST_DEV_RST_TYPE_SW_RST) {
+			adapter->hw.reset_type = TXGBE_SW_RESET;
+			/* errata 7 */
+			if (txgbe_mng_present(&adapter->hw) &&
+				adapter->hw.revision_id == TXGBE_SP_MPW)
+				adapter->flags2 |=
+					TXGBE_FLAG2_MNG_REG_ACCESS_DISABLED;
+		} else if (value == TXGBE_MIS_RST_ST_DEV_RST_TYPE_GLOBAL_RST)
+			adapter->hw.reset_type = TXGBE_GLOBAL_RESET;
+		adapter->hw.force_full_reset = TRUE;
+		txgbe_reinit_locked(adapter);
+		adapter->hw.force_full_reset = FALSE;
+		goto unlock;
+	}
+
+	if (reset_flag & TXGBE_FLAG2_DEV_RESET_REQUESTED) {
+		/* Request a Device Reset
+		 *
+		 * This will start the chip's countdown to the actual full
+		 * chip reset event, and a warning interrupt to be sent
+		 * to all PFs, including the requestor.  Our handler
+		 * for the warning interrupt will deal with the shutdown
+		 * and recovery of the switch setup.
+		 */
+		/*debug to up*/
+		/*txgbe_dump(adapter);*/
+		if (txgbe_mng_present(&adapter->hw)) {
+			txgbe_reset_hostif(&adapter->hw);
+		} else
+			wr32m(&adapter->hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_SW_RST, TXGBE_MIS_RST_SW_RST);
+
+	} else if (reset_flag & TXGBE_FLAG2_PF_RESET_REQUESTED) {
+		/*debug to up*/
+		/*txgbe_dump(adapter);*/
+		txgbe_reinit_locked(adapter);
+	} else if (reset_flag & TXGBE_FLAG2_GLOBAL_RESET_REQUESTED) {
+		/* Request a Global Reset
+		 *
+		 * This will start the chip's countdown to the actual full
+		 * chip reset event, and a warning interrupt to be sent
+		 * to all PFs, including the requestor.  Our handler
+		 * for the warning interrupt will deal with the shutdown
+		 * and recovery of the switch setup.
+		 */
+		/*debug to up*/
+		/*txgbe_dump(adapter);*/
+		pci_save_state(adapter->pdev);
+		if (txgbe_mng_present(&adapter->hw)) {
+			txgbe_reset_hostif(&adapter->hw);
+		} else
+			wr32m(&adapter->hw, TXGBE_MIS_RST,
+				TXGBE_MIS_RST_GLOBAL_RST,
+				TXGBE_MIS_RST_GLOBAL_RST);
+	}
+
+unlock:
+	rtnl_unlock();
+}
+
+static void txgbe_check_pcie_subtask(struct txgbe_adapter *adapter)
+{
+	if (!(adapter->flags2 & TXGBE_FLAG2_PCIE_NEED_RECOVER))
+		return;
+
+	txgbe_print_tx_hang_status(adapter);
+
+	wr32m(&adapter->hw, TXGBE_MIS_PF_SM, TXGBE_MIS_PF_SM_SM, 0);
+#ifdef TXGBE_PCIE_RECOVER
+	e_info(probe, "do recovery\n");
+	txgbe_pcie_do_recovery(adapter->pdev);
+#endif
+	adapter->flags2 &= ~TXGBE_FLAG2_PCIE_NEED_RECOVER;
+}
+
+/**
+ * txgbe_service_task - manages and runs subtasks
+ * @work: pointer to work_struct containing our data
+ **/
+static void txgbe_service_task(struct work_struct *work)
+{
+	struct txgbe_adapter *adapter = container_of(work,
+						     struct txgbe_adapter,
+						     service_task);
+	if (TXGBE_REMOVED(adapter->hw.hw_addr)) {
+		if (!test_bit(__TXGBE_DOWN, &adapter->state)) {
+			rtnl_lock();
+			txgbe_down(adapter);
+			rtnl_unlock();
+		}
+		txgbe_service_event_complete(adapter);
+		return;
+	}
+#if defined(HAVE_UDP_ENC_RX_OFFLOAD) || defined(HAVE_VXLAN_RX_OFFLOAD)
+#ifndef HAVE_UDP_TUNNEL_NIC_INFO
+	if (adapter->flags2 & TXGBE_FLAG2_VXLAN_REREG_NEEDED) {
+		rtnl_lock();
+		adapter->flags2 &= ~TXGBE_FLAG2_VXLAN_REREG_NEEDED;
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+		udp_tunnel_get_rx_info(adapter->netdev);
+#else
+		vxlan_get_rx_port(adapter->netdev);
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD */
+		rtnl_unlock();
+	}
+#endif /* HAVE_UDP_TUNNEL_NIC_INFO */
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD || HAVE_VXLAN_RX_OFFLOAD */
+
+	txgbe_check_pcie_subtask(adapter);
+	txgbe_reset_subtask(adapter);
+	txgbe_sfp_detection_subtask(adapter);
+	txgbe_sfp_link_config_subtask(adapter);
+	txgbe_sfp_reset_eth_phy_subtask(adapter);
+	txgbe_check_overtemp_subtask(adapter);
+	txgbe_watchdog_subtask(adapter);
+#ifdef HAVE_TX_MQ
+	txgbe_fdir_reinit_subtask(adapter);
+#endif
+	txgbe_check_hang_subtask(adapter);
+#ifdef HAVE_PTP_1588_CLOCK
+	if (test_bit(__TXGBE_PTP_RUNNING, &adapter->state)) {
+		txgbe_ptp_overflow_check(adapter);
+		if (unlikely(adapter->flags &
+		    TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER))
+			txgbe_ptp_rx_hang(adapter);
+	}
+#endif /* HAVE_PTP_1588_CLOCK */
+
+	txgbe_service_event_complete(adapter);
+}
+
+static u8 get_ipv6_proto(struct sk_buff *skb, int offset)
+{
+	struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data + offset);
+	u8 nexthdr = hdr->nexthdr;
+
+	offset += sizeof(struct ipv6hdr);
+
+	while (ipv6_ext_hdr(nexthdr)) {
+		struct ipv6_opt_hdr _hdr, *hp;
+
+		if (nexthdr == NEXTHDR_NONE)
+			break;
+
+		hp = skb_header_pointer(skb, offset, sizeof(_hdr), &_hdr);
+		if (!hp)
+			break;
+
+		if (nexthdr == NEXTHDR_FRAGMENT) {
+			break;
+		} else if (nexthdr == NEXTHDR_AUTH) {
+			offset +=  ipv6_authlen(hp);
+		} else {
+			offset +=  ipv6_optlen(hp);
+		}
+
+		nexthdr = hp->nexthdr;
+	}
+
+	return nexthdr;
+}
+
+union network_header {
+	struct iphdr *ipv4;
+	struct ipv6hdr *ipv6;
+	void *raw;
+};
+
+#ifndef ETH_P_TEB
+#define ETH_P_TEB       0x6558
+#endif
+static txgbe_dptype encode_tx_desc_ptype(const struct txgbe_tx_buffer *first)
+{
+	struct sk_buff *skb = first->skb;
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	u8 tun_prot = 0;
+#endif
+	u8 l4_prot = 0;
+	u8 ptype = 0;
+
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	if (skb->encapsulation) {
+		union network_header hdr;
+
+		switch (first->protocol) {
+		case __constant_htons(ETH_P_IP):
+			tun_prot = ip_hdr(skb)->protocol;
+			if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))
+				goto encap_frag;
+			ptype = TXGBE_PTYPE_TUN_IPV4;
+			break;
+		case __constant_htons(ETH_P_IPV6):
+			tun_prot = get_ipv6_proto(skb, skb_network_offset(skb));
+			if (tun_prot == NEXTHDR_FRAGMENT)
+				goto encap_frag;
+			ptype = TXGBE_PTYPE_TUN_IPV6;
+			break;
+		default:
+			goto exit;
+		}
+
+		if (tun_prot == IPPROTO_IPIP) {
+			hdr.raw = (void *)inner_ip_hdr(skb);
+			ptype |= TXGBE_PTYPE_PKT_IPIP;
+		} else if (tun_prot == IPPROTO_UDP) {
+			hdr.raw = (void *)inner_ip_hdr(skb);
+			/* fixme: VXLAN-GPE neither ETHER nor IP */
+#ifdef ENCAP_TYPE_ETHER
+			if (skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
+				skb->inner_protocol != htons(ETH_P_TEB)) {
+				ptype |= TXGBE_PTYPE_PKT_IG;
+			} else {
+				if (((struct ethhdr *)
+					skb_inner_mac_header(skb))->h_proto
+					== htons(ETH_P_8021Q)) {
+					ptype |= TXGBE_PTYPE_PKT_IGMV;
+				} else {
+					ptype |= TXGBE_PTYPE_PKT_IGM;
+				}
+			}
+#endif
+		} else if (tun_prot == IPPROTO_GRE) {
+			hdr.raw = (void *)inner_ip_hdr(skb);
+#ifdef ENCAP_TYPE_ETHER
+			if (skb->inner_protocol ==  htons(ETH_P_IP) ||
+				skb->inner_protocol ==  htons(ETH_P_IPV6)) {
+				ptype |= TXGBE_PTYPE_PKT_IG;
+			} else {
+				if (((struct ethhdr *)
+					skb_inner_mac_header(skb))->h_proto
+					== htons(ETH_P_8021Q)) {
+					ptype |= TXGBE_PTYPE_PKT_IGMV;
+				} else {
+					ptype |= TXGBE_PTYPE_PKT_IGM;
+				}
+			}
+#endif
+		} else {
+			goto exit;
+		}
+
+		switch (hdr.ipv4->version) {
+		case IPVERSION:
+			l4_prot = hdr.ipv4->protocol;
+			if (hdr.ipv4->frag_off & htons(IP_MF | IP_OFFSET)) {
+				ptype |= TXGBE_PTYPE_TYP_IPFRAG;
+				goto exit;
+			}
+			break;
+		case 6:
+			l4_prot = get_ipv6_proto(skb,
+						 skb_inner_network_offset(skb));
+			ptype |= TXGBE_PTYPE_PKT_IPV6;
+			if (l4_prot == NEXTHDR_FRAGMENT) {
+				ptype |= TXGBE_PTYPE_TYP_IPFRAG;
+				goto exit;
+			}
+			break;
+		default:
+			goto exit;
+		}
+	} else {
+encap_frag:
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+		switch (first->protocol) {
+		case __constant_htons(ETH_P_IP):
+			l4_prot = ip_hdr(skb)->protocol;
+			ptype = TXGBE_PTYPE_PKT_IP;
+			if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
+				ptype |= TXGBE_PTYPE_TYP_IPFRAG;
+				goto exit;
+			}
+			break;
+#ifdef NETIF_F_IPV6_CSUM
+		case __constant_htons(ETH_P_IPV6):
+			l4_prot = get_ipv6_proto(skb, skb_network_offset(skb));
+			ptype = TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6;
+			if (l4_prot == NEXTHDR_FRAGMENT) {
+				ptype |= TXGBE_PTYPE_TYP_IPFRAG;
+				goto exit;
+			}
+			break;
+#endif /* NETIF_F_IPV6_CSUM */
+		case __constant_htons(ETH_P_1588):
+			ptype = TXGBE_PTYPE_L2_TS;
+			goto exit;
+		case __constant_htons(ETH_P_FIP):
+			ptype = TXGBE_PTYPE_L2_FIP;
+			goto exit;
+		case __constant_htons(TXGBE_ETH_P_LLDP):
+			ptype = TXGBE_PTYPE_L2_LLDP;
+			goto exit;
+		case __constant_htons(TXGBE_ETH_P_CNM):
+			ptype = TXGBE_PTYPE_L2_CNM;
+			goto exit;
+		case __constant_htons(ETH_P_PAE):
+			ptype = TXGBE_PTYPE_L2_EAPOL;
+			goto exit;
+		case __constant_htons(ETH_P_ARP):
+			ptype = TXGBE_PTYPE_L2_ARP;
+			goto exit;
+		default:
+			ptype = TXGBE_PTYPE_L2_MAC;
+			goto exit;
+		}
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	}
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+
+	switch (l4_prot) {
+	case IPPROTO_TCP:
+		ptype |= TXGBE_PTYPE_TYP_TCP;
+		break;
+	case IPPROTO_UDP:
+		ptype |= TXGBE_PTYPE_TYP_UDP;
+		break;
+#ifdef HAVE_SCTP
+	case IPPROTO_SCTP:
+		ptype |= TXGBE_PTYPE_TYP_SCTP;
+		break;
+#endif /* HAVE_SCTP */
+	default:
+		ptype |= TXGBE_PTYPE_TYP_IP;
+		break;
+	}
+
+exit:
+	return txgbe_decode_ptype(ptype);
+}
+
+static int txgbe_tso(struct txgbe_ring *tx_ring,
+		     struct txgbe_tx_buffer *first,
+		     u8 *hdr_len,  txgbe_dptype dptype)
+{
+#ifndef NETIF_F_TSO
+	return 0;
+#else
+	struct sk_buff *skb = first->skb;
+	u32 vlan_macip_lens, type_tucmd;
+	u32 mss_l4len_idx, l4len;
+	struct tcphdr *tcph;
+	struct iphdr *iph;
+	u32 tunhdr_eiplen_tunlen = 0;
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	u8 tun_prot = 0;
+	bool enc = skb->encapsulation;
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+#ifdef NETIF_F_TSO6
+		struct ipv6hdr *ipv6h;
+#endif
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
+	if (!skb_is_gso(skb))
+		return 0;
+
+	if (skb_header_cloned(skb)) {
+		int err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+		if (err)
+			return err;
+	}
+
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	iph = enc ? inner_ip_hdr(skb) : ip_hdr(skb);
+#else
+	iph = ip_hdr(skb);
+#endif
+	if (iph->version == 4) {
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+		tcph = enc ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+#else
+		tcph = tcp_hdr(skb);
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+		iph->tot_len = 0;
+		iph->check = 0;
+		tcph->check = ~csum_tcpudp_magic(iph->saddr,
+						iph->daddr, 0,
+						IPPROTO_TCP,
+						0);
+		first->tx_flags |= TXGBE_TX_FLAGS_TSO |
+		   TXGBE_TX_FLAGS_CSUM |
+		   TXGBE_TX_FLAGS_IPV4 |
+		   TXGBE_TX_FLAGS_CC;
+
+#ifdef NETIF_F_TSO6
+	} else if (iph->version == 6 && skb_is_gso_v6(skb)) {
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+		ipv6h = enc ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+		tcph = enc ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+#else
+		ipv6h = ipv6_hdr(skb);
+		tcph = tcp_hdr(skb);
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+		ipv6h->payload_len = 0;
+		tcph->check =
+		    ~csum_ipv6_magic(&ipv6h->saddr,
+				     &ipv6h->daddr,
+				     0, IPPROTO_TCP, 0);
+		first->tx_flags |= TXGBE_TX_FLAGS_TSO |
+				   TXGBE_TX_FLAGS_CSUM |
+				   TXGBE_TX_FLAGS_CC;
+#endif /* NETIF_F_TSO6 */
+	}
+
+	/* compute header lengths */
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	l4len = enc ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
+	*hdr_len = enc ? (skb_inner_transport_header(skb) - skb->data)
+		       : skb_transport_offset(skb);
+	*hdr_len += l4len;
+#else
+	l4len = tcp_hdrlen(skb);
+	*hdr_len = skb_transport_offset(skb) + l4len;
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+
+	/* update gso size and bytecount with header size */
+	first->gso_segs = skb_shinfo(skb)->gso_segs;
+	first->bytecount += (first->gso_segs - 1) * *hdr_len;
+
+	/* mss_l4len_id: use 0 as index for TSO */
+	mss_l4len_idx = l4len << TXGBE_TXD_L4LEN_SHIFT;
+	mss_l4len_idx |= skb_shinfo(skb)->gso_size << TXGBE_TXD_MSS_SHIFT;
+#ifdef MAX_9732_SIZE
+	if (skb_shinfo(skb)->gso_size > (9428 - *hdr_len))
+		mss_l4len_idx |= (9428 - *hdr_len) << TXGBE_TXD_MSS_SHIFT;
+	else
+	{
+		mss_l4len_idx |= skb_shinfo(skb)->gso_size << TXGBE_TXD_MSS_SHIFT;
+	}
+#endif
+	/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	if (enc) {
+		switch (first->protocol) {
+		case __constant_htons(ETH_P_IP):
+			tun_prot = ip_hdr(skb)->protocol;
+			first->tx_flags |= TXGBE_TX_FLAGS_OUTER_IPV4;
+			break;
+		case __constant_htons(ETH_P_IPV6):
+			tun_prot = ipv6_hdr(skb)->nexthdr;
+			break;
+		default:
+			break;
+		}
+		switch (tun_prot) {
+		case IPPROTO_UDP:
+			tunhdr_eiplen_tunlen = TXGBE_TXD_TUNNEL_UDP;
+			tunhdr_eiplen_tunlen |=
+					((skb_network_header_len(skb) >> 2) <<
+					TXGBE_TXD_OUTER_IPLEN_SHIFT) |
+					(((skb_inner_mac_header(skb) -
+					skb_transport_header(skb)) >> 1) <<
+					TXGBE_TXD_TUNNEL_LEN_SHIFT);
+			break;
+		case IPPROTO_GRE:
+			tunhdr_eiplen_tunlen = TXGBE_TXD_TUNNEL_GRE;
+			tunhdr_eiplen_tunlen |=
+					((skb_network_header_len(skb) >> 2) <<
+					TXGBE_TXD_OUTER_IPLEN_SHIFT) |
+					(((skb_inner_mac_header(skb) -
+					skb_transport_header(skb)) >> 1) <<
+					TXGBE_TXD_TUNNEL_LEN_SHIFT);
+			break;
+		case IPPROTO_IPIP:
+			tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb)-
+						(char *)ip_hdr(skb)) >> 2) <<
+						TXGBE_TXD_OUTER_IPLEN_SHIFT;
+			break;
+		default:
+			break;
+		}
+
+		vlan_macip_lens = skb_inner_network_header_len(skb) >> 1;
+	} else
+		vlan_macip_lens = skb_network_header_len(skb) >> 1;
+#else
+		vlan_macip_lens = skb_network_header_len(skb) >> 1;
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+	vlan_macip_lens |= skb_network_offset(skb) << TXGBE_TXD_MACLEN_SHIFT;
+	vlan_macip_lens |= first->tx_flags & TXGBE_TX_FLAGS_VLAN_MASK;
+
+	type_tucmd = dptype.ptype << 24;
+#ifdef NETIF_F_HW_VLAN_STAG_TX
+	if (skb->vlan_proto == htons(ETH_P_8021AD))
+		type_tucmd |= TXGBE_SET_FLAG(first->tx_flags,
+					TXGBE_TX_FLAGS_HW_VLAN,
+					0x1 << TXGBE_TXD_TAG_TPID_SEL_SHIFT);
+#endif
+	txgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, tunhdr_eiplen_tunlen,
+		type_tucmd, mss_l4len_idx);
+
+	return 1;
+#endif /* !NETIF_F_TSO */
+}
+
+static void txgbe_tx_csum(struct txgbe_ring *tx_ring,
+			  struct txgbe_tx_buffer *first, txgbe_dptype dptype)
+{
+	struct sk_buff *skb = first->skb;
+	u32 vlan_macip_lens = 0;
+	u32 mss_l4len_idx = 0;
+	u32 tunhdr_eiplen_tunlen = 0;
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	u8 tun_prot = 0;
+#endif
+	u32 type_tucmd;
+
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		if (!(first->tx_flags & TXGBE_TX_FLAGS_HW_VLAN) &&
+		    !(first->tx_flags & TXGBE_TX_FLAGS_CC))
+			return;
+		vlan_macip_lens = skb_network_offset(skb) <<
+				  TXGBE_TXD_MACLEN_SHIFT;
+	} else {
+		u8 l4_prot = 0;
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+		union {
+			struct iphdr *ipv4;
+			struct ipv6hdr *ipv6;
+			u8 *raw;
+		} network_hdr;
+		union {
+			struct tcphdr *tcphdr;
+			u8 *raw;
+		} transport_hdr;
+
+		if (skb->encapsulation) {
+			network_hdr.raw = skb_inner_network_header(skb);
+			transport_hdr.raw = skb_inner_transport_header(skb);
+			vlan_macip_lens = skb_network_offset(skb) <<
+					  TXGBE_TXD_MACLEN_SHIFT;
+			switch (first->protocol) {
+			case __constant_htons(ETH_P_IP):
+				tun_prot = ip_hdr(skb)->protocol;
+				break;
+			case __constant_htons(ETH_P_IPV6):
+				tun_prot = ipv6_hdr(skb)->nexthdr;
+				break;
+			default:
+				if (unlikely(net_ratelimit())) {
+					dev_warn(tx_ring->dev,
+					 "partial checksum but version=%d\n",
+					 network_hdr.ipv4->version);
+				}
+				return;
+			}
+			switch (tun_prot) {
+			case IPPROTO_UDP:
+				tunhdr_eiplen_tunlen = TXGBE_TXD_TUNNEL_UDP;
+				tunhdr_eiplen_tunlen |=
+					((skb_network_header_len(skb) >> 2) <<
+					TXGBE_TXD_OUTER_IPLEN_SHIFT) |
+					(((skb_inner_mac_header(skb) -
+					skb_transport_header(skb)) >> 1) <<
+					TXGBE_TXD_TUNNEL_LEN_SHIFT);
+				break;
+			case IPPROTO_GRE:
+				tunhdr_eiplen_tunlen = TXGBE_TXD_TUNNEL_GRE;
+				tunhdr_eiplen_tunlen |=
+					((skb_network_header_len(skb) >> 2) <<
+					TXGBE_TXD_OUTER_IPLEN_SHIFT) |
+					(((skb_inner_mac_header(skb) -
+					skb_transport_header(skb)) >> 1) <<
+					TXGBE_TXD_TUNNEL_LEN_SHIFT);
+				break;
+			case IPPROTO_IPIP:
+				tunhdr_eiplen_tunlen =
+					(((char *)inner_ip_hdr(skb)-
+					(char *)ip_hdr(skb)) >> 2) <<
+					TXGBE_TXD_OUTER_IPLEN_SHIFT;
+				break;
+			default:
+				break;
+			}
+
+		} else {
+			network_hdr.raw = skb_network_header(skb);
+			transport_hdr.raw = skb_transport_header(skb);
+			vlan_macip_lens = skb_network_offset(skb) <<
+					  TXGBE_TXD_MACLEN_SHIFT;
+		}
+
+		switch (network_hdr.ipv4->version) {
+		case IPVERSION:
+			vlan_macip_lens |=
+				(transport_hdr.raw - network_hdr.raw) >> 1;
+			l4_prot = network_hdr.ipv4->protocol;
+			break;
+		case 6:
+			vlan_macip_lens |=
+				(transport_hdr.raw - network_hdr.raw) >> 1;
+			l4_prot = network_hdr.ipv6->nexthdr;
+			break;
+		default:
+			break;
+		}
+
+#else /* HAVE_ENCAP_TSO_OFFLOAD */
+		switch (first->protocol) {
+		case __constant_htons(ETH_P_IP):
+			vlan_macip_lens |= skb_network_header_len(skb) >> 1;
+			l4_prot = ip_hdr(skb)->protocol;
+			break;
+#ifdef NETIF_F_IPV6_CSUM
+		case __constant_htons(ETH_P_IPV6):
+			vlan_macip_lens |= skb_network_header_len(skb) >> 1;
+			l4_prot = ipv6_hdr(skb)->nexthdr;
+			break;
+#endif /* NETIF_F_IPV6_CSUM */
+		default:
+			break;
+		}
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+
+		switch (l4_prot) {
+		case IPPROTO_TCP:
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+		mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) <<
+				TXGBE_TXD_L4LEN_SHIFT;
+#else
+		mss_l4len_idx = tcp_hdrlen(skb) <<
+				TXGBE_TXD_L4LEN_SHIFT;
+#endif /* HAVE_ENCAP_TSO_OFFLOAD */
+			break;
+#ifdef HAVE_SCTP
+		case IPPROTO_SCTP:
+			mss_l4len_idx = sizeof(struct sctphdr) <<
+					TXGBE_TXD_L4LEN_SHIFT;
+			break;
+#endif /* HAVE_SCTP */
+		case IPPROTO_UDP:
+			mss_l4len_idx = sizeof(struct udphdr) <<
+					TXGBE_TXD_L4LEN_SHIFT;
+			break;
+		default:
+			break;
+		}
+
+		/* update TX checksum flag */
+		first->tx_flags |= TXGBE_TX_FLAGS_CSUM;
+	}
+	first->tx_flags |= TXGBE_TX_FLAGS_CC;
+	/* vlan_macip_lens: MACLEN, VLAN tag */
+#ifndef HAVE_ENCAP_TSO_OFFLOAD
+	vlan_macip_lens |= skb_network_offset(skb) << TXGBE_TXD_MACLEN_SHIFT;
+#endif /* !HAVE_ENCAP_TSO_OFFLOAD */
+	vlan_macip_lens |= first->tx_flags & TXGBE_TX_FLAGS_VLAN_MASK;
+
+	type_tucmd = dptype.ptype << 24;
+#ifdef NETIF_F_HW_VLAN_STAG_TX
+	if (skb->vlan_proto == htons(ETH_P_8021AD))
+		type_tucmd |= TXGBE_SET_FLAG(first->tx_flags,
+					TXGBE_TX_FLAGS_HW_VLAN,
+					0x1 << TXGBE_TXD_TAG_TPID_SEL_SHIFT);
+#endif
+	txgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, tunhdr_eiplen_tunlen,
+			 type_tucmd, mss_l4len_idx);
+}
+
+static u32 txgbe_tx_cmd_type(u32 tx_flags)
+{
+	/* set type for advanced descriptor with frame checksum insertion */
+	u32 cmd_type = TXGBE_TXD_DTYP_DATA |
+		       TXGBE_TXD_IFCS;
+
+	/* set HW vlan bit if vlan is present */
+	cmd_type |= TXGBE_SET_FLAG(tx_flags, TXGBE_TX_FLAGS_HW_VLAN,
+				   TXGBE_TXD_VLE);
+
+	/* set segmentation enable bits for TSO/FSO */
+	cmd_type |= TXGBE_SET_FLAG(tx_flags, TXGBE_TX_FLAGS_TSO,
+				   TXGBE_TXD_TSE);
+
+	/* set timestamp bit if present */
+	cmd_type |= TXGBE_SET_FLAG(tx_flags, TXGBE_TX_FLAGS_TSTAMP,
+				   TXGBE_TXD_MAC_TSTAMP);
+
+	cmd_type |= TXGBE_SET_FLAG(tx_flags, TXGBE_TX_FLAGS_LINKSEC,
+				   TXGBE_TXD_LINKSEC);
+
+	return cmd_type;
+}
+
+static void txgbe_tx_olinfo_status(union txgbe_tx_desc *tx_desc,
+				   u32 tx_flags, unsigned int paylen)
+{
+	u32 olinfo_status = paylen << TXGBE_TXD_PAYLEN_SHIFT;
+
+	/* enable L4 checksum for TSO and TX checksum offload */
+	olinfo_status |= TXGBE_SET_FLAG(tx_flags,
+					TXGBE_TX_FLAGS_CSUM,
+					TXGBE_TXD_L4CS);
+
+	/* enble IPv4 checksum for TSO */
+	olinfo_status |= TXGBE_SET_FLAG(tx_flags,
+					TXGBE_TX_FLAGS_IPV4,
+					TXGBE_TXD_IIPCS);
+	/* enable outer IPv4 checksum for TSO */
+	olinfo_status |= TXGBE_SET_FLAG(tx_flags,
+					TXGBE_TX_FLAGS_OUTER_IPV4,
+					TXGBE_TXD_EIPCS);
+	/*
+	 * Check Context must be set if Tx switch is enabled, which it
+	 * always is for case where virtual functions are running
+	 */
+	olinfo_status |= TXGBE_SET_FLAG(tx_flags,
+					TXGBE_TX_FLAGS_CC,
+					TXGBE_TXD_CC);
+
+	olinfo_status |= TXGBE_SET_FLAG(tx_flags,
+					TXGBE_TX_FLAGS_IPSEC,
+					TXGBE_TXD_IPSEC);
+
+	tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+}
+
+static int __txgbe_maybe_stop_tx(struct txgbe_ring *tx_ring, u16 size)
+{
+	netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+	/* Herbert's original patch had:
+	 *  smp_mb__after_netif_stop_queue();
+	 * but since that doesn't exist yet, just open code it.
+	 */
+	smp_mb();
+
+	/* We need to check again in a case another CPU has just
+	 * made room available.
+	 */
+	if (likely(txgbe_desc_unused(tx_ring) < size))
+		return -EBUSY;
+
+	/* A reprieve! - use start_queue because it doesn't call schedule */
+	netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+	++tx_ring->tx_stats.restart_queue;
+	return 0;
+}
+
+static inline int txgbe_maybe_stop_tx(struct txgbe_ring *tx_ring, u16 size)
+{
+	if (likely(txgbe_desc_unused(tx_ring) >= size))
+		return 0;
+
+	return __txgbe_maybe_stop_tx(tx_ring, size);
+}
+
+#define TXGBE_TXD_CMD (TXGBE_TXD_EOP | \
+		       TXGBE_TXD_RS)
+
+static int txgbe_tx_map(struct txgbe_ring *tx_ring,
+			 struct txgbe_tx_buffer *first,
+			 const u8 hdr_len)
+{
+	struct sk_buff *skb = first->skb;
+	struct txgbe_tx_buffer *tx_buffer;
+	union txgbe_tx_desc *tx_desc;
+	skb_frag_t *frag;
+	dma_addr_t dma;
+	unsigned int data_len, size;
+	u32 tx_flags = first->tx_flags;
+	u32 cmd_type = txgbe_tx_cmd_type(tx_flags);
+	u16 i = tx_ring->next_to_use;
+
+	tx_desc = TXGBE_TX_DESC(tx_ring, i);
+
+	txgbe_tx_olinfo_status(tx_desc, tx_flags, skb->len - hdr_len);
+
+	size = skb_headlen(skb);
+	data_len = skb->data_len;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (tx_flags & TXGBE_TX_FLAGS_FCOE) {
+		if (data_len < sizeof(struct fcoe_crc_eof)) {
+			size -= sizeof(struct fcoe_crc_eof) - data_len;
+			data_len = 0;
+		} else {
+			data_len -= sizeof(struct fcoe_crc_eof);
+		}
+	}
+#endif /* CONFIG_FCOE */
+
+	dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
+
+	tx_buffer = first;
+
+	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+		if (dma_mapping_error(tx_ring->dev, dma))
+			goto dma_error;
+
+		/* record length, and DMA address */
+		dma_unmap_len_set(tx_buffer, len, size);
+		dma_unmap_addr_set(tx_buffer, dma, dma);
+
+		tx_desc->read.buffer_addr = cpu_to_le64(dma);
+
+		while (unlikely(size > TXGBE_MAX_DATA_PER_TXD)) {
+			tx_desc->read.cmd_type_len =
+				cpu_to_le32(cmd_type ^ TXGBE_MAX_DATA_PER_TXD);
+
+			i++;
+			tx_desc++;
+			if (i == tx_ring->count) {
+				tx_desc = TXGBE_TX_DESC(tx_ring, 0);
+				i = 0;
+			}
+			tx_desc->read.olinfo_status = 0;
+
+			dma += TXGBE_MAX_DATA_PER_TXD;
+			size -= TXGBE_MAX_DATA_PER_TXD;
+
+			tx_desc->read.buffer_addr = cpu_to_le64(dma);
+		}
+
+		if (likely(!data_len))
+			break;
+
+		tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size);
+
+		i++;
+		tx_desc++;
+		if (i == tx_ring->count) {
+			tx_desc = TXGBE_TX_DESC(tx_ring, 0);
+			i = 0;
+		}
+		tx_desc->read.olinfo_status = 0;
+
+#if IS_ENABLED(CONFIG_FCOE)
+		size = min_t(unsigned int, data_len, skb_frag_size(frag));
+#else
+		size = skb_frag_size(frag);
+#endif
+		data_len -= size;
+
+		dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size,
+				       DMA_TO_DEVICE);
+
+		tx_buffer = &tx_ring->tx_buffer_info[i];
+	}
+
+	/* write last descriptor with RS and EOP bits */
+	cmd_type |= size | TXGBE_TXD_CMD;
+	tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+
+	netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
+
+	/* set the timestamp */
+	first->time_stamp = jiffies;
+
+#ifndef HAVE_TRANS_START_IN_QUEUE
+	netdev_ring(tx_ring)->trans_start = first->time_stamp;
+#endif
+	/*
+	 * Force memory writes to complete before letting h/w know there
+	 * are new descriptors to fetch.  (Only applicable for weak-ordered
+	 * memory model archs, such as IA-64).
+	 *
+	 * We also need this memory barrier to make certain all of the
+	 * status bits have been updated before next_to_watch is written.
+	 */
+	wmb();
+
+	/* set next_to_watch value indicating a packet is present */
+	first->next_to_watch = tx_desc;
+
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+
+	tx_ring->next_to_use = i;
+
+	txgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+	skb_tx_timestamp(skb);
+
+	if (netif_xmit_stopped(txring_txq(tx_ring)) || !netdev_xmit_more()) {
+		writel(i, tx_ring->tail);
+#ifndef SPIN_UNLOCK_IMPLIES_MMIOWB
+
+		/* The following mmiowb() is required on certain
+		 * architechtures (IA64/Altix in particular) in order to
+		 * synchronize the I/O calls with respect to a spin lock. This
+		 * is because the wmb() on those architectures does not
+		 * guarantee anything for posted I/O writes.
+		 *
+		 * Note that the associated spin_unlock() is not within the
+		 * driver code, but in the networking core stack.
+		 */
+		mmiowb();
+#endif /* SPIN_UNLOCK_IMPLIES_MMIOWB */
+	}
+
+	return 0;
+dma_error:
+	dev_err(tx_ring->dev, "TX DMA map failed\n");
+
+	/* clear dma mappings for failed tx_buffer_info map */
+	for (;;) {
+		tx_buffer = &tx_ring->tx_buffer_info[i];
+		if (dma_unmap_len(tx_buffer, len))
+			dma_unmap_page(tx_ring->dev,
+				       dma_unmap_addr(tx_buffer, dma),
+				       dma_unmap_len(tx_buffer, len),
+				       DMA_TO_DEVICE);
+		dma_unmap_len_set(tx_buffer, len, 0);
+		if (tx_buffer == first)
+			break;
+		if (i == 0)
+			i += tx_ring->count;
+		i--;
+	}
+
+	dev_kfree_skb_any(first->skb);
+	first->skb = NULL;
+
+	tx_ring->next_to_use = i;
+
+	return -1;
+}
+
+static void txgbe_atr(struct txgbe_ring *ring,
+		      struct txgbe_tx_buffer *first,
+		      txgbe_dptype dptype)
+{
+	struct txgbe_q_vector *q_vector = ring->q_vector;
+	union txgbe_atr_hash_dword input = { .dword = 0 };
+	union txgbe_atr_hash_dword common = { .dword = 0 };
+	union network_header hdr;
+	struct tcphdr *th;
+
+	/* if ring doesn't have a interrupt vector, cannot perform ATR */
+	if (!q_vector)
+		return;
+
+	/* do nothing if sampling is disabled */
+	if (!ring->atr_sample_rate)
+		return;
+
+	ring->atr_count++;
+#ifdef HAVE_ENCAP_TSO_OFFLOAD
+	if (dptype.etype) {
+		if (TXGBE_PTYPE_TYP_TCP != TXGBE_PTYPE_TYPL4(dptype.ptype))
+			return;
+		hdr.raw = (void *)skb_inner_network_header(first->skb);
+		th = inner_tcp_hdr(first->skb);
+	} else
+#endif
+	{
+		if (TXGBE_PTYPE_PKT_IP != TXGBE_PTYPE_PKT(dptype.ptype) ||
+		    TXGBE_PTYPE_TYP_TCP != TXGBE_PTYPE_TYPL4(dptype.ptype))
+			return;
+		hdr.raw = (void *)skb_network_header(first->skb);
+		th = tcp_hdr(first->skb);
+	}
+
+	/* skip this packet since it is invalid or the socket is closing */
+	if (!th || th->fin)
+		return;
+
+	/* sample on all syn packets or once every atr sample count */
+	if (!th->syn && (ring->atr_count < ring->atr_sample_rate))
+		return;
+
+	/* reset sample count */
+	ring->atr_count = 0;
+
+	/*
+	 * src and dst are inverted, think how the receiver sees them
+	 *
+	 * The input is broken into two sections, a non-compressed section
+	 * containing vm_pool, vlan_id, and flow_type.  The rest of the data
+	 * is XORed together and stored in the compressed dword.
+	 */
+	input.formatted.vlan_id = htons((u16)dptype.ptype);
+
+	/*
+	 * since src port and flex bytes occupy the same word XOR them together
+	 * and write the value to source port portion of compressed dword
+	 */
+	if (first->tx_flags & TXGBE_TX_FLAGS_SW_VLAN)
+		common.port.src ^= th->dest ^ first->skb->protocol;
+	else if (first->tx_flags & TXGBE_TX_FLAGS_HW_VLAN)
+#if defined(NETIF_F_HW_VLAN_CTAG_TX) || defined(NETIF_F_HW_VLAN_STAG_TX)
+		common.port.src ^= th->dest ^ first->skb->vlan_proto;
+#else
+		common.port.src ^= th->dest ^ htons(ETH_P_8021Q);
+#endif
+	else
+		common.port.src ^= th->dest ^ first->protocol;
+	common.port.dst ^= th->source;
+
+	if (TXGBE_PTYPE_PKT_IPV6 & TXGBE_PTYPE_PKT(dptype.ptype)) {
+		input.formatted.flow_type = TXGBE_ATR_FLOW_TYPE_TCPV6;
+		common.ip ^= hdr.ipv6->saddr.s6_addr32[0] ^
+					 hdr.ipv6->saddr.s6_addr32[1] ^
+					 hdr.ipv6->saddr.s6_addr32[2] ^
+					 hdr.ipv6->saddr.s6_addr32[3] ^
+					 hdr.ipv6->daddr.s6_addr32[0] ^
+					 hdr.ipv6->daddr.s6_addr32[1] ^
+					 hdr.ipv6->daddr.s6_addr32[2] ^
+					 hdr.ipv6->daddr.s6_addr32[3];
+	} else {
+		input.formatted.flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
+		common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
+	}
+
+	/* This assumes the Rx queue and Tx queue are bound to the same CPU */
+	txgbe_fdir_add_signature_filter(&q_vector->adapter->hw,
+					      input, common, ring->queue_index);
+}
+
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#if IS_ENABLED(CONFIG_FCOE)
+
+#if defined(HAVE_NDO_SELECT_QUEUE_FALLBACK_REMOVED)
+static u16 txgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
+			      struct net_device *sb_dev)
+#elif defined(HAVE_NDO_SELECT_QUEUE_SB_DEV)
+static u16 txgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
+			      __always_unused struct net_device *sb_dev,
+			      select_queue_fallback_t fallback)
+#elif defined(HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK)
+static u16 txgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
+			      __always_unused void *accel,
+			      select_queue_fallback_t fallback)
+#elif defined(HAVE_NDO_SELECT_QUEUE_ACCEL)
+static u16 txgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
+			      __always_unused void *accel)
+#else
+static u16 txgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
+#endif /* HAVE_NDO_SELECT_QUEUE_ACCEL */
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_ring_feature *f;
+	int txq;
+
+	/*
+	 * only execute the code below if protocol is FCoE
+	 * or FIP and we have FCoE enabled on the adapter
+	 */
+	switch (vlan_get_protocol(skb)) {
+	case __constant_htons(ETH_P_FCOE):
+	case __constant_htons(ETH_P_FIP):
+		adapter = netdev_priv(dev);
+
+		if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED)
+			break;
+		fallthrough;
+	default:
+#if defined(HAVE_NDO_SELECT_QUEUE_FALLBACK_REMOVED)
+		return netdev_pick_tx(dev, skb, sb_dev);
+#elif defined(HAVE_NDO_SELECT_QUEUE_SB_DEV)
+		return fallback(dev, skb, sb_dev);
+#elif defined(HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK)
+		return fallback(dev, skb);
+#else
+		return __netdev_pick_tx(dev, skb);
+#endif
+	}
+
+	f = &adapter->ring_feature[RING_F_FCOE];
+
+	txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
+					   smp_processor_id();
+
+	while (txq >= f->indices)
+		txq -= f->indices;
+
+	return txq + f->offset;
+}
+#endif /* CONFIG_FCOE */
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+
+/**
+ *	skb_pad			-	zero pad the tail of an skb
+ *	@skb: buffer to pad
+ *	@pad: space to pad
+ *
+ *	Ensure that a buffer is followed by a padding area that is zero
+ *	filled. Used by network drivers which may DMA or transfer data
+ *	beyond the buffer end onto the wire.
+ *
+ *	May return error in out of memory cases. The skb is freed on error.
+ */
+
+int txgbe_skb_pad_nonzero(struct sk_buff *skb, int pad)
+{
+	int err;
+	int ntail;
+
+	/* If the skbuff is non linear tailroom is always zero.. */
+	if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
+		memset(skb->data+skb->len, 0x1, pad);
+		return 0;
+	}
+
+	ntail = skb->data_len + pad - (skb->end - skb->tail);
+	if (likely(skb_cloned(skb) || ntail > 0)) {
+		err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC);
+		if (unlikely(err))
+			goto free_skb;
+	}
+
+	/* FIXME: The use of this function with non-linear skb's really needs
+	 * to be audited.
+	 */
+	err = skb_linearize(skb);
+	if (unlikely(err))
+		goto free_skb;
+
+	memset(skb->data + skb->len, 0x1, pad);
+	return 0;
+
+free_skb:
+	kfree_skb(skb);
+	return err;
+}
+
+
+netdev_tx_t txgbe_xmit_frame_ring(struct sk_buff *skb,
+				  struct txgbe_adapter __maybe_unused *adapter,
+				  struct txgbe_ring *tx_ring)
+{
+	struct txgbe_tx_buffer *first;
+	int tso;
+	u32 tx_flags = 0;
+	unsigned short f;
+	u16 count = TXD_USE_COUNT(skb_headlen(skb));
+	__be16 protocol = skb->protocol;
+	u8 hdr_len = 0;
+	txgbe_dptype dptype;
+	u8 vlan_addlen = 0;
+
+	/* work around hw errata 3 */
+	u16 _llcLen, *llcLen;
+	llcLen = skb_header_pointer(skb, ETH_HLEN - 2, sizeof(u16), &_llcLen);
+	if (*llcLen == 0x3 || *llcLen == 0x4 || *llcLen == 0x5) {
+		if (txgbe_skb_pad_nonzero(skb, ETH_ZLEN - skb->len))
+			return -ENOMEM;
+		__skb_put(skb, ETH_ZLEN - skb->len);
+	}
+
+	/*
+	 * need: 1 descriptor per page * PAGE_SIZE/TXGBE_MAX_DATA_PER_TXD,
+	 *       + 1 desc for skb_headlen/TXGBE_MAX_DATA_PER_TXD,
+	 *       + 2 desc gap to keep tail from touching head,
+	 *       + 1 desc for context descriptor,
+	 * otherwise try next time
+	 */
+	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+		count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->
+						     frags[f]));
+
+	if (txgbe_maybe_stop_tx(tx_ring, count + 3)) {
+		tx_ring->tx_stats.tx_busy++;
+		return NETDEV_TX_BUSY;
+	}
+
+	/* record the location of the first descriptor for this packet */
+	first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+	first->skb = skb;
+	first->bytecount = skb->len;
+	first->gso_segs = 1;
+
+	/* if we have a HW VLAN tag being added default to the HW one */
+	if (skb_vlan_tag_present(skb)) {
+		tx_flags |= skb_vlan_tag_get(skb) << TXGBE_TX_FLAGS_VLAN_SHIFT;
+		tx_flags |= TXGBE_TX_FLAGS_HW_VLAN;
+	/* else if it is a SW VLAN check the next protocol and store the tag */
+	} else if (protocol == htons(ETH_P_8021Q)) {
+		struct vlan_hdr *vhdr, _vhdr;
+		vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
+		if (!vhdr)
+			goto out_drop;
+
+		protocol = vhdr->h_vlan_encapsulated_proto;
+		tx_flags |= ntohs(vhdr->h_vlan_TCI) <<
+				  TXGBE_TX_FLAGS_VLAN_SHIFT;
+		tx_flags |= TXGBE_TX_FLAGS_SW_VLAN;
+	}
+
+	if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {
+		struct vlan_hdr *vhdr, _vhdr;
+		vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
+		if (!vhdr)
+			goto out_drop;
+
+		protocol = vhdr->h_vlan_encapsulated_proto;
+		tx_flags |= TXGBE_TX_FLAGS_SW_VLAN;
+		vlan_addlen += VLAN_HLEN;
+	}
+
+#ifdef HAVE_PTP_1588_CLOCK
+#ifdef SKB_SHARED_TX_IS_UNION
+	if (unlikely(skb_tx(skb)->hardware) &&
+	    adapter->ptp_clock) {
+	    if(!test_and_set_bit_lock(__TXGBE_PTP_TX_IN_PROGRESS,
+				   &adapter->state)) {
+		skb_tx(skb)->in_progress = 1;
+#else
+	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+	    adapter->ptp_clock) {
+		if (!test_and_set_bit_lock(__TXGBE_PTP_TX_IN_PROGRESS,
+				   &adapter->state)) {
+		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+#endif
+		tx_flags |= TXGBE_TX_FLAGS_TSTAMP;
+
+		/* schedule check for Tx timestamp */
+		adapter->ptp_tx_skb = skb_get(skb);
+		adapter->ptp_tx_start = jiffies;
+		schedule_work(&adapter->ptp_tx_work);
+		} else {
+			adapter->tx_hwtstamp_skipped++;
+		}
+	}
+
+#endif
+#ifdef CONFIG_PCI_IOV
+	/*
+	 * Use the l2switch_enable flag - would be false if the DMA
+	 * Tx switch had been disabled.
+	 */
+	if (adapter->flags & TXGBE_FLAG_SRIOV_L2SWITCH_ENABLE)
+		tx_flags |= TXGBE_TX_FLAGS_CC;
+
+#endif
+#ifdef HAVE_TX_MQ
+	if ((adapter->flags & TXGBE_FLAG_DCB_ENABLED) &&
+	    ((tx_flags & (TXGBE_TX_FLAGS_HW_VLAN | TXGBE_TX_FLAGS_SW_VLAN)) ||
+	     (skb->priority != TC_PRIO_CONTROL))) {
+		tx_flags &= ~TXGBE_TX_FLAGS_VLAN_PRIO_MASK;
+#if IS_ENABLED(CONFIG_FCOE)
+		/* for FCoE with DCB, we force the priority to what
+		 * was specified by the switch */
+		if ((adapter->flags & TXGBE_FLAG_FCOE_ENABLED) &&
+		    ((protocol == htons(ETH_P_FCOE)) ||
+		     (protocol == htons(ETH_P_FIP))))
+			tx_flags |= adapter->fcoe.up <<
+				    TXGBE_TX_FLAGS_VLAN_PRIO_SHIFT;
+		else
+#endif /* CONFIG_FCOE */
+			tx_flags |= skb->priority <<
+				    TXGBE_TX_FLAGS_VLAN_PRIO_SHIFT;
+		if (tx_flags & TXGBE_TX_FLAGS_SW_VLAN) {
+			struct vlan_ethhdr *vhdr;
+			if (skb_header_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				goto out_drop;
+			vhdr = (struct vlan_ethhdr *)skb->data;
+			vhdr->h_vlan_TCI = htons(tx_flags >>
+						 TXGBE_TX_FLAGS_VLAN_SHIFT);
+		} else {
+			tx_flags |= TXGBE_TX_FLAGS_HW_VLAN;
+		}
+	}
+
+#endif /* HAVE_TX_MQ */
+	/* record initial flags and protocol */
+	first->tx_flags = tx_flags;
+	first->protocol = protocol;
+
+	dptype = encode_tx_desc_ptype(first);
+
+#if IS_ENABLED(CONFIG_FCOE)
+	/* setup tx offload for FCoE */
+	if ((protocol == htons(ETH_P_FCOE)) &&
+	    (tx_ring->netdev->features & (NETIF_F_FSO | NETIF_F_FCOE_CRC))) {
+		tso = txgbe_fso(tx_ring, first, &hdr_len);
+		if (tso < 0)
+			goto out_drop;
+
+		goto xmit_fcoe;
+	} else if (protocol ==  htons(ETH_P_FIP)) {
+		/* FCoE stack has a bug where it does not set the network
+		 * header offset for FIP frames sent resulting into MACLEN
+		 * being set to ZERO in the Tx context descriptor.
+		 * This will cause MDD events when trying to Tx such frames.
+		 */
+		if (!skb_network_offset(skb)) {
+			if (tx_flags & (TXGBE_TX_FLAGS_HW_VLAN |
+			    TXGBE_TX_FLAGS_SW_VLAN))
+				skb_set_network_header(skb,
+						sizeof(struct ethhdr) +
+						sizeof(struct vlan_hdr) +
+						vlan_addlen);
+			else
+				skb_set_network_header(skb,
+						sizeof(struct ethhdr));
+		}
+	}
+#endif /* CONFIG_FCOE */
+
+	tso = txgbe_tso(tx_ring, first, &hdr_len, dptype);
+	if (tso < 0)
+		goto out_drop;
+	else if (!tso)
+		txgbe_tx_csum(tx_ring, first, dptype);
+
+	/* add the ATR filter if ATR is on */
+	if (test_bit(__TXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
+		txgbe_atr(tx_ring, first, dptype);
+
+#if IS_ENABLED(CONFIG_FCOE)
+xmit_fcoe:
+#endif /* CONFIG_FCOE */
+#ifdef HAVE_PTP_1588_CLOCK
+	if (txgbe_tx_map(tx_ring, first, hdr_len))
+		goto cleanup_tx_tstamp;
+#else
+	txgbe_tx_map(tx_ring, first, hdr_len);
+#endif
+
+	return NETDEV_TX_OK;
+
+out_drop:
+	dev_kfree_skb_any(first->skb);
+	first->skb = NULL;
+#ifdef HAVE_PTP_1588_CLOCK
+cleanup_tx_tstamp:
+	if (unlikely(tx_flags & TXGBE_TX_FLAGS_TSTAMP)) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+		cancel_work_sync(&adapter->ptp_tx_work);
+		clear_bit_unlock(__TXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
+	}
+#endif
+
+	return NETDEV_TX_OK;
+}
+
+static netdev_tx_t txgbe_xmit_frame(struct sk_buff *skb,
+				    struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_ring *tx_ring;
+#ifdef HAVE_TX_MQ
+	unsigned int r_idx = skb->queue_mapping;
+#endif
+
+	if (!netif_carrier_ok(netdev)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/*
+	 * The minimum packet size for olinfo paylen is 17 so pad the skb
+	 * in order to meet this minimum size requirement.
+	 */
+	if (skb_put_padto(skb, 17))
+		return NETDEV_TX_OK;
+
+#ifdef HAVE_TX_MQ
+	if (r_idx >= adapter->num_tx_queues)
+		r_idx = r_idx % adapter->num_tx_queues;
+	tx_ring = adapter->tx_ring[r_idx];
+#else
+	tx_ring = adapter->tx_ring[0];
+#endif
+	if (tx_ring->tx_buffer_info == NULL) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	return txgbe_xmit_frame_ring(skb, adapter, tx_ring);
+}
+
+/**
+ * txgbe_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int txgbe_set_mac(struct net_device *netdev, void *p)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	txgbe_del_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
+	//memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	eth_hw_addr_set(netdev, addr->sa_data);
+	memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
+
+	txgbe_mac_set_default_filter(adapter, hw->mac.addr);
+
+	return 0;
+}
+
+#if defined(HAVE_NETDEV_STORAGE_ADDRESS) && defined(NETDEV_HW_ADDR_T_SAN)
+/**
+ * txgbe_add_sanmac_netdev - Add the SAN MAC address to the corresponding
+ * netdev->dev_addr_list
+ * @netdev: network interface device structure
+ *
+ * Returns non-zero on failure
+ **/
+static int txgbe_add_sanmac_netdev(struct net_device *dev)
+{
+	int err = 0;
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+
+	if (is_valid_ether_addr(hw->mac.san_addr)) {
+		rtnl_lock();
+		err = dev_addr_add(dev, hw->mac.san_addr,
+				   NETDEV_HW_ADDR_T_SAN);
+		rtnl_unlock();
+
+		/* update SAN MAC vmdq pool selection */
+		TCALL(hw, mac.ops.set_vmdq_san_mac, VMDQ_P(0));
+	}
+	return err;
+}
+
+/**
+ * txgbe_del_sanmac_netdev - Removes the SAN MAC address to the corresponding
+ * netdev->dev_addr_list
+ * @netdev: network interface device structure
+ *
+ * Returns non-zero on failure
+ **/
+static int txgbe_del_sanmac_netdev(struct net_device *dev)
+{
+	int err = 0;
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_mac_info *mac = &adapter->hw.mac;
+
+	if (is_valid_ether_addr(mac->san_addr)) {
+		rtnl_lock();
+		err = dev_addr_del(dev, mac->san_addr, NETDEV_HW_ADDR_T_SAN);
+		rtnl_unlock();
+	}
+	return err;
+}
+
+#endif /* (HAVE_NETDEV_STORAGE_ADDRESS) && defined(NETDEV_HW_ADDR_T_SAN) */
+
+
+static int txgbe_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+			   int cmd)
+{
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &ifr->ifr_data;
+	int prtad, devad, ret;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 value = 0;
+
+	prtad = (mii->phy_id & MDIO_PHY_ID_PRTAD) >> 5;
+	devad = (mii->phy_id & MDIO_PHY_ID_DEVAD);
+
+	if (cmd == SIOCGMIIREG) {
+		ret = txgbe_read_mdio(&hw->phy_dev, prtad, devad, mii->reg_num,
+					&value);
+		if (ret < 0)
+			return ret;
+		mii->val_out = value;
+		return 0;
+	} else {
+		return txgbe_write_mdio(&hw->phy_dev, prtad, devad,
+			mii->reg_num, mii->val_in);
+	}
+}
+
+static int txgbe_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+#ifdef HAVE_PTP_1588_CLOCK
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+#endif
+	switch (cmd) {
+#ifdef HAVE_PTP_1588_CLOCK
+#ifdef SIOCGHWTSTAMP
+	case SIOCGHWTSTAMP:
+		return txgbe_ptp_get_ts_config(adapter, ifr);
+#endif
+	case SIOCSHWTSTAMP:
+		return txgbe_ptp_set_ts_config(adapter, ifr);
+#endif
+#ifdef ETHTOOL_OPS_COMPAT
+	case SIOCETHTOOL:
+		return ethtool_ioctl(ifr);
+#endif
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return txgbe_mii_ioctl(netdev, ifr, cmd);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void txgbe_netpoll(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* if interface is down do nothing */
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return;
+
+	if (adapter->flags & TXGBE_FLAG_MSIX_ENABLED) {
+		int i;
+		for (i = 0; i < adapter->num_q_vectors; i++) {
+			adapter->q_vector[i]->netpoll_rx = true;
+			txgbe_msix_clean_rings(0, adapter->q_vector[i]);
+			adapter->q_vector[i]->netpoll_rx = false;
+		}
+	} else {
+		txgbe_intr(0, adapter);
+	}
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/* txgbe_validate_rtr - verify 802.1Qp to Rx packet buffer mapping is valid.
+ * @adapter: pointer to txgbe_adapter
+ * @tc: number of traffic classes currently enabled
+ *
+ * Configure a valid 802.1Qp to Rx packet buffer mapping ie confirm
+ * 802.1Q priority maps to a packet buffer that exists.
+ */
+static void txgbe_validate_rtr(struct txgbe_adapter *adapter, u8 tc)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 reg, rsave;
+	int i;
+
+	reg = rd32(hw, TXGBE_RDB_UP2TC);
+	rsave = reg;
+
+	for (i = 0; i < TXGBE_DCB_MAX_TRAFFIC_CLASS; i++) {
+		u8 up2tc = 0xF & (reg >> (i * TXGBE_RDB_UP2TC_UP_SHIFT));
+
+		/* If up2tc is out of bounds default to zero */
+		if (up2tc > tc)
+			reg &= ~(0xF << (i * TXGBE_RDB_UP2TC_UP_SHIFT));
+	}
+
+	if (reg != rsave)
+		wr32(hw, TXGBE_RDB_UP2TC, reg);
+
+	return;
+}
+
+/**
+ * txgbe_set_prio_tc_map - Configure netdev prio tc map
+ * @adapter: Pointer to adapter struct
+ *
+ * Populate the netdev user priority to tc map
+ */
+static void txgbe_set_prio_tc_map(struct txgbe_adapter __maybe_unused *adapter)
+{
+#ifdef HAVE_DCBNL_IEEE
+	struct net_device *dev = adapter->netdev;
+	struct txgbe_dcb_config *dcb_cfg = &adapter->dcb_cfg;
+	struct ieee_ets *ets = adapter->txgbe_ieee_ets;
+	u8 prio;
+
+	for (prio = 0; prio < TXGBE_DCB_MAX_USER_PRIORITY; prio++) {
+		u8 tc = 0;
+
+		if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)
+			tc = txgbe_dcb_get_tc_from_up(dcb_cfg, 0, prio);
+		else if (ets)
+			tc = ets->prio_tc[prio];
+
+		netdev_set_prio_tc_map(dev, prio, tc);
+	}
+#else
+	UNREFERENCED_PARAMETER(adapter);
+#endif /*HAVE_DCBNL_IEEE*/
+}
+
+/**
+ * txgbe_setup_tc - routine to configure net_device for multiple traffic
+ * classes.
+ *
+ * @netdev: net device to configure
+ * @tc: number of traffic classes to enable
+ */
+int txgbe_setup_tc(struct net_device *dev, u8 tc)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+
+	/* Hardware supports up to 8 traffic classes */
+	if (tc > adapter->dcb_cfg.num_tcs.pg_tcs)
+		return -EINVAL;
+
+	if (tc && adapter->num_vmdqs > TXGBE_MAX_DCBMACVLANS)
+		return -EBUSY;
+
+	/* Hardware has to reinitialize queues and interrupts to
+	 * match packet buffer alignment. Unfortunately, the
+	 * hardware is not flexible enough to do this dynamically.
+	 */
+	if (netif_running(dev))
+		txgbe_close(dev);
+	else
+		txgbe_reset(adapter);
+
+	txgbe_clear_interrupt_scheme(adapter);
+
+	if (tc) {
+		netdev_set_num_tc(dev, tc);
+		txgbe_set_prio_tc_map(adapter);
+
+		adapter->flags |= TXGBE_FLAG_DCB_ENABLED;
+
+	} else {
+		netdev_reset_tc(dev);
+
+		adapter->flags &= ~TXGBE_FLAG_DCB_ENABLED;
+
+		adapter->temp_dcb_cfg.pfc_mode_enable = false;
+		adapter->dcb_cfg.pfc_mode_enable = false;
+	}
+
+	txgbe_validate_rtr(adapter, tc);
+
+	txgbe_init_interrupt_scheme(adapter);
+	if (netif_running(dev))
+		txgbe_open(dev);
+
+	return 0;
+}
+
+#ifdef NETIF_F_HW_TC
+#ifdef TC_MQPRIO_HW_OFFLOAD_MAX
+static int txgbe_setup_tc_mqprio(struct net_device *dev,
+				 struct tc_mqprio_qopt *mqprio)
+{
+	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+	return txgbe_setup_tc(dev, mqprio->num_tc);
+}
+#endif
+#if defined(HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV)
+static int
+__txgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
+		 void *type_data)
+#elif defined(HAVE_NDO_SETUP_TC_CHAIN_INDEX)
+static int
+__txgbe_setup_tc(struct net_device *dev, __always_unused u32 handle,
+		 u32 chain_index, __always_unused __be16 proto,
+		 struct tc_to_netdev *tc)
+#else
+static int
+__txgbe_setup_tc(struct net_device *dev, __always_unused u32 handle,
+		 __always_unused __be16 proto, struct tc_to_netdev *tc)
+#endif
+{
+#ifndef HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+	unsigned int type = tc->type;
+
+#ifdef HAVE_NDO_SETUP_TC_CHAIN_INDEX
+	if (chain_index)
+		return -EOPNOTSUPP;
+
+#endif
+#endif
+	switch (type) {
+	case TC_SETUP_QDISC_MQPRIO:
+#if defined(HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV)
+		return txgbe_setup_tc_mqprio(dev, type_data);
+#elif defined(TC_MQPRIO_HW_OFFLOAD_MAX) && \
+	(!(defined(TXGBE_SUPPORT_KYLIN_FT))) && \
+	(!(defined(TXGBE_SUPPORT_KYLIN_LX)))
+		return txgbe_setup_tc_mqprio(dev, tc->mqprio);
+#else
+		return txgbe_setup_tc(dev, tc->tc);
+#endif
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+#endif /* NETIF_F_HW_TC */
+
+#ifdef CONFIG_PCI_IOV
+void txgbe_sriov_reinit(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	rtnl_lock();
+	txgbe_setup_tc(netdev, netdev_get_num_tc(netdev));
+	rtnl_unlock();
+}
+#endif
+
+void txgbe_do_reset(struct net_device *netdev)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (netif_running(netdev))
+		txgbe_reinit_locked(adapter);
+	else
+		txgbe_reset(adapter);
+}
+
+#ifdef HAVE_NDO_SET_FEATURES
+#ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+static u32 txgbe_fix_features(struct net_device *netdev, u32 features)
+#else
+static netdev_features_t txgbe_fix_features(struct net_device *netdev,
+					    netdev_features_t features)
+#endif
+{
+#if defined(CONFIG_DCB) || defined(TXGBE_NO_LRO)
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+#endif
+
+#if IS_ENABLED(CONFIG_DCB)
+	if (adapter->flags & TXGBE_FLAG_DCB_ENABLED)
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+		features |= NETIF_F_HW_VLAN_CTAG_RX |
+				NETIF_F_HW_VLAN_STAG_RX;
+#elif (defined NETIF_F_HW_VLAN_CTAG_RX)
+		features |= NETIF_F_HW_VLAN_CTAG_RX;
+#elif (defined NETIF_F_HW_VLAN_STAG_RX)
+		features |= NETIF_F_HW_VLAN_STAG_RX;
+#else
+		features |= NETIF_F_HW_VLAN_RX;
+#endif
+#endif /* CONFIG_DCB */
+
+	/* If Rx checksum is disabled, then RSC/LRO should also be disabled */
+	if (!(features & NETIF_F_RXCSUM))
+		features &= ~NETIF_F_LRO;
+
+#ifdef TXGBE_NO_LRO
+	/* Turn off LRO if not RSC capable */
+	if (!(adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE))
+		features &= ~NETIF_F_LRO;
+
+#endif
+
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+	if (!(features & NETIF_F_HW_VLAN_CTAG_RX))
+		features &= ~NETIF_F_HW_VLAN_STAG_RX;
+	else
+		features |= NETIF_F_HW_VLAN_STAG_RX;
+	if (!(features & NETIF_F_HW_VLAN_CTAG_TX))
+		features &= ~NETIF_F_HW_VLAN_STAG_TX;
+	else
+		features |= NETIF_F_HW_VLAN_STAG_TX;
+#endif
+	return features;
+}
+
+#ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+static int txgbe_set_features(struct net_device *netdev, u32 features)
+#else
+static int txgbe_set_features(struct net_device *netdev,
+			      netdev_features_t features)
+#endif
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	bool need_reset = false;
+
+	/* Make sure RSC matches LRO, reset if change */
+	if (!(features & NETIF_F_LRO)) {
+		if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)
+			need_reset = true;
+		adapter->flags2 &= ~TXGBE_FLAG2_RSC_ENABLED;
+	} else if ((adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) &&
+		   !(adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)) {
+		if (adapter->rx_itr_setting == 1 ||
+		    adapter->rx_itr_setting > TXGBE_MIN_RSC_ITR) {
+			adapter->flags2 |= TXGBE_FLAG2_RSC_ENABLED;
+			need_reset = true;
+		} else if ((netdev->features ^ features) & NETIF_F_LRO) {
+#ifdef TXGBE_NO_LRO
+			e_info(probe, "rx-usecs set too low, "
+			       "disabling RSC\n");
+#else
+			e_info(probe, "rx-usecs set too low, "
+			       "falling back to software LRO\n");
+#endif
+		}
+	}
+
+	/*
+	 * Check if Flow Director n-tuple support was enabled or disabled.  If
+	 * the state changed, we need to reset.
+	 */
+	switch (features & NETIF_F_NTUPLE) {
+	case NETIF_F_NTUPLE:
+		/* turn off ATR, enable perfect filters and reset */
+		if (!(adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE))
+			need_reset = true;
+
+		adapter->flags &= ~TXGBE_FLAG_FDIR_HASH_CAPABLE;
+		adapter->flags |= TXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+		break;
+	default:
+		/* turn off perfect filters, enable ATR and reset */
+		if (adapter->flags & TXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+			need_reset = true;
+
+		adapter->flags &= ~TXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+
+		/* We cannot enable ATR if VMDq is enabled */
+		if (adapter->flags & TXGBE_FLAG_VMDQ_ENABLED)
+			break;
+
+		/* We cannot enable ATR if we have 2 or more traffic classes */
+		if (netdev_get_num_tc(netdev) > 1)
+			break;
+
+		/* We cannot enable ATR if RSS is disabled */
+		if (adapter->ring_feature[RING_F_RSS].limit <= 1)
+			break;
+
+		/* A sample rate of 0 indicates ATR disabled */
+		if (!adapter->atr_sample_rate)
+			break;
+
+		adapter->flags |= TXGBE_FLAG_FDIR_HASH_CAPABLE;
+		break;
+	}
+
+#if (defined NETIF_F_HW_VLAN_CTAG_RX) && (defined NETIF_F_HW_VLAN_STAG_RX)
+	if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
+		(features & NETIF_F_HW_VLAN_STAG_RX))
+#elif (defined NETIF_F_HW_VLAN_CTAG_RX)
+	if (features & NETIF_F_HW_VLAN_CTAG_RX)
+#elif (defined NETIF_F_HW_VLAN_STAG_RX)
+	if (features & NETIF_F_HW_VLAN_STAG_RX)
+#else
+	if (features & NETIF_F_HW_VLAN_RX)
+#endif
+		txgbe_vlan_strip_enable(adapter);
+	else
+		txgbe_vlan_strip_disable(adapter);
+
+#ifdef HAVE_VXLAN_CHECKS
+	if (adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE &&
+	    features & NETIF_F_RXCSUM) {
+		//if (!need_reset)
+		//	adapter->flags2 |= TXGBE_FLAG2_VXLAN_REREG_NEEDED;
+	} else {
+		txgbe_clear_vxlan_port(adapter);
+	}
+#endif /* HAVE_VXLAN_CHECKS */
+
+	if (features & NETIF_F_RXHASH) {
+		if (!(adapter->flags2 & TXGBE_FLAG2_RSS_ENABLED)) {
+			wr32m(&adapter->hw, TXGBE_RDB_RA_CTL, 
+				TXGBE_RDB_RA_CTL_RSS_EN, TXGBE_RDB_RA_CTL_RSS_EN);
+			adapter->flags2 |= TXGBE_FLAG2_RSS_ENABLED;
+		}
+	} else {
+		if (adapter->flags2 & TXGBE_FLAG2_RSS_ENABLED) {
+			wr32m(&adapter->hw, TXGBE_RDB_RA_CTL, 
+				TXGBE_RDB_RA_CTL_RSS_EN, ~TXGBE_RDB_RA_CTL_RSS_EN);
+			adapter->flags2 &= ~TXGBE_FLAG2_RSS_ENABLED;
+		}
+	}
+
+	if (need_reset)
+		txgbe_do_reset(netdev);
+
+	return 0;
+
+}
+#endif /* HAVE_NDO_SET_FEATURES */
+
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+#ifndef HAVE_UDP_TUNNEL_NIC_INFO
+/**
+ * txgbe_add_udp_tunnel_port - Get notifications about adding UDP tunnel ports
+ * @dev: The port's netdev
+ * @ti: Tunnel endpoint information
+ **/
+static void txgbe_add_udp_tunnel_port(struct net_device *dev,
+				      struct udp_tunnel_info *ti)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 port = ntohs(ti->port);
+
+	if (ti->sa_family != AF_INET)
+		return;
+
+	switch (ti->type) {
+	case UDP_TUNNEL_TYPE_VXLAN:
+		if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+			return;
+
+		if (adapter->vxlan_port == port)
+			return;
+
+		if (adapter->vxlan_port) {
+			netdev_info(dev,
+				    "VXLAN port %d set, not adding port %d\n",
+				    ntohs(adapter->vxlan_port),
+				    ntohs(port));
+			return;
+		}
+
+		adapter->vxlan_port = port;
+		wr32(hw, TXGBE_CFG_VXLAN, port);
+		break;
+	case UDP_TUNNEL_TYPE_GENEVE:
+	//	if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+	//		return;
+
+		if (adapter->geneve_port == port)
+			return;
+
+		if (adapter->geneve_port) {
+			netdev_info(dev,
+				    "GENEVE port %d set, not adding port %d\n",
+				    ntohs(adapter->geneve_port),
+				    ntohs(port));
+			return;
+		}
+
+		adapter->geneve_port = port;
+		wr32(hw, TXGBE_CFG_GENEVE, port);
+		break;
+	default:
+		return;
+	}
+
+
+}
+
+/**
+ * ixgbe_del_udp_tunnel_port - Get notifications about removing UDP tunnel ports
+ * @dev: The port's netdev
+ * @ti: Tunnel endpoint information
+ **/
+static void txgbe_del_udp_tunnel_port(struct net_device *dev,
+				      struct udp_tunnel_info *ti)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+
+	if (ti->type != UDP_TUNNEL_TYPE_VXLAN &&
+	    ti->type != UDP_TUNNEL_TYPE_GENEVE)
+		return;
+
+	if (ti->sa_family != AF_INET)
+		return;
+
+	switch (ti->type) {
+	case UDP_TUNNEL_TYPE_VXLAN:
+		if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+			return;
+
+		if (adapter->vxlan_port != ti->port) {
+			netdev_info(dev, "VXLAN port %d not found\n",
+				    ntohs(ti->port));
+			return;
+		}
+
+		txgbe_clear_vxlan_port(adapter);
+		adapter->flags2 |= TXGBE_FLAG2_VXLAN_REREG_NEEDED;
+		break;
+	case UDP_TUNNEL_TYPE_GENEVE:
+//		if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+//			return;
+
+		if (adapter->geneve_port != ti->port) {
+			netdev_info(dev, "GENEVE port %d not found\n",
+				    ntohs(ti->port));
+			return;
+		}
+
+		adapter->geneve_port = 0;
+		wr32(&adapter->hw, TXGBE_CFG_GENEVE, 0);
+		break;
+	default:
+		return;
+	}
+
+}
+#endif
+#elif defined(HAVE_VXLAN_RX_OFFLOAD)
+/**
+ * txgbe_add_vxlan_port - Get notifications about VXLAN ports that come up
+ * @dev: The port's netdev
+ * @sa_family: Socket Family that VXLAN is notifiying us about
+ * @port: New UDP port number that VXLAN started listening to
+ */
+static void txgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
+				 __be16 port)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 new_port = ntohs(port);
+
+	if (sa_family == AF_INET6)
+		return;
+
+	if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_ENABLE))
+		return;
+
+	if (adapter->vxlan_port == new_port) {
+		netdev_info(dev, "Port %d already offloaded\n", new_port);
+		return;
+	}
+	if (adapter->vxlan_port) {
+		netdev_info(dev,
+			    "Maximum VXLAN offload ports reached, not "
+			    "offloading port %d\n",
+			    new_port);
+		return;
+	}
+	adapter->vxlan_port = new_port;
+	wr32(hw, TXGBE_CFG_VXLAN, new_port);
+}
+
+/**
+ * txgbe_del_vxlan_port - Get notifications about VXLAN ports that go away
+ * @dev: The port's netdev
+ * @sa_family: Socket Family that VXLAN is notifying us about
+ * @port: UDP port number that VXLAN stopped listening to
+ */
+static void txgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
+				 __be16 port)
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	u16 new_port = ntohs(port);
+
+	if (sa_family == AF_INET6)
+		return;
+
+	if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_ENABLE))
+		return;
+
+	if (adapter->vxlan_port != new_port) {
+		netdev_info(dev, "Port %d was not found, not deleting\n",
+			    new_port);
+		return;
+	}
+
+	txgbe_clear_vxlan_port(adapter);
+	adapter->flags2 |= TXGBE_FLAG2_VXLAN_REREG_NEEDED;
+}
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+
+#ifdef HAVE_NDO_GSO_CHECK
+static bool
+txgbe_gso_check(struct sk_buff *skb, __always_unused struct net_device *dev)
+{
+	return vxlan_gso_check(skb);
+}
+#endif /* HAVE_NDO_GSO_CHECK */
+
+#ifdef HAVE_FDB_OPS
+#ifdef USE_CONST_DEV_UC_CHAR
+static int txgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			     struct net_device *dev,
+			     const unsigned char *addr,
+#ifdef HAVE_NDO_FDB_ADD_VID
+			     u16 vid,
+#endif
+#ifdef HAVE_NDO_FDB_ADD_EXTACK
+			     u16 flags,
+			     struct netlink_ext_ack __always_unused *extack)
+#else
+			     u16 flags)
+#endif
+#else
+static int txgbe_ndo_fdb_add(struct ndmsg *ndm,
+			     struct net_device *dev,
+			     unsigned char *addr,
+			     u16 flags)
+#endif /* USE_CONST_DEV_UC_CHAR */
+{
+	/* guarantee we can provide a unique filter for the unicast address */
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
+		if (TXGBE_MAX_PF_MACVLANS <= netdev_uc_count(dev))
+			return -ENOMEM;
+	}
+
+#ifdef USE_CONST_DEV_UC_CHAR
+#ifdef HAVE_NDO_FDB_ADD_VID
+	return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags);
+#else
+	return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
+#endif /* HAVE_NDO_FDB_ADD_VID */
+#else
+	return ndo_dflt_fdb_add(ndm, dev, addr, flags);
+#endif /* USE_CONST_DEV_UC_CHAR */
+}
+
+#ifdef HAVE_BRIDGE_ATTRIBS
+#ifdef HAVE_NDO_BRIDGE_SETLINK_EXTACK
+static int txgbe_ndo_bridge_setlink(struct net_device *dev,
+				    struct nlmsghdr *nlh,
+				    __always_unused u16 flags,
+				    struct netlink_ext_ack __always_unused *ext)
+#elif defined(HAVE_NDO_BRIDGE_SET_DEL_LINK_FLAGS)
+static int txgbe_ndo_bridge_setlink(struct net_device *dev,
+				    struct nlmsghdr *nlh,
+				    __always_unused u16 flags)
+#else
+static int txgbe_ndo_bridge_setlink(struct net_device *dev,
+				    struct nlmsghdr *nlh)
+#endif /* HAVE_NDO_BRIDGE_SETLINK_EXTACK */
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	struct nlattr *attr, *br_spec;
+	int rem;
+
+	if (!(adapter->flags & TXGBE_FLAG_SRIOV_ENABLED))
+		return -EOPNOTSUPP;
+
+	br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+
+	nla_for_each_nested(attr, br_spec, rem) {
+		__u16 mode;
+
+		if (nla_type(attr) != IFLA_BRIDGE_MODE)
+			continue;
+
+		mode = nla_get_u16(attr);
+		if (mode == BRIDGE_MODE_VEPA) {
+			adapter->flags |= TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
+		} else if (mode == BRIDGE_MODE_VEB) {
+			adapter->flags &= ~TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
+		} else {
+			return -EINVAL;
+		}
+
+		adapter->bridge_mode = mode;
+
+		/* re-configure settings related to bridge mode */
+		txgbe_configure_bridge_mode(adapter);
+
+		e_info(drv, "enabling bridge mode: %s\n",
+			mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB");
+	}
+
+	return 0;
+}
+
+#ifdef HAVE_NDO_BRIDGE_GETLINK_NLFLAGS
+static int txgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+				    struct net_device *dev,
+				    u32 __maybe_unused filter_mask,
+				    int nlflags)
+#elif defined(HAVE_BRIDGE_FILTER)
+static int txgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+				    struct net_device *dev,
+				    u32 __always_unused filter_mask)
+#else
+static int txgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+				    struct net_device *dev)
+#endif /* HAVE_NDO_BRIDGE_GETLINK_NLFLAGS */
+{
+	struct txgbe_adapter *adapter = netdev_priv(dev);
+	u16 mode;
+
+	if (!(adapter->flags & TXGBE_FLAG_SRIOV_ENABLED))
+		return 0;
+
+	mode = adapter->bridge_mode;
+#ifdef HAVE_NDO_DFLT_BRIDGE_GETLINK_VLAN_SUPPORT
+	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0, nlflags,
+				       filter_mask, NULL);
+#elif defined(HAVE_NDO_BRIDGE_GETLINK_NLFLAGS)
+	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0, nlflags);
+#elif defined(HAVE_NDO_FDB_ADD_VID) || \
+      defined (NDO_DFLT_BRIDGE_GETLINK_HAS_BRFLAGS)
+	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0);
+#else
+	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode);
+#endif /* HAVE_NDO_BRIDGE_GETLINK_NLFLAGS */
+}
+#endif /* HAVE_BRIDGE_ATTRIBS */
+#endif /* HAVE_FDB_OPS */
+
+#ifdef HAVE_NDO_FEATURES_CHECK
+#define TXGBE_MAX_TUNNEL_HDR_LEN 80
+static netdev_features_t
+txgbe_features_check(struct sk_buff *skb, struct net_device *dev,
+		     netdev_features_t features)
+{
+	u32 vlan_num = 0;
+	u16 vlan_depth = skb->mac_len;
+	__be16 type = skb->protocol;
+	struct vlan_hdr *vh;
+
+	if (skb_vlan_tag_present(skb)) {
+		vlan_num++;
+	}
+
+	if (vlan_depth) {
+		vlan_depth -= VLAN_HLEN;
+	} else {
+		vlan_depth = ETH_HLEN;
+	}
+
+	while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
+		vlan_num++;
+		vh = (struct vlan_hdr *)(skb->data + vlan_depth);
+		type = vh->h_vlan_encapsulated_proto;
+		vlan_depth += VLAN_HLEN;
+
+	}
+
+	if (vlan_num > 2)
+		features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
+			    NETIF_F_HW_VLAN_STAG_TX);
+
+	if (skb->encapsulation) {
+		if (unlikely(skb_inner_mac_header(skb) -
+			     skb_transport_header(skb) >
+			     TXGBE_MAX_TUNNEL_HDR_LEN))
+			return features & ~NETIF_F_CSUM_MASK;
+	}
+	return features;
+}
+#endif /* HAVE_NDO_FEATURES_CHECK */
+
+#ifdef HAVE_VIRTUAL_STATION
+static inline int txgbe_inc_vmdqs(struct txgbe_fwd_adapter *accel)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+
+	if (++adapter->num_vmdqs > 1 || adapter->num_vfs > 0)
+		adapter->flags |= TXGBE_FLAG_VMDQ_ENABLED |
+				  TXGBE_FLAG_SRIOV_ENABLED;
+	accel->index = find_first_zero_bit(&adapter->fwd_bitmask,
+					   TXGBE_MAX_MACVLANS);
+	set_bit(accel->index, &adapter->fwd_bitmask);
+
+	return 1 + find_last_bit(&adapter->fwd_bitmask, TXGBE_MAX_MACVLANS);
+}
+
+static inline int txgbe_dec_vmdqs(struct txgbe_fwd_adapter *accel)
+{
+	struct txgbe_adapter *adapter = accel->adapter;
+
+	if (--adapter->num_vmdqs == 1 && adapter->num_vfs == 0)
+		adapter->flags &= ~(TXGBE_FLAG_VMDQ_ENABLED |
+				    TXGBE_FLAG_SRIOV_ENABLED);
+	clear_bit(accel->index, &adapter->fwd_bitmask);
+
+	return 1 + find_last_bit(&adapter->fwd_bitmask, TXGBE_MAX_MACVLANS);
+}
+
+static void *txgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
+{
+	struct txgbe_fwd_adapter *accel = NULL;
+	struct txgbe_adapter *adapter = netdev_priv(pdev);
+	int used_pools = adapter->num_vfs + adapter->num_vmdqs;
+	int err;
+
+	if (test_bit(__TXGBE_DOWN, &adapter->state))
+		return ERR_PTR(-EPERM);
+
+	/* Hardware has a limited number of available pools. Each VF, and the
+	 * PF require a pool. Check to ensure we don't attempt to use more
+	 * than the available number of pools.
+	 */
+	if (used_pools >= TXGBE_MAX_VF_FUNCTIONS)
+		return ERR_PTR(-EINVAL);
+
+#ifdef CONFIG_RPS
+	if (vdev->num_rx_queues != vdev->num_tx_queues) {
+		netdev_info(pdev, "%s: Only supports a single queue count for "
+			    "TX and RX\n",
+			    vdev->name);
+		return ERR_PTR(-EINVAL);
+	}
+#endif
+	/* Check for hardware restriction on number of rx/tx queues */
+	if (vdev->num_tx_queues != 2 && vdev->num_tx_queues != 4) {
+		netdev_info(pdev,
+			    "%s: Supports RX/TX Queue counts 2, and 4\n",
+			    pdev->name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if ((adapter->flags & TXGBE_FLAG_DCB_ENABLED &&
+	     adapter->num_vmdqs > TXGBE_MAX_DCBMACVLANS - 1) ||
+	    (adapter->num_vmdqs > TXGBE_MAX_MACVLANS - 1))
+		return ERR_PTR(-EBUSY);
+
+	accel = kzalloc(sizeof(*accel), GFP_KERNEL);
+	if (!accel)
+		return ERR_PTR(-ENOMEM);
+	accel->adapter = adapter;
+
+	/* Enable VMDq flag so device will be set in VM mode */
+	adapter->ring_feature[RING_F_VMDQ].limit = txgbe_inc_vmdqs(accel);
+	adapter->ring_feature[RING_F_RSS].limit = vdev->num_tx_queues;
+
+	/* Force reinit of ring allocation with VMDQ enabled */
+	err = txgbe_setup_tc(pdev, netdev_get_num_tc(pdev));
+	if (err)
+		goto fwd_add_err;
+
+	err = txgbe_fwd_ring_up(vdev, accel);
+	if (err)
+		goto fwd_add_err;
+
+	netif_tx_start_all_queues(vdev);
+	return accel;
+fwd_add_err:
+	/* unwind counter and free adapter struct */
+	netdev_info(pdev,
+		    "%s: dfwd hardware acceleration failed\n", vdev->name);
+	txgbe_dec_vmdqs(accel);
+	kfree(accel);
+	return ERR_PTR(err);
+}
+
+static void txgbe_fwd_del(struct net_device *pdev, void *fwd_priv)
+{
+	struct txgbe_fwd_adapter *accel = fwd_priv;
+	struct txgbe_adapter *adapter = accel->adapter;
+
+	if (!accel || adapter->num_vmdqs <= 1)
+		return;
+
+	adapter->ring_feature[RING_F_VMDQ].limit = txgbe_dec_vmdqs(accel);
+	txgbe_fwd_ring_down(accel->vdev, accel);
+	txgbe_setup_tc(pdev, netdev_get_num_tc(pdev));
+	netdev_dbg(pdev, "pool %i:%i queues %i:%i VSI bitmask %lx\n",
+		   accel->index, adapter->num_vmdqs,
+		   accel->rx_base_queue,
+		   accel->rx_base_queue + adapter->queues_per_pool,
+		   adapter->fwd_bitmask);
+	kfree(accel);
+}
+#endif /*HAVE_VIRTUAL_STATION*/
+
+
+#ifdef HAVE_NET_DEVICE_OPS
+static const struct net_device_ops txgbe_netdev_ops = {
+	.ndo_open               = txgbe_open,
+	.ndo_stop               = txgbe_close,
+	.ndo_start_xmit         = txgbe_xmit_frame,
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#if IS_ENABLED(CONFIG_FCOE)
+	.ndo_select_queue       = txgbe_select_queue,
+#else
+#ifndef HAVE_MQPRIO
+	.ndo_select_queue       = __netdev_pick_tx,
+#endif
+#endif
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+	.ndo_set_rx_mode        = txgbe_set_rx_mode,
+	.ndo_validate_addr      = eth_validate_addr,
+	.ndo_set_mac_address    = txgbe_set_mac,
+#ifdef HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
+	.extended.ndo_change_mtu = txgbe_change_mtu,
+#else
+	.ndo_change_mtu		    = txgbe_change_mtu,
+#endif
+	.ndo_tx_timeout         = txgbe_tx_timeout,
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	.ndo_vlan_rx_add_vid    = txgbe_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid   = txgbe_vlan_rx_kill_vid,
+#endif
+	.ndo_do_ioctl           = txgbe_ioctl,
+#ifdef HAVE_RHEL7_NET_DEVICE_OPS_EXT
+	/* RHEL7 requires this to be defined to enable extended ops.  RHEL7 uses the
+	 * function get_ndo_ext to retrieve offsets for extended fields from with the
+	 * net_device_ops struct and ndo_size is checked to determine whether or not
+	 * the offset is valid.
+	 */
+	.ndo_size		= sizeof(const struct net_device_ops),
+#endif
+#ifdef IFLA_VF_MAX
+	.ndo_set_vf_mac         = txgbe_ndo_set_vf_mac,
+#ifdef HAVE_RHEL7_NETDEV_OPS_EXT_NDO_SET_VF_VLAN
+	.extended.ndo_set_vf_vlan = txgbe_ndo_set_vf_vlan,
+#else
+	.ndo_set_vf_vlan	= txgbe_ndo_set_vf_vlan,
+#endif
+
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+	.ndo_set_vf_rate        = txgbe_ndo_set_vf_bw,
+#else
+	.ndo_set_vf_tx_rate     = txgbe_ndo_set_vf_bw,
+#endif /* HAVE_NDO_SET_VF_MIN_MAX_TX_RATE */
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+	.ndo_set_vf_spoofchk    = txgbe_ndo_set_vf_spoofchk,
+#endif
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
+	.ndo_set_vf_link_state	= txgbe_ndo_set_vf_link_state,
+#endif
+#ifdef HAVE_NDO_SET_VF_TRUST
+#ifdef HAVE_RHEL7_NET_DEVICE_OPS_EXT
+	.extended.ndo_set_vf_trust = txgbe_ndo_set_vf_trust,
+#else
+	.ndo_set_vf_trust	= txgbe_ndo_set_vf_trust,
+#endif /* HAVE_RHEL7_NET_DEVICE_OPS_EXT */
+#endif /* HAVE_NDO_SET_VF_TRUST */
+
+	.ndo_get_vf_config      = txgbe_ndo_get_vf_config,
+#endif
+#ifdef HAVE_NDO_GET_STATS64
+	.ndo_get_stats64        = txgbe_get_stats64,
+#else
+	.ndo_get_stats          = txgbe_get_stats,
+#endif /* HAVE_NDO_GET_STATS64 */
+#ifdef HAVE_SETUP_TC
+#ifdef HAVE_RHEL7_NETDEV_OPS_EXT_NDO_SETUP_TC
+	.extended.ndo_setup_tc_rh = __txgbe_setup_tc,
+#else
+#ifdef NETIF_F_HW_TC
+	.ndo_setup_tc		= __txgbe_setup_tc,
+#else
+	.ndo_setup_tc		= txgbe_setup_tc,
+#endif /* NETIF_F_HW_TC */
+#endif /* HAVE_RHEL7_NETDEV_OPS_EXT_NDO_SETUP_TC */
+#endif /* HAVE_SETUP_TC */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller    = txgbe_netpoll,
+#endif
+#ifndef HAVE_RHEL6_NET_DEVICE_EXTENDED
+#ifdef HAVE_NDO_BUSY_POLL
+	.ndo_busy_poll          = txgbe_busy_poll_recv,
+#endif /* HAVE_NDO_BUSY_POLL */
+#endif /* !HAVE_RHEL6_NET_DEVICE_EXTENDED */
+#if IS_ENABLED(CONFIG_FCOE)
+	.ndo_fcoe_ddp_setup = txgbe_fcoe_ddp_get,
+#ifdef HAVE_NETDEV_OPS_FCOE_DDP_TARGET
+	.ndo_fcoe_ddp_target = txgbe_fcoe_ddp_target,
+#endif
+	.ndo_fcoe_ddp_done = txgbe_fcoe_ddp_put,
+#ifdef HAVE_NETDEV_OPS_FCOE_ENABLE
+	.ndo_fcoe_enable = txgbe_fcoe_enable,
+	.ndo_fcoe_disable = txgbe_fcoe_disable,
+#endif
+#ifdef HAVE_NETDEV_OPS_FCOE_GETWWN
+	.ndo_fcoe_get_wwn = txgbe_fcoe_get_wwn,
+#endif
+#endif /* CONFIG_FCOE */
+#ifdef HAVE_VLAN_RX_REGISTER
+	.ndo_vlan_rx_register   = &txgbe_vlan_mode,
+#endif
+#ifdef HAVE_FDB_OPS
+	.ndo_fdb_add            = txgbe_ndo_fdb_add,
+#ifndef USE_DEFAULT_FDB_DEL_DUMP
+	.ndo_fdb_del            = ndo_dflt_fdb_del,
+	.ndo_fdb_dump           = ndo_dflt_fdb_dump,
+#endif
+#ifdef HAVE_BRIDGE_ATTRIBS
+	.ndo_bridge_setlink     = txgbe_ndo_bridge_setlink,
+	.ndo_bridge_getlink     = txgbe_ndo_bridge_getlink,
+#endif /* HAVE_BRIDGE_ATTRIBS */
+#endif
+#ifdef HAVE_VIRTUAL_STATION
+	.ndo_dfwd_add_station   = txgbe_fwd_add,
+	.ndo_dfwd_del_station   = txgbe_fwd_del,
+#endif
+#ifdef HAVE_UDP_ENC_RX_OFFLOAD
+#ifdef HAVE_RHEL7_NETDEV_OPS_EXT_NDO_UDP_TUNNEL
+	.extended.ndo_udp_tunnel_add = txgbe_add_udp_tunnel_port,
+	.extended.ndo_udp_tunnel_del = txgbe_del_udp_tunnel_port,
+#else
+#ifndef HAVE_UDP_TUNNEL_NIC_INFO
+	.ndo_udp_tunnel_add	= txgbe_add_udp_tunnel_port,
+	.ndo_udp_tunnel_del	= txgbe_del_udp_tunnel_port,
+#endif
+#endif
+#elif defined(HAVE_VXLAN_RX_OFFLOAD)
+	.ndo_add_vxlan_port	= txgbe_add_vxlan_port,
+	.ndo_del_vxlan_port	= txgbe_del_vxlan_port,
+#endif /* HAVE_UDP_ENC_RX_OFFLOAD */
+#ifdef HAVE_NDO_GSO_CHECK
+	.ndo_gso_check          = txgbe_gso_check,
+#endif /* HAVE_NDO_GSO_CHECK */
+#ifdef HAVE_NDO_FEATURES_CHECK
+	.ndo_features_check     = txgbe_features_check,
+#endif /* HAVE_NDO_FEATURES_CHECK */
+#ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+};
 
-#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+/* RHEL6 keeps these operations in a separate structure */
+static const struct net_device_ops_ext txgbe_netdev_ops_ext = {
+	.size = sizeof(struct net_device_ops_ext),
+#endif /* HAVE_RHEL6_NET_DEVICE_OPS_EXT */
+#ifdef HAVE_NDO_SET_FEATURES
+	.ndo_set_features = txgbe_set_features,
+	.ndo_fix_features = txgbe_fix_features,
+#endif /* HAVE_NDO_SET_FEATURES */
+};
+#endif /* HAVE_NET_DEVICE_OPS */
 
-static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
+void txgbe_assign_netdev_ops(struct net_device *dev)
 {
-	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
-	struct net_device *netdev = adapter->netdev;
+#ifdef HAVE_NET_DEVICE_OPS
+	dev->netdev_ops = &txgbe_netdev_ops;
+#ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+	set_netdev_ops_ext(dev, &txgbe_netdev_ops_ext);
+#endif /* HAVE_RHEL6_NET_DEVICE_OPS_EXT */
+#else /* HAVE_NET_DEVICE_OPS */
+	dev->open = &txgbe_open;
+	dev->stop = &txgbe_close;
+	dev->hard_start_xmit = &txgbe_xmit_frame;
+	dev->get_stats = &txgbe_get_stats;
+#ifdef HAVE_SET_RX_MODE
+	dev->set_rx_mode = &txgbe_set_rx_mode;
+#endif
+	dev->set_multicast_list = &txgbe_set_rx_mode;
+	dev->set_mac_address = &txgbe_set_mac;
+	dev->change_mtu = &txgbe_change_mtu;
+	dev->do_ioctl = &txgbe_ioctl;
+#ifdef HAVE_TX_TIMEOUT
+	dev->tx_timeout = &txgbe_tx_timeout;
+#endif
+#if defined(NETIF_F_HW_VLAN_TX) || defined(NETIF_F_HW_VLAN_CTAG_TX) || \
+	defined(NETIF_F_HW_VLAN_STAG_TX)
+	dev->vlan_rx_register = &txgbe_vlan_mode;
+	dev->vlan_rx_add_vid = &txgbe_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = &txgbe_vlan_rx_kill_vid;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = &txgbe_netpoll;
+#endif
+#ifdef HAVE_NETDEV_SELECT_QUEUE
+#if IS_ENABLED(CONFIG_FCOE)
+	dev->select_queue = &txgbe_select_queue;
+#else
+	dev->select_queue = &__netdev_pick_tx;
+#endif
+#endif /* HAVE_NETDEV_SELECT_QUEUE */
+#endif /* HAVE_NET_DEVICE_OPS */
 
-	netif_device_detach(netdev);
+#ifdef HAVE_RHEL6_NET_DEVICE_EXTENDED
+#ifdef HAVE_NDO_BUSY_POLL
+	netdev_extended(dev)->ndo_busy_poll             = txgbe_busy_poll_recv;
+#endif /* HAVE_NDO_BUSY_POLL */
+#endif /* HAVE_RHEL6_NET_DEVICE_EXTENDED */
 
-	pci_disable_device(pdev);
+	txgbe_set_ethtool_ops(dev);
+	dev->watchdog_timeo = 5 * HZ;
 }
 
-static void txgbe_shutdown(struct pci_dev *pdev)
+/**
+ * txgbe_wol_supported - Check whether device supports WoL
+ * @adapter: the adapter private structure
+ * @device_id: the device ID
+ * @subdev_id: the subsystem device ID
+ *
+ * This function is used by probe and ethtool to determine
+ * which devices have WoL support
+ *
+ **/
+int txgbe_wol_supported(struct txgbe_adapter *adapter)
 {
-	bool wake;
-
-	txgbe_dev_shutdown(pdev, &wake);
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 wol_cap = adapter->eeprom_cap & TXGBE_DEVICE_CAPS_WOL_MASK;
 
-	if (system_state == SYSTEM_POWER_OFF) {
-		pci_wake_from_d3(pdev, wake);
-		pci_set_power_state(pdev, PCI_D3hot);
-	}
+	/* check eeprom to see if WOL is enabled */
+	if ((wol_cap == TXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
+	    ((wol_cap == TXGBE_DEVICE_CAPS_WOL_PORT0) &&
+	     (hw->bus.func == 0)))
+		return true;
+	else
+		return false;
 }
 
+
+
 /**
  * txgbe_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -63,71 +10584,699 @@ static void txgbe_shutdown(struct pci_dev *pdev)
  * The OS initialization, configuring of the adapter private structure,
  * and a hardware reset occur.
  **/
-static int txgbe_probe(struct pci_dev *pdev,
-		       const struct pci_device_id __always_unused *ent)
+static int __devinit txgbe_probe(struct pci_dev *pdev,
+				const struct pci_device_id __always_unused *ent)
 {
-	struct txgbe_adapter *adapter = NULL;
 	struct net_device *netdev;
-	int err;
+	struct txgbe_adapter *adapter = NULL;
+	struct txgbe_hw *hw = NULL;
+	static int cards_found;
+	int err, pci_using_dac, expected_gts;
+	u16 offset = 0;
+	u16 eeprom_verh = 0, eeprom_verl = 0;
+	u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0;
+	u32 etrack_id = 0;
+	u16 build = 0, major = 0, patch = 0;
+	char *info_string, *i_s_var;
+	u8 part_str[TXGBE_PBANUM_LENGTH];
+#ifdef HAVE_TX_MQ
+	unsigned int indices = MAX_TX_QUEUES;
+#endif /* HAVE_TX_MQ */
+	bool disable_dev = false;
+#if IS_ENABLED(CONFIG_FCOE)
+#endif /* IS_ENABLED(CONFIG_FCOE) */
+#ifndef NETIF_F_GSO_PARTIAL
+#ifdef HAVE_NDO_SET_FEATURES
+#ifndef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+	netdev_features_t hw_features;
+#else /* HAVE_RHEL6_NET_DEVICE_OPS_EXT */
+	u32 hw_features;
+#endif /* HAVE_RHEL6_NET_DEVICE_OPS_EXT */
+#endif /* HAVE_NDO_SET_FEATURES */
+#endif /* NETIF_F_GSO_PARTIAL */
+#ifdef TXGBE_DIS_COMP_TIMEOUT
+		u16 pvalue = 0;
+#endif
 
 	err = pci_enable_device_mem(pdev);
 	if (err)
 		return err;
 
-	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-	if (err) {
-		dev_err(&pdev->dev,
-			"No usable DMA configuration, aborting\n");
-		goto err_pci_disable_dev;
+
+	if (!dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64)) &&
+	    !dma_set_coherent_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64))) {
+		pci_using_dac = 1;
+	} else {
+		err = dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(32));
+		if (err) {
+			err = dma_set_coherent_mask(pci_dev_to_dev(pdev),
+						    DMA_BIT_MASK(32));
+			if (err) {
+				dev_err(pci_dev_to_dev(pdev), "No usable DMA "
+					"configuration, aborting\n");
+				goto err_dma;
+			}
+		}
+		pci_using_dac = 0;
 	}
 
-	err = pci_request_selected_regions(pdev,
-					   pci_select_bars(pdev, IORESOURCE_MEM),
-					   txgbe_driver_name);
+	err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
+					   IORESOURCE_MEM), txgbe_driver_name);
 	if (err) {
-		dev_err(&pdev->dev,
+		dev_err(pci_dev_to_dev(pdev),
 			"pci_request_selected_regions failed 0x%x\n", err);
-		goto err_pci_disable_dev;
+		goto err_pci_reg;
+	}
+
+
+	hw = vmalloc(sizeof(struct txgbe_hw));
+	if (!hw) {
+		pr_info("Unable to allocate memory for early mac "
+			"check\n");
+	} else {
+		hw->vendor_id = pdev->vendor;
+		hw->device_id = pdev->device;
+		vfree(hw);
 	}
 
 	pci_enable_pcie_error_reporting(pdev);
+
 	pci_set_master(pdev);
+	/* errata 16 */
+	if (MAX_REQUEST_SIZE == 512) {
+		pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+							PCI_EXP_DEVCTL_READRQ,
+							0x2000);
+	} else {
+		pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+							PCI_EXP_DEVCTL_READRQ,
+							0x1000);
+	}
 
-	netdev = devm_alloc_etherdev_mqs(&pdev->dev,
-					 sizeof(struct txgbe_adapter),
-					 TXGBE_MAX_TX_QUEUES,
-					 TXGBE_MAX_RX_QUEUES);
+#ifdef HAVE_TX_MQ
+	netdev = alloc_etherdev_mq(sizeof(struct txgbe_adapter), indices);
+#else /* HAVE_TX_MQ */
+	netdev = alloc_etherdev(sizeof(struct txgbe_adapter));
+#endif /* HAVE_TX_MQ */
 	if (!netdev) {
 		err = -ENOMEM;
-		goto err_pci_release_regions;
+		goto err_alloc_etherdev;
 	}
 
-	SET_NETDEV_DEV(netdev, &pdev->dev);
+	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, pci_dev_to_dev(pdev));
 
 	adapter = netdev_priv(netdev);
+#ifdef HAVE_TX_MQ
+#ifndef HAVE_NETDEV_SELECT_QUEUE
+	adapter->indices = indices;
+#endif
+#endif /* HAVE_TX_MQ */
 	adapter->netdev = netdev;
 	adapter->pdev = pdev;
+	hw = &adapter->hw;
+	hw->back = adapter;
+	adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+	hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
+			      pci_resource_len(pdev, 0));
+	adapter->io_addr = hw->hw_addr;
+	if (!hw->hw_addr) {
+		err = -EIO;
+		goto err_ioremap;
+	}
+
+	txgbe_assign_netdev_ops(netdev);
+
+	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+	adapter->bd_number = cards_found;
+
+	/* setup the private structure */
+	err = txgbe_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	/*
+	 * check_options must be called before setup_link to set up
+	 * hw->fc completely
+	 */
+	txgbe_check_options(adapter);
+	txgbe_bp_mode_setting(adapter);
+	TCALL(hw, mac.ops.set_lan_id);
+	/* check if flash load is done after hw power up */
+	err = txgbe_check_flash_load(hw, TXGBE_SPI_ILDR_STATUS_PERST);
+	if (err)
+		goto err_sw_init;
+	err = txgbe_check_flash_load(hw, TXGBE_SPI_ILDR_STATUS_PWRRST);
+	if (err)
+		goto err_sw_init;
+	/* reset_hw fills in the perm_addr as well */
+	hw->phy.reset_if_overtemp = true;
+	err = TCALL(hw, mac.ops.reset_hw);
+	hw->phy.reset_if_overtemp = false;
+	if (err == TXGBE_ERR_SFP_NOT_PRESENT) {
+		err = 0;
+	} else if (err == TXGBE_ERR_SFP_NOT_SUPPORTED) {
+		e_dev_err("failed to load because an unsupported SFP+ "
+			  "module type was detected.\n");
+		e_dev_err("Reload the driver after installing a supported "
+			  "module.\n");
+		goto err_sw_init;
+	} else if (err) {
+		e_dev_err("HW Init failed: %d\n", err);
+		goto err_sw_init;
+	}
+
+#ifdef CONFIG_PCI_IOV
+#ifdef HAVE_SRIOV_CONFIGURE
+	if (adapter->num_vfs > 0) {
+		e_dev_warn("Enabling SR-IOV VFs using the max_vfs module "
+			   "parameter is deprecated.\n");
+		e_dev_warn("Please use the pci sysfs interface instead. Ex:\n");
+		e_dev_warn("echo '%d' > /sys/bus/pci/devices/%04x:%02x:%02x.%1x"
+			   "/sriov_numvfs\n",
+			   adapter->num_vfs,
+			   pci_domain_nr(pdev->bus),
+			   pdev->bus->number,
+			   PCI_SLOT(pdev->devfn),
+			   PCI_FUNC(pdev->devfn)
+			   );
+	}
+
+#endif
+	if (adapter->flags & TXGBE_FLAG_SRIOV_CAPABLE) {
+		u32 match;
+		match = min_t(u32, adapter->vf_mode, TXGBE_MAX_VFS_DRV_LIMIT); 
+		pci_sriov_set_totalvfs(pdev, match);
+		txgbe_enable_sriov(adapter);
+	}
+#endif /* CONFIG_PCI_IOV */
+
+#ifdef NETIF_F_GSO_PARTIAL
+	netdev->features = NETIF_F_SG |
+			   NETIF_F_TSO |
+			   NETIF_F_TSO6 |
+			   NETIF_F_RXHASH |
+			   NETIF_F_RXCSUM |
+			   NETIF_F_HW_CSUM;
+
+	netdev->gso_partial_features = TXGBE_GSO_PARTIAL_FEATURES;
+	netdev->features |= NETIF_F_GSO_PARTIAL |
+			    TXGBE_GSO_PARTIAL_FEATURES;
+
+	netdev->features |= NETIF_F_SCTP_CRC;
+
+	/* copy netdev features into list of user selectable features */
+	netdev->hw_features |= netdev->features |
+			       NETIF_F_HW_VLAN_CTAG_FILTER |
+			       NETIF_F_HW_VLAN_CTAG_RX |
+			       NETIF_F_HW_VLAN_CTAG_TX |
+			       NETIF_F_RXALL;
+
+	netdev->hw_features |= NETIF_F_NTUPLE |
+				       NETIF_F_HW_TC;
+
+	if (pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID;
+	netdev->hw_enc_features |= netdev->vlan_features;
+	netdev->mpls_features |= NETIF_F_HW_CSUM;
+
+	/* set this bit last since it cannot be part of vlan_features */
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
+			    NETIF_F_HW_VLAN_CTAG_RX |
+			    NETIF_F_HW_VLAN_CTAG_TX;
+
+	netdev->priv_flags |= IFF_UNICAST_FLT;
+	netdev->priv_flags |= IFF_SUPP_NOFCS;
+
+	/* give us the option of enabling RSC/LRO later */
+	if (adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) {
+		netdev->hw_features |= NETIF_F_LRO;
+		netdev->features |= NETIF_F_LRO;
+	}
+#else	/* NETIF_F_GSO_PARTIAL */
+	netdev->features |= NETIF_F_SG |
+			    NETIF_F_IP_CSUM;
+
+#ifdef NETIF_F_IPV6_CSUM
+	netdev->features |= NETIF_F_IPV6_CSUM;
+#endif
+
+#ifdef NETIF_F_HW_VLAN_CTAG_TX
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_TX |
+			    NETIF_F_HW_VLAN_CTAG_RX;
+#endif
+
+#ifdef NETIF_F_HW_VLAN_STAG_TX
+	netdev->features |= NETIF_F_HW_VLAN_STAG_TX |
+			    NETIF_F_HW_VLAN_STAG_RX;
+#endif
+
+#ifdef NETIF_F_HW_VLAN_TX
+	netdev->features |= NETIF_F_HW_VLAN_TX |
+			    NETIF_F_HW_VLAN_RX;
+#endif
+	netdev->features |= txgbe_tso_features();
+#ifdef NETIF_F_RXHASH
+	if (adapter->flags2 & TXGBE_FLAG2_RSS_ENABLED)
+		netdev->features |= NETIF_F_RXHASH;
+#endif
+	netdev->features |= NETIF_F_RXCSUM;
+#ifdef HAVE_VIRTUAL_STATION
+	netdev->features |= NETIF_F_HW_L2FW_DOFFLOAD;
+#endif
+#ifdef HAVE_NDO_SET_FEATURES
+	/* copy netdev features into list of user selectable features */
+#ifndef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+	hw_features = netdev->hw_features;
+#else
+	hw_features = get_netdev_hw_features(netdev);
+#endif
+	hw_features |= netdev->features;
+
+	/* give us the option of enabling RSC/LRO later */
+#ifdef TXGBE_NO_LRO
+	if (adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE)
+#endif
+		hw_features |= NETIF_F_LRO;
 
-	adapter->io_addr = devm_ioremap(&pdev->dev,
-					pci_resource_start(pdev, 0),
-					pci_resource_len(pdev, 0));
-	if (!adapter->io_addr) {
+#else /* !HAVE_NDO_SET_FEATURES */
+#ifdef NETIF_F_GRO
+	/* this is only needed on kernels prior to 2.6.39 */
+	netdev->features |= NETIF_F_GRO;
+#endif
+#endif /* HAVE_NDO_SET_FEATURES */
+
+#ifdef NETIF_F_HW_VLAN_CTAG_TX
+	/* set this bit last since it cannot be part of hw_features */
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+#endif
+#ifdef NETIF_F_HW_VLAN_STAG_TX
+	netdev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+	/* set this bit last since it cannot be part of hw_features */
+	netdev->features |= NETIF_F_HW_VLAN_FILTER;
+#endif
+	netdev->features |= NETIF_F_SCTP_CSUM;
+	netdev->features |= NETIF_F_NTUPLE;
+	adapter->flags |= TXGBE_FLAG_FDIR_HASH_CAPABLE;
+#ifdef HAVE_NDO_SET_FEATURES
+	hw_features |= NETIF_F_SCTP_CSUM |
+			       NETIF_F_NTUPLE;
+#endif
+
+#ifdef HAVE_NDO_SET_FEATURES
+#ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
+	set_netdev_hw_features(netdev, hw_features);
+#else
+	netdev->hw_features = hw_features;
+#endif
+#endif
+
+#ifdef HAVE_NETDEV_VLAN_FEATURES
+	netdev->vlan_features |= NETIF_F_SG |
+				 NETIF_F_IP_CSUM |
+				 NETIF_F_IPV6_CSUM |
+				 NETIF_F_TSO |
+				 NETIF_F_TSO6;
+
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+#ifdef HAVE_ENCAP_CSUM_OFFLOAD
+	netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_IP_CSUM | TXGBE_GSO_PARTIAL_FEATURES | NETIF_F_TSO; 
+#endif /* HAVE_ENCAP_CSUM_OFFLOAD */
+#ifdef HAVE_VXLAN_RX_OFFLOAD
+	netdev->hw_enc_features |= NETIF_F_RXCSUM;
+
+#endif /* NETIF_F_GSO_PARTIAL */
+
+#endif /* HAVE_VXLAN_RX_OFFLOAD */
+	if (netdev->features & NETIF_F_LRO) {
+		if ((adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) &&
+		    ((adapter->rx_itr_setting == 1) ||
+		     (adapter->rx_itr_setting > TXGBE_MIN_RSC_ITR))) {
+			adapter->flags2 |= TXGBE_FLAG2_RSC_ENABLED;
+		} else if (adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE) {
+#ifdef TXGBE_NO_LRO
+			e_dev_info("InterruptThrottleRate set too high, "
+				   "disabling RSC\n");
+#else
+			e_dev_info("InterruptThrottleRate set too high, "
+				   "falling back to software LRO\n");
+#endif
+		}
+	}
+#ifdef IFF_UNICAST_FLT
+	netdev->priv_flags |= IFF_UNICAST_FLT;
+#endif
+#ifdef IFF_SUPP_NOFCS
+	netdev->priv_flags |= IFF_SUPP_NOFCS;
+#endif
+
+#ifdef HAVE_NETDEVICE_MIN_MAX_MTU
+	/* MTU range: 68 - 9710 */
+#ifdef HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
+	netdev->extended->min_mtu = ETH_MIN_MTU;
+	netdev->extended->max_mtu = TXGBE_MAX_JUMBO_FRAME_SIZE -
+				    (ETH_HLEN + ETH_FCS_LEN);
+#else
+	netdev->min_mtu = ETH_MIN_MTU;
+	netdev->max_mtu = TXGBE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN);
+#endif
+#endif /* HAVE_NETDEVICE_MIN_MAX_MTU */
+
+#if IS_ENABLED(CONFIG_DCB)
+	netdev->dcbnl_ops = &dcbnl_ops;
+#endif /* CONFIG_DCB */
+
+#if IS_ENABLED(CONFIG_FCOE)
+#ifdef NETIF_F_FSO
+	if (adapter->flags & TXGBE_FLAG_FCOE_CAPABLE) {
+		unsigned int fcoe_l;
+
+		{
+			netdev->features |= NETIF_F_FSO |
+					    NETIF_F_FCOE_CRC;
+#ifndef HAVE_NETDEV_OPS_FCOE_ENABLE
+			txgbe_fcoe_ddp_enable(adapter);
+			adapter->flags |= TXGBE_FLAG_FCOE_ENABLED;
+			netdev->features |= NETIF_F_FCOE_MTU;
+#endif /* HAVE_NETDEV_OPS_FCOE_ENABLE */
+		}
+
+		fcoe_l = min_t(int, TXGBE_RDB_FCRE_TBL_SIZE, num_online_cpus());
+		adapter->ring_feature[RING_F_FCOE].limit = fcoe_l;
+
+#ifdef HAVE_NETDEV_VLAN_FEATURES
+		netdev->vlan_features |= NETIF_F_FSO |
+					 NETIF_F_FCOE_CRC |
+					 NETIF_F_FCOE_MTU;
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+	}
+#endif /* NETIF_F_FSO */
+#endif /* CONFIG_FCOE */
+	if (pci_using_dac) {
+		netdev->features |= NETIF_F_HIGHDMA;
+#ifdef HAVE_NETDEV_VLAN_FEATURES
+		netdev->vlan_features |= NETIF_F_HIGHDMA;
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+	}
+
+	TCALL(hw, eeprom.ops.init_params);
+	/* make sure the EEPROM is good */
+	if (TCALL(hw, eeprom.ops.validate_checksum, NULL)) {
+		e_dev_err("The EEPROM Checksum Is Not Valid\n");
+		wr32(hw, TXGBE_MIS_RST, TXGBE_MIS_RST_SW_RST);
 		err = -EIO;
-		goto err_pci_release_regions;
+		goto err_sw_init;
+	}
+	eth_hw_addr_set(netdev, hw->mac.perm_addr);
+
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+		e_dev_err("invalid MAC address\n");
+		err = -EIO;
+		goto err_sw_init;
+	}
+
+	txgbe_mac_set_default_filter(adapter, hw->mac.perm_addr);
+
+	timer_setup(&adapter->service_timer, txgbe_service_timer, 0);
+	
+#ifdef POLL_LINK_STATUS
+	timer_setup(&adapter->link_check_timer, txgbe_link_check_timer, 0);
+#endif
+
+	if (TXGBE_REMOVED(hw->hw_addr)) {
+		err = -EIO;
+		goto err_sw_init;
+	}
+	INIT_WORK(&adapter->service_task, txgbe_service_task);
+	INIT_WORK(&adapter->sfp_sta_task, txgbe_sfp_phy_status_work);
+	set_bit(__TXGBE_SERVICE_INITED, &adapter->state);
+	clear_bit(__TXGBE_SERVICE_SCHED, &adapter->state);
+
+	err = txgbe_init_interrupt_scheme(adapter);
+	if (err)
+		goto err_sw_init;
+
+	/* WOL not supported for all devices */
+	adapter->wol = 0;
+	TCALL(hw, eeprom.ops.read,
+		hw->eeprom.sw_region_offset + TXGBE_DEVICE_CAPS,
+		&adapter->eeprom_cap);
+
+	if((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP &&
+		hw->bus.lan_id == 0) {
+		adapter->wol = TXGBE_PSR_WKUP_CTL_MAG;
+		wr32(hw, TXGBE_PSR_WKUP_CTL, adapter->wol);
+	}
+	hw->wol_enabled = !!(adapter->wol);
+
+	device_set_wakeup_enable(pci_dev_to_dev(adapter->pdev), adapter->wol);
+
+	/*
+	 * Save off EEPROM version number and Option Rom version which
+	 * together make a unique identify for the eeprom
+	 */
+	TCALL(hw, eeprom.ops.read,
+		hw->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_H,
+		&eeprom_verh);
+	TCALL(hw, eeprom.ops.read,
+		hw->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_L,
+		&eeprom_verl);
+	etrack_id = (eeprom_verh << 16) | eeprom_verl;
+
+	TCALL(hw, eeprom.ops.read,
+		hw->eeprom.sw_region_offset + TXGBE_ISCSI_BOOT_CONFIG, &offset);
+
+	/* Make sure offset to SCSI block is valid */
+	if (!(offset == 0x0) && !(offset == 0xffff)) {
+		TCALL(hw, eeprom.ops.read, offset + 0x84, &eeprom_cfg_blkh);
+		TCALL(hw, eeprom.ops.read, offset + 0x83, &eeprom_cfg_blkl);
+
+		/* Only display Option Rom if exist */
+		if (eeprom_cfg_blkl && eeprom_cfg_blkh) {
+			major = eeprom_cfg_blkl >> 8;
+			build = (eeprom_cfg_blkl << 8) | (eeprom_cfg_blkh >> 8);
+			patch = eeprom_cfg_blkh & 0x00ff;
+
+			snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+				 "0x%08x, %d.%d.%d", etrack_id, major, build,
+				 patch);
+		} else {
+			snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+				 "0x%08x", etrack_id);
+		}
+	} else {
+		snprintf(adapter->eeprom_id, sizeof(adapter->eeprom_id),
+			 "0x%08x", etrack_id);
 	}
 
-	netdev->features |= NETIF_F_HIGHDMA;
+	/* reset the hardware with the new settings */
+	err = TCALL(hw, mac.ops.start_hw);
+	if (err == TXGBE_ERR_EEPROM_VERSION) {
+		/* We are running on a pre-production device, log a warning */
+		e_dev_warn("This device is a pre-production adapter/LOM. "
+			   "Please be aware there may be issues associated "
+			   "with your hardware.  If you are experiencing "
+			   "problems please contact your hardware "
+			   "representative who provided you with this "
+			   "hardware.\n");
+	} else if (err) {
+		e_dev_err("HW init failed\n");
+		goto err_register;
+	}
+
+	/* pick up the PCI bus settings for reporting later */
+	TCALL(hw, mac.ops.get_bus_info);
+
+	strcpy(netdev->name, "eth%d");
+	err = register_netdev(netdev);
+	if (err)
+		goto err_register;
 
 	pci_set_drvdata(pdev, adapter);
+	adapter->netdev_registered = true;
+#ifdef HAVE_PCI_ERS
+	/*
+	 * call save state here in standalone driver because it relies on
+	 * adapter struct to exist, and needs to call netdev_priv
+	 */
+	pci_save_state(pdev);
+#endif
+
+
+	if(!((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP))
+		/* power down the optics for SFP+ fiber */
+		TCALL(hw, mac.ops.disable_tx_laser);
+
+	/* carrier off reporting is important to ethtool even BEFORE open */
+	netif_carrier_off(netdev);
+	/* keep stopping all the transmit queues for older kernels */
+	netif_tx_stop_all_queues(netdev);
+
+#if IS_ENABLED(CONFIG_TPH)
+	if (adapter->flags & TXGBE_FLAG_TPH_CAPABLE) {
+		err = dca_add_requester(pci_dev_to_dev(pdev));
+		switch (err) {
+		case 0:
+			adapter->flags |= TXGBE_FLAG_TPH_ENABLED;
+			txgbe_setup_tph(adapter);
+			break;
+		/* -19 is returned from the kernel when no provider is found */
+		case -19:
+			e_info(rx_err, "No TPH provider found. Please "
+			       "start ioatdma for DCA functionality.\n");
+			break;
+		default:
+			e_info(probe, "DCA registration failed: %d\n", err);
+			break;
+		}
+	}
+#endif
+
+	/* print all messages at the end so that we use our eth%d name */
+
+	/* calculate the expected PCIe bandwidth required for optimal
+	 * performance. Note that some older parts will never have enough
+	 * bandwidth due to being older generation PCIe parts. We clamp these
+	 * parts to ensure that no warning is displayed, as this could confuse
+	 * users otherwise. */
+
+	expected_gts = txgbe_enumerate_functions(adapter) * 10;
+
+
+	/* don't check link if we failed to enumerate functions */
+	if (expected_gts > 0)
+		txgbe_check_minimum_link(adapter, expected_gts);
+
+	if ((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)
+			e_info(probe, "NCSI : support");
+	else
+			e_info(probe, "NCSI : unsupported");
+
+	/* First try to read PBA as a string */
+	err = txgbe_read_pba_string(hw, part_str, TXGBE_PBANUM_LENGTH);
+	if (err)
+		strncpy(part_str, "Unknown", TXGBE_PBANUM_LENGTH);
+	if (txgbe_is_sfp(hw) && hw->phy.sfp_type != txgbe_sfp_type_not_present)
+		e_info(probe, "PHY: %d, SFP+: %d, PBA No: %s\n",
+		       hw->phy.type, hw->phy.sfp_type, part_str);
+	else
+		e_info(probe, "PHY: %d, PBA No: %s\n",
+		       hw->phy.type, part_str);
+
+	e_dev_info("%02x:%02x:%02x:%02x:%02x:%02x\n",
+		   netdev->dev_addr[0], netdev->dev_addr[1],
+		   netdev->dev_addr[2], netdev->dev_addr[3],
+		   netdev->dev_addr[4], netdev->dev_addr[5]);
+
+#define INFO_STRING_LEN 255
+	info_string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
+	if (!info_string) {
+		e_err(probe, "allocation for info string failed\n");
+		goto no_info_string;
+	}
+	i_s_var = info_string;
+	i_s_var += sprintf(info_string, "Enabled Features: ");
+	i_s_var += sprintf(i_s_var, "RxQ: %d TxQ: %d ",
+			   adapter->num_rx_queues, adapter->num_tx_queues);
+#if IS_ENABLED(CONFIG_FCOE)
+	if (adapter->flags & TXGBE_FLAG_FCOE_ENABLED)
+		i_s_var += sprintf(i_s_var, "FCoE ");
+#endif
+	if (adapter->flags & TXGBE_FLAG_FDIR_HASH_CAPABLE)
+		i_s_var += sprintf(i_s_var, "FdirHash ");
+	if (adapter->flags & TXGBE_FLAG_DCB_ENABLED)
+		i_s_var += sprintf(i_s_var, "DCB ");
+	if (adapter->flags & TXGBE_FLAG_TPH_ENABLED)
+		i_s_var += sprintf(i_s_var, "TPH ");
+	if (adapter->flags2 & TXGBE_FLAG2_RSC_ENABLED)
+		i_s_var += sprintf(i_s_var, "RSC ");
+#ifndef TXGBE_NO_LRO
+	else if (netdev->features & NETIF_F_LRO)
+		i_s_var += sprintf(i_s_var, "LRO ");
+#endif
+	if (adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_ENABLE)
+		i_s_var += sprintf(i_s_var, "vxlan_rx ");
+
+	BUG_ON(i_s_var > (info_string + INFO_STRING_LEN));
+	/* end features printing */
+	e_info(probe, "%s\n", info_string);
+	kfree(info_string);
+no_info_string:
+#ifdef CONFIG_PCI_IOV
+	if (adapter->flags & TXGBE_FLAG_SRIOV_ENABLED) {
+		int i;
+		for (i = 0; i < adapter->num_vfs; i++)
+			txgbe_vf_configuration(pdev, (i | 0x10000000));
+	}
+#endif
+	/* firmware requires blank driver version */
+	TCALL(hw, mac.ops.set_fw_drv_ver, 0xFF, 0xFF, 0xFF, 0xFF);
+#if defined(HAVE_NETDEV_STORAGE_ADDRESS) && defined(NETDEV_HW_ADDR_T_SAN)
+	/* add san mac addr to netdev */
+	txgbe_add_sanmac_netdev(netdev);
+
+#endif /* (HAVE_NETDEV_STORAGE_ADDRESS) && (NETDEV_HW_ADDR_T_SAN) */
+	e_info(probe, "WangXun(R) 10 Gigabit Network Connection\n");
+	cards_found++;
+#ifdef TXGBE_SYSFS
+	if (txgbe_sysfs_init(adapter))
+		e_err(probe, "failed to allocate sysfs resources\n");
+#ifdef TXGBE_PROCFS
+	if (txgbe_procfs_init(adapter))
+		e_err(probe, "failed to allocate procfs resources\n");
+#endif /* TXGBE_PROCFS */
+#endif /* TXGBE_SYSFS */
+
+#ifdef HAVE_TXGBE_DEBUG_FS
+	txgbe_dbg_adapter_init(adapter);
+#endif /* HAVE_TXGBE_DEBUG_FS */
+
+	/* setup link for SFP devices with MNG FW, else wait for TXGBE_UP */
+	if (txgbe_mng_present(hw) && txgbe_is_sfp(hw) &&
+		((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP))
+		TCALL(hw, mac.ops.setup_link,
+			TXGBE_LINK_SPEED_10GB_FULL | TXGBE_LINK_SPEED_1GB_FULL,
+			true);
+
+	TCALL(hw, mac.ops.setup_eee,
+		(adapter->flags2 & TXGBE_FLAG2_EEE_CAPABLE) &&
+		(adapter->flags2 & TXGBE_FLAG2_EEE_ENABLED));
+
+#ifdef TXGBE_DIS_COMP_TIMEOUT
+	pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &pvalue);
+	pvalue = pvalue | 0x10;
+	pcie_capability_write_word(pdev, PCI_EXP_DEVCTL2, pvalue);
+	e_info(probe, "disable completion timeout\n");
+#endif
 
 	return 0;
 
-err_pci_release_regions:
-	pci_disable_pcie_error_reporting(pdev);
+err_register:
+	txgbe_clear_interrupt_scheme(adapter);
+	txgbe_release_hw_control(adapter);
+err_sw_init:
+#ifdef CONFIG_PCI_IOV
+	txgbe_disable_sriov(adapter);
+#endif /* CONFIG_PCI_IOV */
+	adapter->flags2 &= ~TXGBE_FLAG2_SEARCH_FOR_SFP;
+	kfree(adapter->mac_table);
+	iounmap(adapter->io_addr);
+err_ioremap:
+	disable_dev = !test_and_set_bit(__TXGBE_DISABLED, &adapter->state);
+	free_netdev(netdev);
+err_alloc_etherdev:
 	pci_release_selected_regions(pdev,
 				     pci_select_bars(pdev, IORESOURCE_MEM));
-err_pci_disable_dev:
-	pci_disable_device(pdev);
+err_pci_reg:
+err_dma:
+	if (!adapter || disable_dev)
+		pci_disable_device(pdev);
 	return err;
 }
 
@@ -140,27 +11289,454 @@ static int txgbe_probe(struct pci_dev *pdev,
  * Hot-Plug event, or because the driver is going to be removed from
  * memory.
  **/
-static void txgbe_remove(struct pci_dev *pdev)
+static void __devexit txgbe_remove(struct pci_dev *pdev)
 {
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev;
+	bool disable_dev;
+
+	/* if !adapter then we already cleaned up in probe */
+	if (!adapter)
+		return;
+
+	netdev = adapter->netdev;
+#ifdef HAVE_TXGBE_DEBUG_FS
+	txgbe_dbg_adapter_exit(adapter);
+#endif
+
+	set_bit(__TXGBE_REMOVING, &adapter->state);
+	cancel_work_sync(&adapter->service_task);
+
+#if IS_ENABLED(CONFIG_TPH)
+	if (adapter->flags & TXGBE_FLAG_TPH_ENABLED) {
+		adapter->flags &= ~TXGBE_FLAG_TPH_ENABLED;
+	}
+#endif /* CONFIG_TPH */
+
+#ifdef TXGBE_SYSFS
+	txgbe_sysfs_exit(adapter);
+#else
+#ifdef TXGBE_PROCFS
+	txgbe_procfs_exit(adapter);
+#endif
+#endif /* TXGBE-SYSFS */
+
+#if defined(HAVE_NETDEV_STORAGE_ADDRESS) && defined(NETDEV_HW_ADDR_T_SAN)
+	/* remove the added san mac */
+	txgbe_del_sanmac_netdev(netdev);
+
+#endif /* (HAVE_NETDEV_STORAGE_ADDRESS) && (NETDEV_HW_ADDR_T_SAN) */
+	if (adapter->netdev_registered) {
+		unregister_netdev(netdev);
+		adapter->netdev_registered = false;
+	}
+
+#ifdef CONFIG_PCI_IOV
+	txgbe_disable_sriov(adapter);
+#endif
+
+#if IS_ENABLED(CONFIG_FCOE)
+#ifndef HAVE_NETDEV_OPS_FCOE_ENABLE
+	txgbe_fcoe_ddp_disable(adapter);
+#endif
+#endif /* CONFIG_FCOE */
+
+	txgbe_clear_interrupt_scheme(adapter);
+	txgbe_release_hw_control(adapter);
+
+#ifdef HAVE_DCBNL_IEEE
+	kfree(adapter->txgbe_ieee_pfc);
+	kfree(adapter->txgbe_ieee_ets);
+
+#endif
+	iounmap(adapter->io_addr);
 	pci_release_selected_regions(pdev,
 				     pci_select_bars(pdev, IORESOURCE_MEM));
 
+	kfree(adapter->mac_table);
+	disable_dev = !test_and_set_bit(__TXGBE_DISABLED, &adapter->state);
+	free_netdev(netdev);
+
 	pci_disable_pcie_error_reporting(pdev);
 
-	pci_disable_device(pdev);
+	if (disable_dev)
+		pci_disable_device(pdev);
+}
+
+static bool txgbe_check_cfg_remove(struct txgbe_hw *hw, struct pci_dev *pdev)
+{
+	u16 value;
+
+	pci_read_config_word(pdev, PCI_VENDOR_ID, &value);
+	if (value == TXGBE_FAILED_READ_CFG_WORD) {
+		txgbe_remove_adapter(hw);
+		return true;
+	}
+	return false;
+}
+
+u16 txgbe_read_pci_cfg_word(struct txgbe_hw *hw, u32 reg)
+{
+	struct txgbe_adapter *adapter = hw->back;
+	u16 value;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return TXGBE_FAILED_READ_CFG_WORD;
+	pci_read_config_word(adapter->pdev, reg, &value);
+	if (value == TXGBE_FAILED_READ_CFG_WORD &&
+	    txgbe_check_cfg_remove(hw, adapter->pdev))
+		return TXGBE_FAILED_READ_CFG_WORD;
+	return value;
+}
+
+#ifdef HAVE_PCI_ERS
+#ifdef CONFIG_PCI_IOV
+static u32 txgbe_read_pci_cfg_dword(struct txgbe_hw *hw, u32 reg)
+{
+	struct txgbe_adapter *adapter = hw->back;
+	u32 value;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return TXGBE_FAILED_READ_CFG_DWORD;
+	pci_read_config_dword(adapter->pdev, reg, &value);
+	if (value == TXGBE_FAILED_READ_CFG_DWORD &&
+	    txgbe_check_cfg_remove(hw, adapter->pdev))
+		return TXGBE_FAILED_READ_CFG_DWORD;
+	return value;
+}
+#endif /* CONFIG_PCI_IOV */
+#endif /* HAVE_PCI_ERS */
+
+void txgbe_write_pci_cfg_word(struct txgbe_hw *hw, u32 reg, u16 value)
+{
+	struct txgbe_adapter *adapter = hw->back;
+
+	if (TXGBE_REMOVED(hw->hw_addr))
+		return;
+	pci_write_config_word(adapter->pdev, reg, value);
+}
+
+#ifdef HAVE_PCI_ERS
+/**
+ * txgbe_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t txgbe_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+
+#ifdef CONFIG_PCI_IOV
+		struct txgbe_hw *hw = &adapter->hw;
+		struct pci_dev *bdev, *vfdev;
+		u32 dw0, dw1, dw2, dw3;
+		int vf, pos;
+		u16 req_id, pf_func;
+		e_info(hw, "in txgbe_io_error_detected.\n");
+
+		if (adapter->num_vfs == 0)
+			goto skip_bad_vf_detection;
+
+		bdev = pdev->bus->self;
+		while (bdev && (pci_pcie_type(bdev) != PCI_EXP_TYPE_ROOT_PORT))
+			bdev = bdev->bus->self;
+
+		if (!bdev)
+			goto skip_bad_vf_detection;
+
+		pos = pci_find_ext_capability(bdev, PCI_EXT_CAP_ID_ERR);
+		if (!pos)
+			goto skip_bad_vf_detection;
+
+		dw0 = txgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG);
+		dw1 = txgbe_read_pci_cfg_dword(hw,
+					       pos + PCI_ERR_HEADER_LOG + 4);
+		dw2 = txgbe_read_pci_cfg_dword(hw,
+					       pos + PCI_ERR_HEADER_LOG + 8);
+		dw3 = txgbe_read_pci_cfg_dword(hw,
+					       pos + PCI_ERR_HEADER_LOG + 12);
+		if (TXGBE_REMOVED(hw->hw_addr))
+			goto skip_bad_vf_detection;
+
+		req_id = dw1 >> 16;
+		/* if bit 7 of the requestor ID is set then it's a VF */
+		if (!(req_id & 0x0080))
+			goto skip_bad_vf_detection;
+
+		pf_func = req_id & 0x01;
+		if ((pf_func & 1) == (pdev->devfn & 1)) {
+			vf = (req_id & 0x7F) >> 1;
+			e_dev_err("VF %d has caused a PCIe error\n", vf);
+			e_dev_err("TLP: dw0: %8.8x\tdw1: %8.8x\tdw2: "
+					"%8.8x\tdw3: %8.8x\n",
+			dw0, dw1, dw2, dw3);
+
+			/* Find the pci device of the offending VF */
+			vfdev = pci_get_device(PCI_VENDOR_ID_TRUSTNETIC,
+						TXGBE_VF_DEVICE_ID, NULL);
+			while (vfdev) {
+				if (vfdev->devfn == (req_id & 0xFF))
+					break;
+				vfdev = pci_get_device(PCI_VENDOR_ID_TRUSTNETIC,
+						TXGBE_VF_DEVICE_ID, vfdev);
+			}
+			/*
+			 * There's a slim chance the VF could have been hot
+			 * plugged, so if it is no longer present we don't need
+			 * to issue the VFLR.Just clean up the AER in that case.
+			 */
+			if (vfdev) {
+				txgbe_issue_vf_flr(adapter, vfdev);
+				/* Free device reference count */
+				pci_dev_put(vfdev);
+			}
+
+			pci_aer_clear_nonfatal_status(pdev);
+		}
+
+		/*
+		 * Even though the error may have occurred on the other port
+		 * we still need to increment the vf error reference count for
+		 * both ports because the I/O resume function will be called
+		 * for both of them.
+		 */
+		adapter->vferr_refcount++;
+
+		return PCI_ERS_RESULT_RECOVERED;
+
+	skip_bad_vf_detection:
+#endif /* CONFIG_PCI_IOV */
+
+	if (!test_bit(__TXGBE_SERVICE_INITED, &adapter->state))
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	rtnl_lock();
+	netif_device_detach(netdev);
+
+	if (state == pci_channel_io_perm_failure) {
+		rtnl_unlock();
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	if (netif_running(netdev))
+		txgbe_close(netdev);
+
+	if (!test_and_set_bit(__TXGBE_DISABLED, &adapter->state))
+		pci_disable_device(pdev);
+	rtnl_unlock();
+	e_info(hw, "leave txgbe_io_error_detected.\n");
+
+	/* Request a slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * txgbe_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t txgbe_io_slot_reset(struct pci_dev *pdev)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	pci_ers_result_t result = PCI_ERS_RESULT_RECOVERED;
+
+	e_info(hw, "in txgbe_io_slot_reset\n");
+
+	if (pci_enable_device_mem(pdev)) {
+		e_err(probe, "Cannot re-enable PCI device after reset.\n");
+		result = PCI_ERS_RESULT_DISCONNECT;
+	} else {
+		smp_mb__before_atomic();
+		clear_bit(__TXGBE_DISABLED, &adapter->state);
+		adapter->hw.hw_addr = adapter->io_addr;
+		pci_set_master(pdev);
+		pci_restore_state(pdev);
+		/*
+		 * After second error pci->state_saved is false, this
+		 * resets it so EEH doesn't break.
+		 */
+		pci_save_state(pdev);
+
+		pci_wake_from_d3(pdev, false);
+
+		txgbe_reset(adapter);
+
+		result = PCI_ERS_RESULT_RECOVERED;
+	}
+
+	pci_aer_clear_nonfatal_status(pdev);
+	e_info(hw, "exit txgbe_io_slot_reset\n");
+
+	return result;
+}
+
+/**
+ * txgbe_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void txgbe_io_resume(struct pci_dev *pdev)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	struct net_device *netdev = adapter->netdev;
+	e_info(hw, "in io_resume.\n");
+
+#ifdef CONFIG_PCI_IOV
+	if (adapter->vferr_refcount) {
+		e_info(drv, "Resuming after VF err\n");
+		adapter->vferr_refcount--;
+		return;
+	}
+
+#endif
+	rtnl_lock();
+	if (netif_running(netdev))
+		txgbe_open(netdev);
+
+	netif_device_attach(netdev);
+	rtnl_unlock();
+	e_info(hw, "exit io_resume.\n");
+}
+
+#ifdef HAVE_CONST_STRUCT_PCI_ERROR_HANDLERS
+static const struct pci_error_handlers txgbe_err_handler = {
+#else
+static struct pci_error_handlers txgbe_err_handler = {
+#endif
+	.error_detected = txgbe_io_error_detected,
+	.slot_reset = txgbe_io_slot_reset,
+	.resume = txgbe_io_resume,
+};
+#endif /* HAVE_PCI_ERS */
+
+struct net_device *txgbe_hw_to_netdev(const struct txgbe_hw *hw)
+{
+	return ((struct txgbe_adapter *)hw->back)->netdev;
+}
+struct txgbe_msg *txgbe_hw_to_msg(const struct txgbe_hw *hw)
+{
+	struct txgbe_adapter *adapter =
+		container_of(hw, struct txgbe_adapter, hw);
+	return (struct txgbe_msg *)&adapter->msg_enable;
 }
 
+#ifdef CONFIG_PM
+#ifndef USE_LEGACY_PM_SUPPORT
+static const struct dev_pm_ops txgbe_pm_ops = {
+	.suspend        = txgbe_suspend,
+	.resume         = txgbe_resume,
+	.freeze         = txgbe_freeze,
+	.thaw           = txgbe_thaw,
+	.poweroff       = txgbe_suspend,
+	.restore        = txgbe_resume,
+};
+#endif /* USE_LEGACY_PM_SUPPORT */
+#endif
+
+#ifdef HAVE_RHEL6_SRIOV_CONFIGURE
+static struct pci_driver_rh txgbe_driver_rh = {
+	.sriov_configure = txgbe_pci_sriov_configure,
+};
+#endif
+
 static struct pci_driver txgbe_driver = {
 	.name     = txgbe_driver_name,
 	.id_table = txgbe_pci_tbl,
 	.probe    = txgbe_probe,
-	.remove   = txgbe_remove,
+	.remove   = __devexit_p(txgbe_remove),
+#ifdef CONFIG_PM
+#ifndef USE_LEGACY_PM_SUPPORT
+	.driver = {
+		.pm = &txgbe_pm_ops,
+	},
+#else
+	.suspend  = txgbe_suspend,
+	.resume   = txgbe_resume,
+#endif /* USE_LEGACY_PM_SUPPORT */
+#endif
+#ifndef USE_REBOOT_NOTIFIER
 	.shutdown = txgbe_shutdown,
+#endif
+
+#if defined(HAVE_SRIOV_CONFIGURE)
+	.sriov_configure = txgbe_pci_sriov_configure,
+#elif defined(HAVE_RHEL6_SRIOV_CONFIGURE)
+	.rh_reserved = &txgbe_driver_rh,
+#endif
+
+#ifdef HAVE_PCI_ERS
+	.err_handler = &txgbe_err_handler
+#endif
 };
 
-module_pci_driver(txgbe_driver);
+bool txgbe_is_txgbe(struct pci_dev *pcidev)
+{
+	if (pci_dev_driver(pcidev) != &txgbe_driver)
+		return false;
+	else
+		return true;
+}
+
+/**
+ * txgbe_init_module - Driver Registration Routine
+ *
+ * txgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init txgbe_init_module(void)
+{
+	int ret;
+	pr_info("%s - version %s\n", txgbe_driver_string, txgbe_driver_version);
+	pr_info("%s\n", txgbe_copyright);
+
+	txgbe_wq = create_singlethread_workqueue(txgbe_driver_name);
+	if (!txgbe_wq) {
+		pr_err("%s: Failed to create workqueue\n", txgbe_driver_name);
+		return -ENOMEM;
+	}
+
+#ifdef TXGBE_PROCFS
+	if (txgbe_procfs_topdir_init())
+		pr_info("Procfs failed to initialize topdir\n");
+#endif
+
+#ifdef HAVE_TXGBE_DEBUG_FS
+	txgbe_dbg_init();
+#endif
+
+	ret = pci_register_driver(&txgbe_driver);
+	return ret;
+}
+
+module_init(txgbe_init_module);
+
+/**
+ * txgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * txgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit txgbe_exit_module(void)
+{
+	pci_unregister_driver(&txgbe_driver);
+#ifdef TXGBE_PROCFS
+	txgbe_procfs_topdir_exit();
+#endif
+	destroy_workqueue(txgbe_wq);
+#ifdef HAVE_TXGBE_DEBUG_FS
+	txgbe_dbg_exit();
+#endif /* HAVE_TXGBE_DEBUG_FS */
+}
+
+module_exit(txgbe_exit_module);
+
+/* txgbe_main.c */
 
-MODULE_DEVICE_TABLE(pci, txgbe_pci_tbl);
-MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
-MODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.c
new file mode 100644
index 000000000000..691e6957a24a
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.c
@@ -0,0 +1,707 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_mbx.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#include "txgbe_type.h"
+#include "txgbe.h"
+#include "txgbe_mbx.h"
+
+
+/**
+ *  txgbe_read_mbx - Reads a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+int txgbe_read_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int err = TXGBE_ERR_MBX;
+
+	/* limit read to size of mailbox */
+	if (size > mbx->size)
+		size = mbx->size;
+
+	err = TCALL(hw, mbx.ops.read, msg, size, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_write_mbx - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+int txgbe_write_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int err = 0;
+
+	if (size > mbx->size) {
+		err = TXGBE_ERR_MBX;
+		ERROR_REPORT2(TXGBE_ERROR_ARGUMENT,
+			     "Invalid mailbox message size %d", size);
+	} else
+		err = TCALL(hw, mbx.ops.write, msg, size, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_msg - checks to see if someone sent us mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+int txgbe_check_for_msg(struct txgbe_hw *hw, u16 mbx_id)
+{
+	int err = TXGBE_ERR_MBX;
+
+	err = TCALL(hw, mbx.ops.check_for_msg, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_ack - checks to see if someone sent us ACK
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+int txgbe_check_for_ack(struct txgbe_hw *hw, u16 mbx_id)
+{
+	int err = TXGBE_ERR_MBX;
+
+	err = TCALL(hw, mbx.ops.check_for_ack, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_rst - checks to see if other side has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+int txgbe_check_for_rst(struct txgbe_hw *hw, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int err = TXGBE_ERR_MBX;
+
+	if (mbx->ops.check_for_rst)
+		err = mbx->ops.check_for_rst(hw, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+int txgbe_poll_for_msg(struct txgbe_hw *hw, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	if (!countdown || !mbx->ops.check_for_msg)
+		goto out;
+
+	while (countdown && TCALL(hw, mbx.ops.check_for_msg, mbx_id)) {
+		countdown--;
+		if (!countdown)
+			break;
+		udelay(mbx->udelay);
+	}
+
+	if (countdown == 0)
+		ERROR_REPORT2(TXGBE_ERROR_POLLING,
+			   "Polling for VF%d mailbox message timedout", mbx_id);
+
+out:
+	return countdown ? 0 : TXGBE_ERR_MBX;
+}
+
+/**
+ *  txgbe_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgement
+ **/
+int txgbe_poll_for_ack(struct txgbe_hw *hw, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	if (!countdown || !mbx->ops.check_for_ack)
+		goto out;
+
+	while (countdown && TCALL(hw, mbx.ops.check_for_ack, mbx_id)) {
+		countdown--;
+		if (!countdown)
+			break;
+		udelay(mbx->udelay);
+	}
+
+	if (countdown == 0)
+		ERROR_REPORT2(TXGBE_ERROR_POLLING,
+			     "Polling for VF%d mailbox ack timedout", mbx_id);
+
+out:
+	return countdown ? 0 : TXGBE_ERR_MBX;
+}
+
+/**
+ *  txgbe_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+int txgbe_read_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int err = TXGBE_ERR_MBX;
+
+	if (!mbx->ops.read)
+		goto out;
+
+	err = txgbe_poll_for_msg(hw, mbx_id);
+
+	/* if ack received read message, otherwise we timed out */
+	if (!err)
+		err = TCALL(hw, mbx.ops.read, msg, size, mbx_id);
+out:
+	return err;
+}
+
+/**
+ *  txgbe_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+int txgbe_write_posted_mbx(struct txgbe_hw *hw, u32 *msg, u16 size,
+			   u16 mbx_id)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+	int err;
+
+	/* exit if either we can't write or there isn't a defined timeout */
+	if (!mbx->timeout)
+		return TXGBE_ERR_MBX;
+
+	/* send msg */
+	err = TCALL(hw, mbx.ops.write, msg, size, mbx_id);
+
+	/* if msg sent wait until we receive an ack */
+	if (!err)
+		err = txgbe_poll_for_ack(hw, mbx_id);
+
+	return err;
+}
+
+/**
+ *  txgbe_init_mbx_ops - Initialize MB function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the mailbox read and write message function pointers
+ **/
+void txgbe_init_mbx_ops(struct txgbe_hw *hw)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+
+	mbx->ops.read_posted = txgbe_read_posted_mbx;
+	mbx->ops.write_posted = txgbe_write_posted_mbx;
+}
+
+/**
+ *  txgbe_read_v2p_mailbox - read v2p mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  This function is used to read the v2p mailbox without losing the read to
+ *  clear status bits.
+ **/
+u32 txgbe_read_v2p_mailbox(struct txgbe_hw *hw)
+{
+	u32 v2p_mailbox = rd32(hw, TXGBE_VXMAILBOX);
+
+	v2p_mailbox |= hw->mbx.v2p_mailbox;
+	/* read and clear mirrored mailbox flags */
+	v2p_mailbox |= rd32a(hw, TXGBE_VXMBMEM, TXGBE_VXMAILBOX_SIZE);
+	wr32a(hw, TXGBE_VXMBMEM, TXGBE_VXMAILBOX_SIZE, 0);
+	hw->mbx.v2p_mailbox |= v2p_mailbox & TXGBE_VXMAILBOX_R2C_BITS;
+
+	return v2p_mailbox;
+}
+
+/**
+ *  txgbe_check_for_bit_vf - Determine if a status bit was set
+ *  @hw: pointer to the HW structure
+ *  @mask: bitmask for bits to be tested and cleared
+ *
+ *  This function is used to check for the read to clear bits within
+ *  the V2P mailbox.
+ **/
+int txgbe_check_for_bit_vf(struct txgbe_hw *hw, u32 mask)
+{
+	u32 mailbox = txgbe_read_v2p_mailbox(hw);
+
+	hw->mbx.v2p_mailbox &= ~mask;
+
+	return (mailbox & mask ? 0 : TXGBE_ERR_MBX);
+}
+
+/**
+ *  txgbe_check_for_msg_vf - checks to see if the PF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the Status bit or else ERR_MBX
+ **/
+int txgbe_check_for_msg_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+	int err = TXGBE_ERR_MBX;
+
+	UNREFERENCED_PARAMETER(mbx_id);
+
+	/* read clear the pf sts bit */
+	if (!txgbe_check_for_bit_vf(hw, TXGBE_VXMAILBOX_PFSTS)) {
+		err = 0;
+		hw->mbx.stats.reqs++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_ack_vf - checks to see if the PF has ACK'd
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
+ **/
+int txgbe_check_for_ack_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+	int err = TXGBE_ERR_MBX;
+
+	UNREFERENCED_PARAMETER(mbx_id);
+
+	/* read clear the pf ack bit */
+	if (!txgbe_check_for_bit_vf(hw, TXGBE_VXMAILBOX_PFACK)) {
+		err = 0;
+		hw->mbx.stats.acks++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_rst_vf - checks to see if the PF has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns true if the PF has set the reset done bit or else false
+ **/
+int txgbe_check_for_rst_vf(struct txgbe_hw *hw, u16 mbx_id)
+{
+	int err = TXGBE_ERR_MBX;
+
+	UNREFERENCED_PARAMETER(mbx_id);
+	if (!txgbe_check_for_bit_vf(hw, (TXGBE_VXMAILBOX_RSTD |
+	    TXGBE_VXMAILBOX_RSTI))) {
+		err = 0;
+		hw->mbx.stats.rsts++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_obtain_mbx_lock_vf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+int txgbe_obtain_mbx_lock_vf(struct txgbe_hw *hw)
+{
+	int err = TXGBE_ERR_MBX;
+	u32 mailbox;
+
+	/* Take ownership of the buffer */
+	wr32(hw, TXGBE_VXMAILBOX, TXGBE_VXMAILBOX_VFU);
+
+	/* reserve mailbox for vf use */
+	mailbox = txgbe_read_v2p_mailbox(hw);
+	if (mailbox & TXGBE_VXMAILBOX_VFU)
+		err = 0;
+	else
+		ERROR_REPORT2(TXGBE_ERROR_POLLING,
+			   "Failed to obtain mailbox lock for VF");
+
+	return err;
+}
+
+/**
+ *  txgbe_write_mbx_vf - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+int txgbe_write_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size,
+			      u16 mbx_id)
+{
+	int err;
+	u16 i;
+
+	UNREFERENCED_PARAMETER(mbx_id);
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = txgbe_obtain_mbx_lock_vf(hw);
+	if (err)
+		goto out_no_write;
+
+	/* flush msg and acks as we are overwriting the message buffer */
+	txgbe_check_for_msg_vf(hw, 0);
+	txgbe_check_for_ack_vf(hw, 0);
+
+	/* copy the caller specified message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		wr32a(hw, TXGBE_VXMBMEM, i, msg[i]);
+
+	/* update stats */
+	hw->mbx.stats.msgs_tx++;
+
+	/* Drop VFU and interrupt the PF to tell it a message has been sent */
+	wr32(hw, TXGBE_VXMAILBOX, TXGBE_VXMAILBOX_REQ);
+
+out_no_write:
+	return err;
+}
+
+/**
+ *  txgbe_read_mbx_vf - Reads a message from the inbox intended for vf
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+int txgbe_read_mbx_vf(struct txgbe_hw *hw, u32 *msg, u16 size,
+			     u16 mbx_id)
+{
+	int err = 0;
+	u16 i;
+	UNREFERENCED_PARAMETER(mbx_id);
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = txgbe_obtain_mbx_lock_vf(hw);
+	if (err)
+		goto out_no_read;
+
+	/* copy the message from the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		msg[i] = rd32a(hw, TXGBE_VXMBMEM, i);
+
+	/* Acknowledge receipt and release mailbox, then we're done */
+	wr32(hw, TXGBE_VXMAILBOX, TXGBE_VXMAILBOX_ACK);
+
+	/* update stats */
+	hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+	return err;
+}
+
+/**
+ *  txgbe_init_mbx_params_vf - set initial values for vf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+void txgbe_init_mbx_params_vf(struct txgbe_hw *hw)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+
+	/* start mailbox as timed out and let the reset_hw call set the timeout
+	 * value to begin communications */
+	mbx->timeout = 0;
+	mbx->udelay = TXGBE_VF_MBX_INIT_DELAY;
+
+	mbx->size = TXGBE_VXMAILBOX_SIZE;
+
+	mbx->ops.read = txgbe_read_mbx_vf;
+	mbx->ops.write = txgbe_write_mbx_vf;
+	mbx->ops.read_posted = txgbe_read_posted_mbx;
+	mbx->ops.write_posted = txgbe_write_posted_mbx;
+	mbx->ops.check_for_msg = txgbe_check_for_msg_vf;
+	mbx->ops.check_for_ack = txgbe_check_for_ack_vf;
+	mbx->ops.check_for_rst = txgbe_check_for_rst_vf;
+
+	mbx->stats.msgs_tx = 0;
+	mbx->stats.msgs_rx = 0;
+	mbx->stats.reqs = 0;
+	mbx->stats.acks = 0;
+	mbx->stats.rsts = 0;
+}
+
+int txgbe_check_for_bit_pf(struct txgbe_hw *hw, u32 mask, int index)
+{
+	u32 mbvficr = rd32(hw, TXGBE_MBVFICR(index));
+	int err = TXGBE_ERR_MBX;
+
+	if (mbvficr & mask) {
+		err = 0;
+		wr32(hw, TXGBE_MBVFICR(index), mask);
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_msg_pf - checks to see if the VF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @vf: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+int txgbe_check_for_msg_pf(struct txgbe_hw *hw, u16 vf)
+{
+	int err = TXGBE_ERR_MBX;
+	int index = TXGBE_MBVFICR_INDEX(vf);
+	u32 vf_bit = vf % 16;
+
+	if (!txgbe_check_for_bit_pf(hw, TXGBE_MBVFICR_VFREQ_VF1 << vf_bit,
+				    index)) {
+		err = 0;
+		hw->mbx.stats.reqs++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_ack_pf - checks to see if the VF has ACKed
+ *  @hw: pointer to the HW structure
+ *  @vf: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+int txgbe_check_for_ack_pf(struct txgbe_hw *hw, u16 vf)
+{
+	int err = TXGBE_ERR_MBX;
+	int index = TXGBE_MBVFICR_INDEX(vf);
+	u32 vf_bit = vf % 16;
+
+	if (!txgbe_check_for_bit_pf(hw, TXGBE_MBVFICR_VFACK_VF1 << vf_bit,
+				    index)) {
+		err = 0;
+		hw->mbx.stats.acks++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_check_for_rst_pf - checks to see if the VF has reset
+ *  @hw: pointer to the HW structure
+ *  @vf: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+int txgbe_check_for_rst_pf(struct txgbe_hw *hw, u16 vf)
+{
+	u32 reg_offset = (vf < 32) ? 0 : 1;
+	u32 vf_shift = vf % 32;
+	u32 vflre = 0;
+	int err = TXGBE_ERR_MBX;
+
+	vflre = rd32(hw, TXGBE_VFLRE(reg_offset));
+
+	if (vflre & (1 << vf_shift)) {
+		err = 0;
+		wr32(hw, TXGBE_VFLREC(reg_offset), (1 << vf_shift));
+		hw->mbx.stats.rsts++;
+	}
+
+	return err;
+}
+
+/**
+ *  txgbe_obtain_mbx_lock_pf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *  @vf: the VF index
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+int txgbe_obtain_mbx_lock_pf(struct txgbe_hw *hw, u16 vf)
+{
+	int err = TXGBE_ERR_MBX;
+	u32 mailbox;
+
+	/* Take ownership of the buffer */
+	wr32(hw, TXGBE_PXMAILBOX(vf), TXGBE_PXMAILBOX_PFU);
+
+	/* reserve mailbox for vf use */
+	mailbox = rd32(hw, TXGBE_PXMAILBOX(vf));
+	if (mailbox & TXGBE_PXMAILBOX_PFU)
+		err = 0;
+	else
+		ERROR_REPORT2(TXGBE_ERROR_POLLING,
+			   "Failed to obtain mailbox lock for PF%d", vf);
+
+
+	return err;
+}
+
+/**
+ *  txgbe_write_mbx_pf - Places a message in the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf: the VF index
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+int txgbe_write_mbx_pf(struct txgbe_hw *hw, u32 *msg, u16 size,
+			      u16 vf)
+{
+	int err;
+	u16 i;
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = txgbe_obtain_mbx_lock_pf(hw, vf);
+	if (err)
+		goto out_no_write;
+
+	/* flush msg and acks as we are overwriting the message buffer */
+	txgbe_check_for_msg_pf(hw, vf);
+	txgbe_check_for_ack_pf(hw, vf);
+
+	/* copy the caller specified message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		wr32a(hw, TXGBE_PXMBMEM(vf), i, msg[i]);
+
+	/* Interrupt VF to tell it a message has been sent and release buffer*/
+	/* set mirrored mailbox flags */
+	wr32a(hw, TXGBE_PXMBMEM(vf), TXGBE_VXMAILBOX_SIZE, TXGBE_PXMAILBOX_STS);
+	wr32(hw, TXGBE_PXMAILBOX(vf), TXGBE_PXMAILBOX_STS);
+
+	/* update stats */
+	hw->mbx.stats.msgs_tx++;
+
+out_no_write:
+	return err;
+
+}
+
+/**
+ *  txgbe_read_mbx_pf - Read a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf: the VF index
+ *
+ *  This function copies a message from the mailbox buffer to the caller's
+ *  memory buffer.  The presumption is that the caller knows that there was
+ *  a message due to a VF request so no polling for message is needed.
+ **/
+int txgbe_read_mbx_pf(struct txgbe_hw *hw, u32 *msg, u16 size,
+			     u16 vf)
+{
+	int err;
+	u16 i;
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = txgbe_obtain_mbx_lock_pf(hw, vf);
+	if (err)
+		goto out_no_read;
+
+	/* copy the message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		msg[i] = rd32a(hw, TXGBE_PXMBMEM(vf), i);
+
+	/* Acknowledge the message and release buffer */
+	/* set mirrored mailbox flags */
+	wr32a(hw, TXGBE_PXMBMEM(vf), TXGBE_VXMAILBOX_SIZE, TXGBE_PXMAILBOX_ACK);
+	wr32(hw, TXGBE_PXMAILBOX(vf), TXGBE_PXMAILBOX_ACK);
+
+	/* update stats */
+	hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+	return err;
+}
+
+/**
+ *  txgbe_init_mbx_params_pf - set initial values for pf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for pf mailbox
+ */
+void txgbe_init_mbx_params_pf(struct txgbe_hw *hw)
+{
+	struct txgbe_mbx_info *mbx = &hw->mbx;
+
+	mbx->timeout = 0;
+	mbx->udelay = 0;
+
+	mbx->size = TXGBE_VXMAILBOX_SIZE;
+
+	mbx->ops.read = txgbe_read_mbx_pf;
+	mbx->ops.write = txgbe_write_mbx_pf;
+	mbx->ops.read_posted = txgbe_read_posted_mbx;
+	mbx->ops.write_posted = txgbe_write_posted_mbx;
+	mbx->ops.check_for_msg = txgbe_check_for_msg_pf;
+	mbx->ops.check_for_ack = txgbe_check_for_ack_pf;
+	mbx->ops.check_for_rst = txgbe_check_for_rst_pf;
+
+	mbx->stats.msgs_tx = 0;
+	mbx->stats.msgs_rx = 0;
+	mbx->stats.reqs = 0;
+	mbx->stats.acks = 0;
+	mbx->stats.rsts = 0;
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.h
new file mode 100644
index 000000000000..fd2ad99d3ccb
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_mbx.h
@@ -0,0 +1,172 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_mbx.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#ifndef _TXGBE_MBX_H_
+#define _TXGBE_MBX_H_
+
+#define TXGBE_VXMAILBOX_SIZE    (16 - 1)
+
+/**
+ * VF Registers
+ **/
+#define TXGBE_VXMAILBOX         0x00600
+#define TXGBE_VXMAILBOX_REQ     ((0x1) << 0) /* Request for PF Ready bit */
+#define TXGBE_VXMAILBOX_ACK     ((0x1) << 1) /* Ack PF message received */
+#define TXGBE_VXMAILBOX_VFU     ((0x1) << 2) /* VF owns the mailbox buffer */
+#define TXGBE_VXMAILBOX_PFU     ((0x1) << 3) /* PF owns the mailbox buffer */
+#define TXGBE_VXMAILBOX_PFSTS   ((0x1) << 4) /* PF wrote a message in the MB */
+#define TXGBE_VXMAILBOX_PFACK   ((0x1) << 5) /* PF ack the previous VF msg */
+#define TXGBE_VXMAILBOX_RSTI    ((0x1) << 6) /* PF has reset indication */
+#define TXGBE_VXMAILBOX_RSTD    ((0x1) << 7) /* PF has indicated reset done */
+#define TXGBE_VXMAILBOX_R2C_BITS (TXGBE_VXMAILBOX_RSTD | \
+	    TXGBE_VXMAILBOX_PFSTS | TXGBE_VXMAILBOX_PFACK)
+
+#define TXGBE_VXMBMEM           0x00C00 /* 16*4B */
+
+/**
+ * PF Registers
+ **/
+#define TXGBE_PXMAILBOX(i)      (0x00600 + (4 * (i))) /* i=[0,63] */
+#define TXGBE_PXMAILBOX_STS     ((0x1) << 0) /* Initiate message send to VF */
+#define TXGBE_PXMAILBOX_ACK     ((0x1) << 1) /* Ack message recv'd from VF */
+#define TXGBE_PXMAILBOX_VFU     ((0x1) << 2) /* VF owns the mailbox buffer */
+#define TXGBE_PXMAILBOX_PFU     ((0x1) << 3) /* PF owns the mailbox buffer */
+#define TXGBE_PXMAILBOX_RVFU    ((0x1) << 4) /* Reset VFU - used when VF stuck*/
+
+#define TXGBE_PXMBMEM(i)        (0x5000 + (64 * (i))) /* i=[0,63] */
+
+#define TXGBE_VFLRP(i)          (0x00490 + (4 * (i))) /* i=[0,1] */
+#define TXGBE_VFLRE(i)          (0x004A0 + (4 * (i))) /* i=[0,1] */
+#define TXGBE_VFLREC(i)         (0x004A8 + (4 * (i))) /* i=[0,1] */
+
+/* SR-IOV specific macros */
+#define TXGBE_MBVFICR(i)         (0x00480 + (4 * (i))) /* i=[0,3] */
+#define TXGBE_MBVFICR_INDEX(vf) ((vf) >> 4)
+#define TXGBE_MBVFICR_VFREQ_MASK (0x0000FFFF) /* bits for VF messages */
+#define TXGBE_MBVFICR_VFREQ_VF1  (0x00000001) /* bit for VF 1 message */
+#define TXGBE_MBVFICR_VFACK_MASK (0xFFFF0000) /* bits for VF acks */
+#define TXGBE_MBVFICR_VFACK_VF1  (0x00010000) /* bit for VF 1 ack */
+
+/**
+ * Messages
+ **/
+/* If it's a TXGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is TXGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define TXGBE_VT_MSGTYPE_ACK    0x80000000 /* Messages below or'd with
+					    * this are the ACK */
+#define TXGBE_VT_MSGTYPE_NACK   0x40000000 /* Messages below or'd with
+					    * this are the NACK */
+#define TXGBE_VT_MSGTYPE_CTS    0x20000000 /* Indicates that VF is still
+					    * clear to send requests */
+#define TXGBE_VT_MSGINFO_SHIFT  16
+/* bits 23:16 are used for extra info for certain messages */
+#define TXGBE_VT_MSGINFO_MASK   (0xFF << TXGBE_VT_MSGINFO_SHIFT)
+
+/* definitions to support mailbox API version negotiation */
+
+/*
+ * each element denotes a version of the API; existing numbers may not
+ * change; any additions must go at the end
+ */
+enum txgbe_pfvf_api_rev {
+	txgbe_mbox_api_null,
+	txgbe_mbox_api_10,      /* API version 1.0, linux/freebsd VF driver */
+	txgbe_mbox_api_11,      /* API version 1.1, linux/freebsd VF driver */
+	txgbe_mbox_api_12,      /* API version 1.2, linux/freebsd VF driver */
+	txgbe_mbox_api_13,	/* API version 1.3, linux/freebsd VF driver */
+	txgbe_mbox_api_20,      /* API version 2.0, solaris Phase1 VF driver */
+	txgbe_mbox_api_unknown, /* indicates that API version is not known */
+};
+
+/* mailbox API, legacy requests */
+#define TXGBE_VF_RESET          0x01 /* VF requests reset */
+#define TXGBE_VF_SET_MAC_ADDR   0x02 /* VF requests PF to set MAC addr */
+#define TXGBE_VF_SET_MULTICAST  0x03 /* VF requests PF to set MC addr */
+#define TXGBE_VF_SET_VLAN       0x04 /* VF requests PF to set VLAN */
+
+/* mailbox API, version 1.0 VF requests */
+#define TXGBE_VF_SET_LPE        0x05 /* VF requests PF to set VMOLR.LPE */
+#define TXGBE_VF_SET_MACVLAN    0x06 /* VF requests PF for unicast filter */
+#define TXGBE_VF_API_NEGOTIATE  0x08 /* negotiate API version */
+
+/* mailbox API, version 1.1 VF requests */
+#define TXGBE_VF_GET_QUEUES     0x09 /* get queue configuration */
+
+/* mailbox API, version 1.2 VF requests */
+#define TXGBE_VF_GET_RETA      0x0a    /* VF request for RETA */
+#define TXGBE_VF_GET_RSS_KEY	0x0b    /* get RSS key */
+#define TXGBE_VF_UPDATE_XCAST_MODE	0x0c
+#define TXGBE_VF_GET_LINK_STATE 0x10 /* get vf link state */
+#define TXGBE_VF_BACKUP		0x8001 /* VF requests backup */
+
+/* mode choices for IXGBE_VF_UPDATE_XCAST_MODE */
+enum txgbevf_xcast_modes {
+	TXGBEVF_XCAST_MODE_NONE = 0,
+	TXGBEVF_XCAST_MODE_MULTI,
+	TXGBEVF_XCAST_MODE_ALLMULTI,
+	TXGBEVF_XCAST_MODE_PROMISC,
+};
+
+/* GET_QUEUES return data indices within the mailbox */
+#define TXGBE_VF_TX_QUEUES      1       /* number of Tx queues supported */
+#define TXGBE_VF_RX_QUEUES      2       /* number of Rx queues supported */
+#define TXGBE_VF_TRANS_VLAN     3       /* Indication of port vlan */
+#define TXGBE_VF_DEF_QUEUE      4       /* Default queue offset */
+
+/* length of permanent address message returned from PF */
+#define TXGBE_VF_PERMADDR_MSG_LEN       4
+/* word in permanent address message with the current multicast type */
+#define TXGBE_VF_MC_TYPE_WORD           3
+
+#define TXGBE_PF_CONTROL_MSG            0x0100 /* PF control message */
+
+/* mailbox API, version 2.0 VF requests */
+#define TXGBE_VF_API_NEGOTIATE          0x08 /* negotiate API version */
+#define TXGBE_VF_GET_QUEUES             0x09 /* get queue configuration */
+#define TXGBE_VF_ENABLE_MACADDR         0x0A /* enable MAC address */
+#define TXGBE_VF_DISABLE_MACADDR        0x0B /* disable MAC address */
+#define TXGBE_VF_GET_MACADDRS           0x0C /* get all configured MAC addrs */
+#define TXGBE_VF_SET_MCAST_PROMISC      0x0D /* enable multicast promiscuous */
+#define TXGBE_VF_GET_MTU                0x0E /* get bounds on MTU */
+#define TXGBE_VF_SET_MTU                0x0F /* set a specific MTU */
+
+/* mailbox API, version 2.0 PF requests */
+#define TXGBE_PF_TRANSPARENT_VLAN       0x0101 /* enable transparent vlan */
+
+#define TXGBE_VF_MBX_INIT_TIMEOUT       2000 /* number of retries on mailbox */
+#define TXGBE_VF_MBX_INIT_DELAY         500  /* microseconds between retries */
+
+int txgbe_read_mbx(struct txgbe_hw *, u32 *, u16, u16);
+int txgbe_write_mbx(struct txgbe_hw *, u32 *, u16, u16);
+int txgbe_read_posted_mbx(struct txgbe_hw *, u32 *, u16, u16);
+int txgbe_write_posted_mbx(struct txgbe_hw *, u32 *, u16, u16);
+int txgbe_check_for_msg(struct txgbe_hw *, u16);
+int txgbe_check_for_ack(struct txgbe_hw *, u16);
+int txgbe_check_for_rst(struct txgbe_hw *, u16);
+void txgbe_init_mbx_ops(struct txgbe_hw *hw);
+void txgbe_init_mbx_params_vf(struct txgbe_hw *);
+void txgbe_init_mbx_params_pf(struct txgbe_hw *);
+
+#endif /* _TXGBE_MBX_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.c
new file mode 100644
index 000000000000..5f3ab94660d5
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.c
@@ -0,0 +1,1553 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+
+#include "txgbe_mtd.h"
+#include "kcompat.h"
+
+MTD_STATUS mtdHwXmdioWrite(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 dev,
+	IN MTD_U16 reg,
+	IN MTD_U16 value)
+{
+	MTD_STATUS result = MTD_OK;
+
+
+	if (devPtr->fmtdWriteMdio != NULL) {
+		if (devPtr->fmtdWriteMdio(devPtr, port, dev, reg, value) == MTD_FAIL) {
+			result = MTD_FAIL;
+			MTD_DBG_INFO("fmtdWriteMdio 0x%04X failed to port=%d, dev=%d, reg=0x%04X\n",
+							(unsigned)(value), (unsigned)port, (unsigned)dev, (unsigned)reg);
+		}
+	} else
+		result = MTD_FAIL;
+
+	return result;
+}
+
+MTD_STATUS mtdHwXmdioRead(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 dev,
+	IN MTD_U16 reg,
+	OUT MTD_U16 * data)
+{
+	MTD_STATUS result = MTD_OK;
+
+
+	if (devPtr->fmtdReadMdio != NULL) {
+		if (devPtr->fmtdReadMdio(devPtr, port, dev, reg, data) == MTD_FAIL) {
+			result = MTD_FAIL;
+			MTD_DBG_INFO("fmtdReadMdio failed from port=%d, dev=%d, reg=0x%04X\n",
+						(unsigned)port, (unsigned)dev, (unsigned)reg);
+		}
+	} else
+		result = MTD_FAIL;
+
+	return result;
+}
+
+/*
+	This macro calculates the mask for partial read/write of register's data.
+*/
+#define MTD_CALC_MASK(fieldOffset, fieldLen, mask)	do {\
+			if ((fieldLen + fieldOffset) >= 16)	  \
+				mask = (0 - (1 << fieldOffset));	\
+			else									\
+				mask = (((1 << (fieldLen + fieldOffset))) - (1 << fieldOffset));\
+		} while (0)
+
+MTD_STATUS mtdHwGetPhyRegField(
+	IN  MTD_DEV_PTR devPtr,
+	IN  MTD_U16	 port,
+	IN  MTD_U16	 dev,
+	IN  MTD_U16	 regAddr,
+	IN  MTD_U8	 fieldOffset,
+	IN  MTD_U8	 fieldLength,
+	OUT MTD_U16	 * data)
+{
+	MTD_U16 tmpData;
+	MTD_STATUS   retVal;
+
+	retVal = mtdHwXmdioRead(devPtr, port, dev, regAddr, &tmpData);
+
+	if (retVal != MTD_OK) {
+		MTD_DBG_ERROR("Failed to read register \n");
+		return MTD_FAIL;
+	}
+
+	mtdHwGetRegFieldFromWord(tmpData, fieldOffset, fieldLength, data);
+
+	MTD_DBG_INFO("fOff %d, fLen %d, data 0x%04X.\n", (int)fieldOffset,
+										(int)fieldLength, (int)*data);
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdHwSetPhyRegField(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16	  port,
+	IN MTD_U16	  dev,
+	IN MTD_U16	  regAddr,
+	IN MTD_U8	   fieldOffset,
+	IN MTD_U8	   fieldLength,
+	IN MTD_U16	  data)
+{
+	MTD_U16 tmpData, newData;
+	MTD_STATUS   retVal;
+
+	retVal = mtdHwXmdioRead(devPtr, port, dev, regAddr, &tmpData);
+	if (retVal != MTD_OK) {
+		MTD_DBG_ERROR("Failed to read register \n");
+		return MTD_FAIL;
+	}
+
+	mtdHwSetRegFieldToWord(tmpData, data, fieldOffset, fieldLength, &newData);
+
+	retVal = mtdHwXmdioWrite(devPtr, port, dev, regAddr, newData);
+
+	if (retVal != MTD_OK) {
+		MTD_DBG_ERROR("Failed to write register \n");
+		return MTD_FAIL;
+	}
+
+	MTD_DBG_INFO("fieldOff %d, fieldLen %d, data 0x%x.\n", fieldOffset,
+				  fieldLength, data);
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdHwGetRegFieldFromWord(
+	IN  MTD_U16	  regData,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data)
+{
+	/* Bits mask to be read */
+	MTD_U16 mask;
+
+	MTD_CALC_MASK(fieldOffset, fieldLength, mask);
+
+	*data = (regData & mask) >> fieldOffset;
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdHwSetRegFieldToWord(
+	IN  MTD_U16	  regData,
+	IN  MTD_U16	  bitFieldData,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data)
+{
+	/* Bits mask to be read */
+	MTD_U16 mask;
+
+	MTD_CALC_MASK(fieldOffset, fieldLength, mask);
+
+	/* Set the desired bits to 0. */
+	regData &= ~mask;
+	/* Set the given data into the above reset bits.*/
+	regData |= ((bitFieldData << fieldOffset) & mask);
+
+	*data = regData;
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdWait(IN MTD_UINT x)
+{
+	msleep(x);
+	return MTD_OK;
+}
+
+
+/* internal device registers */
+#define MTD_REG_CCCR9 31, 0xF05E	/* do not enclose in parentheses */
+#define MTD_REG_SCR   31, 0xF0F0	/* do not enclose in parentheses */
+#define MTD_REG_ECSR  31, 0xF0F5	/* do not enclose in parentheses */
+MTD_STATUS mtdCheckDeviceCapabilities(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL * phyHasMacsec,
+	OUT MTD_BOOL * phyHasCopperInterface,
+	OUT MTD_BOOL * isE20X0Device)
+{
+	MTD_U8 major, minor, inc, test;
+	MTD_U16 abilities;
+
+	*phyHasMacsec = MTD_TRUE;
+	*phyHasCopperInterface = MTD_TRUE;
+	*isE20X0Device = MTD_FALSE;
+
+	if (mtdGetFirmwareVersion(devPtr, port, &major, &minor, &inc, &test) == MTD_FAIL) {
+		/* firmware not running will produce this case */
+		major = minor = inc = test = 0;
+	}
+
+	if (major == 0 && minor == 0 && inc == 0 && test == 0) {
+		/* no code loaded into internal processor */
+		/* have to read it from the device itself the hard way */
+		MTD_U16 reg2, reg3; 
+		MTD_U16 index, index2;
+		MTD_U16 temp;
+		MTD_U16 bit16thru23[8];
+
+		/* save these registers */
+		/* ATTEMPT(mtdHwXmdioRead(devPtr,port,MTD_REG_CCCR9,&reg1)); some revs can't read this register reliably */
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_REG_SCR, &reg2));
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_REG_ECSR, &reg3));
+
+		/* clear these bit indications */
+		for (index = 0; index < 8; index++) {
+			bit16thru23[index] = 0;
+		}
+
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_CCCR9, 0x0300)); /* force clock on */
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_SCR, 0x0102)); /* set access */
+		mtdWait(1);
+
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x06D3)); /* sequence needed */
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0593));
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0513));
+		mtdWait(1);
+
+		index = 0;
+		index2 = 0;
+		while (index < 24) {
+			ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0413));
+			mtdWait(1);
+			ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0513));
+			mtdWait(1);
+
+			if (index >= 16) {
+				ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_REG_ECSR, &bit16thru23[index2++]));
+			} else {
+				ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_REG_ECSR, &temp));
+			}
+			mtdWait(1);
+			index++;
+		}
+
+		if (((bit16thru23[0] >> 11) & 1) | ((bit16thru23[1] >> 11) & 1)) {
+			*phyHasMacsec = MTD_FALSE;
+		}
+		if (((bit16thru23[4] >> 11) & 1) | ((bit16thru23[5] >> 11) & 1)) {
+			*phyHasCopperInterface = MTD_FALSE;
+		}
+
+		if (((bit16thru23[6] >> 11) & 1) | ((bit16thru23[7] >> 11) & 1)) {
+			*isE20X0Device = MTD_TRUE;
+		}
+
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0413));
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0493));
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0413));
+		mtdWait(1);
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, 0x0513));
+		mtdWait(1);
+
+		/* restore the registers */
+		/* ATTEMPT(mtdHwXmdioWrite(devPtr,port,MTD_REG_CCCR9,reg1)); Some revs can't read this register reliably */
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_CCCR9, 0x5440)); /* set back to reset value */
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_SCR, reg2));
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_REG_ECSR, reg3));
+
+	} else {
+		/* should just read it from the firmware status register */
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_TUNIT_XG_EXT_STATUS, &abilities));
+		if (abilities & (1 << 12)) {
+			*phyHasMacsec = MTD_FALSE;
+		}
+
+		if (abilities & (1 << 13)) {
+			*phyHasCopperInterface = MTD_FALSE;
+		}
+
+		if (abilities & (1 << 14)) {
+			*isE20X0Device = MTD_TRUE;
+		}
+
+	}
+
+	return MTD_OK;
+}
+
+MTD_STATUS mtdIsPhyReadyAfterReset(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL * phyReady)
+{
+	MTD_U16 val;
+
+	*phyReady = MTD_FALSE;
+
+	ATTEMPT(mtdHwGetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 15, 1, &val));
+
+	if (val) {
+		/* if still in reset return '0' (could be coming up, or disabled by download mode) */
+		*phyReady = MTD_FALSE;
+	} else {
+		/* if Phy is in normal operation */
+		*phyReady = MTD_TRUE;
+	}
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdSoftwareReset(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 timeoutMs)
+{
+	MTD_U16 counter;
+	MTD_BOOL phyReady;
+	/* bit self clears when done */
+	ATTEMPT(mtdHwSetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 15, 1, 1));
+
+	if (timeoutMs) {
+		counter = 0;
+		ATTEMPT(mtdIsPhyReadyAfterReset(devPtr, port, &phyReady));
+		while (phyReady == MTD_FALSE && counter <= timeoutMs) {
+			ATTEMPT(mtdWait(1));
+			ATTEMPT(mtdIsPhyReadyAfterReset(devPtr, port, &phyReady));
+			counter++;
+		}
+
+		if (counter < timeoutMs) {
+			return MTD_OK;
+		} else {
+			/* timed out without becoming ready */
+			return MTD_FAIL;
+		}
+	} else {
+		return MTD_OK;
+	}
+}
+
+MTD_STATUS mtdIsPhyReadyAfterHardwareReset(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *phyReady)
+{
+	MTD_U16 val;
+
+	*phyReady = MTD_FALSE;
+
+	ATTEMPT(mtdHwGetPhyRegField(devPtr, port, MTD_CUNIT_PORT_CTRL, 14, 1, &val));
+
+	if (val) {
+		/* if still in reset return '0' (could be coming up, or disabled by download mode) */
+		*phyReady = MTD_FALSE;
+	} else {
+		/* if Phy is in normal operation */
+		*phyReady = MTD_TRUE;
+	}
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdHardwareReset(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 timeoutMs)
+{
+	MTD_U16 counter;
+	MTD_BOOL phyReady;
+
+	/* bit self clears when done */
+	ATTEMPT(mtdHwSetPhyRegField(devPtr, port, MTD_CUNIT_PORT_CTRL, 14, 1, 1));
+
+	if (timeoutMs) {
+		counter = 0;
+		ATTEMPT(mtdIsPhyReadyAfterHardwareReset(devPtr, port, &phyReady));
+		while (phyReady == MTD_FALSE && counter <= timeoutMs) {
+			ATTEMPT(mtdWait(1));
+			ATTEMPT(mtdIsPhyReadyAfterHardwareReset(devPtr, port, &phyReady));
+			counter++;
+		}
+		if (counter < timeoutMs)
+			return MTD_OK;
+		else
+			return MTD_FAIL; /* timed out without becoming ready */
+	} else {
+		return MTD_OK;
+	}
+}
+
+/****************************************************************************/
+
+/****************************************************************************/
+/*******************************************************************
+   802.3 Clause 28 and Clause 45
+   Autoneg Related Control & Status
+ *******************************************************************/
+/*******************************************************************
+  Enabling speeds for autonegotiation
+  Reading speeds enabled for autonegotation
+  Set/get pause advertisement for autonegotiation
+  Other Autoneg-related Control and Status (restart,disable/enable,
+  force master/slave/auto, checking for autoneg resolution, etc.)
+ *******************************************************************/
+
+#define MTD_7_0010_SPEED_BIT_LENGTH 4
+#define MTD_7_0010_SPEED_BIT_POS	5
+#define MTD_7_8000_SPEED_BIT_LENGTH 2
+#define MTD_7_8000_SPEED_BIT_POS	8
+#define MTD_7_0020_SPEED_BIT_LENGTH 1   /* for 88X32X0 family and 88X33X0 family */
+#define MTD_7_0020_SPEED_BIT_POS	12
+#define MTD_7_0020_SPEED_BIT_LENGTH2 2   /* for 88X33X0 family A0 revision 2.5/5G */
+#define MTD_7_0020_SPEED_BIT_POS2	7
+
+/* Bit defines for speed bits */
+#define MTD_FORCED_SPEEDS_BIT_MASK  (MTD_SPEED_10M_HD_AN_DIS | MTD_SPEED_10M_FD_AN_DIS | \
+									 MTD_SPEED_100M_HD_AN_DIS | MTD_SPEED_100M_FD_AN_DIS)
+#define MTD_LOWER_BITS_MASK			0x000F /* bits in base page */
+#define MTD_GIG_SPEED_POS			4
+#define MTD_XGIG_SPEED_POS			6
+#define MTD_2P5G_SPEED_POS			11
+#define MTD_5G_SPEED_POS			12
+#define MTD_GET_1000BT_BITS(_speedBits) ((_speedBits & (MTD_SPEED_1GIG_HD | MTD_SPEED_1GIG_FD)) \
+										>> MTD_GIG_SPEED_POS) /* 1000BT bits */
+#define MTD_GET_10GBT_BIT(_speedBits) ((_speedBits & MTD_SPEED_10GIG_FD) \
+										>> MTD_XGIG_SPEED_POS) /* 10GBT bit setting */
+#define MTD_GET_2P5GBT_BIT(_speedBits) ((_speedBits & MTD_SPEED_2P5GIG_FD) \
+										>> MTD_2P5G_SPEED_POS) /* 2.5GBT bit setting */
+#define MTD_GET_5GBT_BIT(_speedBits) ((_speedBits & MTD_SPEED_5GIG_FD) \
+										>> MTD_5G_SPEED_POS) /* 5GBT bit setting */
+
+
+MTD_STATUS mtdEnableSpeeds(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 speed_bits,
+	IN MTD_BOOL anRestart)
+{
+	MTD_BOOL speedForced;
+	MTD_U16 dummy;
+	MTD_U16 tempRegValue;
+
+	if (speed_bits & MTD_FORCED_SPEEDS_BIT_MASK) {
+		/* tried to force the speed, this function is for autonegotiation control */
+		return MTD_FAIL;
+	}
+
+	if (MTD_IS_X32X0_BASE(devPtr->deviceId) && ((speed_bits & MTD_SPEED_2P5GIG_FD) ||
+												(speed_bits & MTD_SPEED_5GIG_FD))) {
+		return MTD_FAIL; /* tried to advertise 2.5G/5G on a 88X32X0 chipset */
+	}
+
+	if (MTD_IS_X33X0_BASE(devPtr->deviceId)) {
+		const MTD_U16 chipRev = (devPtr->deviceId & 0xf); /* get the chip revision */
+
+		if (chipRev == 9 || chipRev == 5 || chipRev == 1 || /* Z2 chip revisions */
+			chipRev == 8 || chipRev == 4 || chipRev == 0)   /* Z1 chip revisions */ {
+			/* this is an X33X0 or E20X0 Z2/Z1 device and not supported (not compatible with A0) */
+			return MTD_FAIL;
+		}
+	}
+
+	/* Enable AN and set speed back to power-on default in case previously forced
+	   Only do it if forced, to avoid an extra/unnecessary soft reset */
+	ATTEMPT(mtdGetForcedSpeed(devPtr, port, &speedForced, &dummy));
+	if (speedForced) {
+		ATTEMPT(mtdUndoForcedSpeed(devPtr, port, MTD_FALSE));
+	}
+
+	if (speed_bits == MTD_ADV_NONE) {
+		/* Set all speeds to be disabled
+		 Take care of bits in 7.0010 (advertisement register, 10BT and 100BT bits) */
+		ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x0010,\
+				MTD_7_0010_SPEED_BIT_POS, MTD_7_0010_SPEED_BIT_LENGTH, \
+				0));
+
+		/* Take care of speed bits in 7.8000 (1000BASE-T speed bits) */
+		ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x8000,\
+				MTD_7_8000_SPEED_BIT_POS, MTD_7_8000_SPEED_BIT_LENGTH, \
+				0));
+
+		/* Now take care of bit in 7.0020 (10GBASE-T) */
+		ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x0020,\
+				MTD_7_0020_SPEED_BIT_POS, MTD_7_0020_SPEED_BIT_LENGTH, 0));
+
+		if (MTD_IS_X33X0_BASE(devPtr->deviceId)) {
+			/* Now take care of bits in 7.0020 (2.5G, 5G speed bits) */
+			ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x0020,\
+					MTD_7_0020_SPEED_BIT_POS2, MTD_7_0020_SPEED_BIT_LENGTH2, 0));
+		}
+	} else {
+		/* Take care of bits in 7.0010 (advertisement register, 10BT and 100BT bits) */
+		ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x0010,\
+				MTD_7_0010_SPEED_BIT_POS, MTD_7_0010_SPEED_BIT_LENGTH, \
+				(speed_bits & MTD_LOWER_BITS_MASK)));
+
+		/* Take care of speed bits in 7.8000 (1000BASE-T speed bits) */
+		ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x8000,\
+				MTD_7_8000_SPEED_BIT_POS, MTD_7_8000_SPEED_BIT_LENGTH, \
+				MTD_GET_1000BT_BITS(speed_bits)));
+
+
+		/* Now take care of bits in 7.0020 (10GBASE-T first) */
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, 7, 0x0020, &tempRegValue));
+		ATTEMPT(mtdHwSetRegFieldToWord(tempRegValue, MTD_GET_10GBT_BIT(speed_bits),\
+				MTD_7_0020_SPEED_BIT_POS, MTD_7_0020_SPEED_BIT_LENGTH, \
+				&tempRegValue));
+
+		if (MTD_IS_X33X0_BASE(devPtr->deviceId)) {
+			/* Now take care of 2.5G bit in 7.0020 */
+			ATTEMPT(mtdHwSetRegFieldToWord(tempRegValue, MTD_GET_2P5GBT_BIT(speed_bits),\
+					7, 1, \
+					&tempRegValue));
+
+			/* Now take care of 5G bit in 7.0020 */
+			ATTEMPT(mtdHwSetRegFieldToWord(tempRegValue, MTD_GET_5GBT_BIT(speed_bits),\
+					8, 1, \
+					&tempRegValue));
+		}
+
+		/* Now write result back to 7.0020 */
+		ATTEMPT(mtdHwXmdioWrite(devPtr, port, 7, 0x0020, tempRegValue));
+
+		if (MTD_GET_10GBT_BIT(speed_bits) ||
+			MTD_GET_2P5GBT_BIT(speed_bits) ||
+			MTD_GET_5GBT_BIT(speed_bits)) {
+			/* Set XNP on if any bit that required it was set */
+			ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0, 13, 1, 1));
+		}
+	}
+
+	if (anRestart) {
+		return ((MTD_STATUS)(mtdAutonegEnable(devPtr, port) ||
+							 mtdAutonegRestart(devPtr, port)));
+	}
+
+	return MTD_OK;
+}
+
+MTD_STATUS mtdUndoForcedSpeed(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_BOOL anRestart)
+{
+
+	ATTEMPT(mtdHwSetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 13, 1, 1));
+	ATTEMPT(mtdHwSetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 6, 1, 1));
+
+	/* when speed bits are changed, T unit sw reset is required, wait until phy is ready */
+	ATTEMPT(mtdSoftwareReset(devPtr, port, 1000));
+
+	if (anRestart) {
+		return ((MTD_STATUS)(mtdAutonegEnable(devPtr, port) ||
+							 mtdAutonegRestart(devPtr, port)));
+	}
+
+	return MTD_OK;
+}
+
+
+
+MTD_STATUS mtdGetForcedSpeed(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *speedIsForced,
+	OUT MTD_U16 *forcedSpeed)
+{
+	MTD_U16 val, bit0, bit1, forcedSpeedBits, duplexBit;
+	MTD_BOOL anDisabled;
+
+	*speedIsForced = MTD_FALSE;
+	*forcedSpeed = MTD_ADV_NONE;
+
+	/* check if 7.0.12 is 0 or 1 (disabled or enabled) */
+	ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 7, 0, 12, 1, &val));
+
+	(val) ? (anDisabled = MTD_FALSE) : (anDisabled = MTD_TRUE);
+
+	if (anDisabled) {
+		/* autoneg is disabled, see if it's forced to one of the speeds that work without AN */
+		ATTEMPT(mtdHwGetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 6, 1, &bit0));
+		ATTEMPT(mtdHwGetPhyRegField(devPtr, port, MTD_TUNIT_IEEE_PMA_CTRL1, 13, 1, &bit1));
+
+		/* now read the duplex bit setting */
+		ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 7, 0x8000, 4, 1, &duplexBit));
+
+		forcedSpeedBits = 0;
+		forcedSpeedBits = bit0 | (bit1 << 1);
+
+		if (forcedSpeedBits == 0) {
+			/* it's set to 10BT */
+			if (duplexBit) {
+				*speedIsForced = MTD_TRUE;
+				*forcedSpeed = MTD_SPEED_10M_FD_AN_DIS;
+			} else {
+				*speedIsForced = MTD_TRUE;
+				*forcedSpeed = MTD_SPEED_10M_HD_AN_DIS;
+			}
+		} else if (forcedSpeedBits == 2) {
+			/* it's set to 100BT */
+			if (duplexBit) {
+				*speedIsForced = MTD_TRUE;
+				*forcedSpeed = MTD_SPEED_100M_FD_AN_DIS;
+			} else {
+				*speedIsForced = MTD_TRUE;
+				*forcedSpeed = MTD_SPEED_100M_HD_AN_DIS;
+			}
+		}
+		/* else it's set to 1000BT or 10GBT which require AN to work */
+	}
+
+	return MTD_OK;
+}
+
+MTD_STATUS mtdAutonegRestart(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port)
+{
+	/* set 7.0.9, restart AN */
+	return (mtdHwSetPhyRegField(devPtr, port, 7, 0,
+			 9, 1, 1));
+}
+
+
+MTD_STATUS mtdAutonegEnable(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port)
+{
+	/* set 7.0.12=1, enable AN */
+	return (mtdHwSetPhyRegField(devPtr, port, 7, 0,
+			12, 1, 1));
+}
+
+/******************************************************************************
+ MTD_STATUS mtdAutonegIsSpeedDuplexResolutionDone
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port,
+	 OUT MTD_BOOL *anSpeedResolutionDone
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	anSpeedResolutionDone - one of the following
+		 MTD_TRUE if speed/duplex is resolved
+		 MTD_FALSE if speed/duplex is not resolved
+
+ Returns:
+	MTD_OK or MTD_FAIL, if query was successful or not
+
+ Description:
+	Queries register 3.8008.11 Speed/Duplex resolved to see if autonegotiation
+	is resolved or in progress. See note below. This function is only to be
+	called if autonegotation is enabled and speed is not forced.
+
+	anSpeedResolutionDone being MTD_TRUE, only indicates if AN has determined
+	the speed and duplex bits in 3.8008, which will indicate what registers
+	to read later for AN resolution after AN has completed.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	If autonegotiation is disabled or speed is forced, this function returns
+	MTD_TRUE.
+
+******************************************************************************/
+MTD_STATUS mtdAutonegIsSpeedDuplexResolutionDone(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *anSpeedResolutionDone)
+{
+	MTD_U16 val;
+
+	/* read speed/duplex resolution done bit in 3.8008 bit 11 */
+	if (mtdHwGetPhyRegField(devPtr, port,
+			3, 0x8008, 11, 1, &val) == MTD_FAIL) {
+		*anSpeedResolutionDone = MTD_FALSE;
+		return MTD_FAIL;
+	}
+
+	(val) ? (*anSpeedResolutionDone = MTD_TRUE) : (*anSpeedResolutionDone = MTD_FALSE);
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdGetAutonegSpeedDuplexResolution(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U16 *speedResolution)
+{
+	MTD_U16 val, speed, speed2, duplex;
+	MTD_BOOL resDone;
+
+	*speedResolution = MTD_ADV_NONE;
+
+	/* check if AN is enabled */
+	ATTEMPT(mtdHwGetPhyRegField(devPtr, port, \
+			7, 0, 12, 1, &val));
+
+	if (val) {
+		/* an is enabled, check if speed is resolved */
+		ATTEMPT(mtdAutonegIsSpeedDuplexResolutionDone(devPtr, port, &resDone));
+
+		if (resDone) {
+			ATTEMPT(mtdHwGetPhyRegField(devPtr, port, \
+					3, 0x8008, 14, 2, &speed));
+
+			ATTEMPT(mtdHwGetPhyRegField(devPtr, port, \
+					3, 0x8008, 13, 1, &duplex));
+
+			switch (speed) {
+			case MTD_CU_SPEED_10_MBPS:
+				if (duplex) {
+					*speedResolution = MTD_SPEED_10M_FD;
+				} else {
+					*speedResolution = MTD_SPEED_10M_HD;
+				}
+				break;
+			case MTD_CU_SPEED_100_MBPS:
+				if (duplex) {
+					*speedResolution = MTD_SPEED_100M_FD;
+				} else {
+					*speedResolution = MTD_SPEED_100M_HD;
+				}
+				break;
+			case MTD_CU_SPEED_1000_MBPS:
+				if (duplex) {
+					*speedResolution = MTD_SPEED_1GIG_FD;
+				} else {
+					*speedResolution = MTD_SPEED_1GIG_HD;
+				}
+				break;
+			case MTD_CU_SPEED_10_GBPS: /* also MTD_CU_SPEED_NBT */
+				if (MTD_IS_X32X0_BASE(devPtr->deviceId)) {
+					*speedResolution = MTD_SPEED_10GIG_FD; /* 10G has only full duplex, ignore duplex bit */
+				} else {
+					ATTEMPT(mtdHwGetPhyRegField(devPtr, port, \
+							3, 0x8008, 2, 2, &speed2));
+
+					switch (speed2) {
+					case MTD_CU_SPEED_NBT_10G:
+						*speedResolution = MTD_SPEED_10GIG_FD;
+						break;
+
+					case MTD_CU_SPEED_NBT_5G:
+						*speedResolution = MTD_SPEED_5GIG_FD;
+						break;
+
+					case MTD_CU_SPEED_NBT_2P5G:
+						*speedResolution = MTD_SPEED_2P5GIG_FD;
+						break;
+
+					default:
+						/* this is an error */
+						return MTD_FAIL;
+						break;
+					}
+				}
+				break;
+			default:
+				/* this is an error */
+				return MTD_FAIL;
+				break;
+			}
+
+		}
+
+	}
+
+	return MTD_OK;
+}
+
+
+/****************************************************************************/
+MTD_STATUS mtdIsBaseTUp(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U16 *speed,
+	OUT MTD_BOOL *linkUp)
+{
+	MTD_BOOL speedIsForced;
+	MTD_U16 forcedSpeed, cuSpeed, cuLinkStatus;
+
+	*linkUp = MTD_FALSE;
+	*speed = MTD_ADV_NONE;
+
+	/* first check if speed is forced to one of the speeds not requiring AN to train */
+	ATTEMPT(mtdGetForcedSpeed(devPtr, port, &speedIsForced, &forcedSpeed));
+
+	if (speedIsForced) {
+		/* check if the link is up at the speed it's forced to */
+		ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 3, 0x8008, 14, 2, &cuSpeed));
+		ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 3, 0x8008, 10, 1, &cuLinkStatus));
+
+		switch (forcedSpeed) {
+		case MTD_SPEED_10M_HD_AN_DIS:
+		case MTD_SPEED_10M_FD_AN_DIS:
+		/* might want to add checking the duplex to make sure there
+		 * is no duplex mismatch */
+			if (cuSpeed == MTD_CU_SPEED_10_MBPS) {
+				*speed = forcedSpeed;
+			} else {
+				*speed = MTD_SPEED_MISMATCH;
+			}
+			if (cuLinkStatus) {
+				*linkUp = MTD_TRUE;
+			}
+			break;
+
+		case MTD_SPEED_100M_HD_AN_DIS:
+		case MTD_SPEED_100M_FD_AN_DIS:
+		/* might want to add checking the duplex to make sure there
+		 * is no duplex mismatch */
+			if (cuSpeed == MTD_CU_SPEED_100_MBPS) {
+				*speed = forcedSpeed;
+			} else {
+				*speed = MTD_SPEED_MISMATCH;
+			}
+			if (cuLinkStatus) {
+				*linkUp = MTD_TRUE;
+			}
+			break;
+
+		default:
+			return MTD_FAIL;
+			break;
+		}
+	} else {
+		/* must be going through AN */
+		ATTEMPT(mtdGetAutonegSpeedDuplexResolution(devPtr, port, speed));
+
+		if (*speed != MTD_ADV_NONE) {
+			/* check if the link is up at the speed it's AN to */
+			ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 3, 0x8008, 10, 1, &cuLinkStatus));
+
+			switch (*speed) {
+			case MTD_SPEED_10M_HD:
+			case MTD_SPEED_10M_FD:
+			case MTD_SPEED_100M_HD:
+			case MTD_SPEED_100M_FD:
+			case MTD_SPEED_1GIG_HD:
+			case MTD_SPEED_1GIG_FD:
+			case MTD_SPEED_10GIG_FD:
+			case MTD_SPEED_2P5GIG_FD:
+			case MTD_SPEED_5GIG_FD:
+				if (cuLinkStatus) {
+					*linkUp = MTD_TRUE;
+				}
+				break;
+			default:
+				return MTD_FAIL;
+				break;
+			}
+
+		}
+		/* else link is down, and AN is in progress, */
+	}
+
+	if (*speed == MTD_SPEED_MISMATCH) {
+		return MTD_FAIL;
+	} else {
+		return MTD_OK;
+	}
+
+}
+
+MTD_STATUS mtdSetPauseAdvertisement(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U32 pauseType,
+	IN MTD_BOOL anRestart)
+{
+	/* sets/clears bits 11, 10 (A6,A5 in the tech bit field of 7.16) */
+	ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 7, 0x0010, \
+						10, 2, (MTD_U16)pauseType));
+
+	if (anRestart) {
+		return ((MTD_STATUS)(mtdAutonegEnable(devPtr, port) ||
+							 mtdAutonegRestart(devPtr, port)));
+	}
+
+	return MTD_OK;
+}
+
+
+/******************************************************************************
+ MTD_STATUS mtdAutonegIsCompleted
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port,
+	 OUT MTD_BOOL *anStatusReady
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	anStatusReady - one of the following
+		 MTD_TRUE if AN status registers are available to be read (7.1, 7.33, 7.32769, etc.)
+		 MTD_FALSE if AN is not completed and AN status registers may contain old data
+
+ Returns:
+	MTD_OK or MTD_FAIL, if query was successful or not
+
+ Description:
+	Checks 7.1.5 for 1. If 1, returns MTD_TRUE. If not, returns MTD_FALSE. Many
+	autonegotiation status registers are not valid unless AN has completed
+	meaning 7.1.5 = 1.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	Call this function before reading 7.33 or 7.32769 to check for master/slave
+	resolution or other negotiated parameters which are negotiated during
+	autonegotiation like fast retrain, fast retrain type, etc.
+
+******************************************************************************/
+MTD_STATUS mtdAutonegIsCompleted(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *anStatusReady)
+{
+	MTD_U16 val;
+
+	/* read an completed, 7.1.5 bit */
+	if (mtdHwGetPhyRegField(devPtr, port,
+			7, 1, 5, 1, &val) == MTD_FAIL) {
+		*anStatusReady = MTD_FALSE;
+		return MTD_FAIL;
+	}
+
+	(val) ? (*anStatusReady = MTD_TRUE) : (*anStatusReady = MTD_FALSE);
+
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdGetLPAdvertisedPause(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *pauseBits)
+{
+	MTD_U16 val;
+	MTD_BOOL anStatusReady;
+
+	/* Make sure AN is complete */
+	ATTEMPT(mtdAutonegIsCompleted(devPtr, port, &anStatusReady));
+
+	if (anStatusReady == MTD_FALSE) {
+		*pauseBits = MTD_CLEAR_PAUSE;
+		return MTD_FAIL;
+	}
+
+	/* get bits 11, 10 (A6,A5 in the tech bit field of 7.19) */
+	if (mtdHwGetPhyRegField(devPtr, port, 7, 19,
+		 10, 2, &val) == MTD_FAIL) {
+		*pauseBits = MTD_CLEAR_PAUSE;
+		return MTD_FAIL;
+	}
+
+	*pauseBits = (MTD_U8)val;
+
+	return MTD_OK;
+}
+
+/*******************************************************************
+ Firmware Version
+ *******************************************************************/
+/****************************************************************************/
+MTD_STATUS mtdGetFirmwareVersion(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *major,
+	OUT MTD_U8 *minor,
+	OUT MTD_U8 *inc,
+	OUT MTD_U8 *test)
+{
+	MTD_U16 reg_49169, reg_49170;
+
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, 1, 49169, &reg_49169));
+
+	*major = (reg_49169 & 0xFF00) >> 8;
+	*minor = (reg_49169 & 0x00FF);
+
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, 1, 49170, &reg_49170));
+
+	*inc = (reg_49170 & 0xFF00) >> 8;
+	*test = (reg_49170 & 0x00FF);
+
+	/* firmware is not running if all 0's */
+	if (!(*major || *minor || *inc || *test)) {
+		return MTD_FAIL;
+	}
+	return MTD_OK;
+}
+
+
+MTD_STATUS mtdGetPhyRevision(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_DEVICE_ID * phyRev,
+	OUT MTD_U8 *numPorts,
+	OUT MTD_U8 *thisPort)
+{
+	MTD_U16 temp = 0, tryCounter, temp2, baseType, reportedHwRev;
+	MTD_U16 revision = 0, numports, thisport, readyBit, fwNumports, fwThisport;
+	MTD_BOOL registerExists, regReady, hasMacsec, hasCopper, isE20X0Device;
+	MTD_U8 major, minor, inc, test;
+
+	*phyRev = MTD_REV_UNKNOWN; /* in case we have any failed ATTEMPT below, will return unknown */
+	*numPorts = 0;
+	*thisPort = 0;
+
+	/* first check base type of device, get reported rev and port info */
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, 3, 0xD00D, &temp));
+	baseType = ((temp & 0xFC00) >> 6);
+	reportedHwRev = (temp & 0x000F);
+	numports = ((temp & 0x0380) >> 7) + 1;
+	thisport = ((temp & 0x0070) >> 4);
+
+	/* find out if device has macsec/ptp, copper unit or is an E20X0-type device */
+	ATTEMPT(mtdCheckDeviceCapabilities(devPtr, port, &hasMacsec, &hasCopper, &isE20X0Device));
+
+	/* check if internal processor firmware is up and running, and if so, easier to get info */
+	if (mtdGetFirmwareVersion(devPtr, port, &major, &minor, &inc, &test) == MTD_FAIL) {
+		major = minor = inc = test = 0; /* this is expected if firmware is not loaded/running */
+	}
+
+	if (major == 0 && minor == 0 && inc == 0 && test == 0) {
+		/* no firmware running, have to verify device revision */
+		if (MTD_IS_X32X0_BASE(baseType)) {
+			/* A0 and Z2 report the same revision, need to check which is which */
+			if (reportedHwRev == 1) {
+				/* need to figure out if it's A0 or Z2 */
+				/* remove internal reset */
+				ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 3, 0xD801, 5, 1, 1));
+
+				/* wait until it's ready */
+				regReady = MTD_FALSE;
+				tryCounter = 0;
+				while (regReady == MTD_FALSE && tryCounter++ < 10) {
+					ATTEMPT(mtdWait(1)); /* timeout is set to 10 ms */
+					ATTEMPT(mtdHwGetPhyRegField(devPtr, port, 3, 0xD007, 6, 1, &readyBit));
+					if (readyBit == 1) {
+						regReady = MTD_TRUE;
+					}
+				}
+
+				if (regReady == MTD_FALSE) {
+					/* timed out, can't tell for sure what rev this is */
+					*numPorts = 0;
+					*thisPort = 0;
+					*phyRev = MTD_REV_UNKNOWN;
+					return MTD_FAIL;
+				}
+
+				/* perform test */
+				registerExists = MTD_FALSE;
+				ATTEMPT(mtdHwXmdioRead(devPtr, port, 3, 0x8EC6, &temp));
+				ATTEMPT(mtdHwXmdioWrite(devPtr, port, 3, 0x8EC6, 0xA5A5));
+				ATTEMPT(mtdHwXmdioRead(devPtr, port, 3, 0x8EC6, &temp2));
+
+				/* put back internal reset */
+				ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 3, 0xD801, 5, 1, 0));
+
+				if (temp == 0 && temp2 == 0xA5A5) {
+					registerExists = MTD_TRUE;
+				}
+
+				if (registerExists == MTD_TRUE) {
+					revision = 2; /* this is actually QA0 */
+				} else {
+					revision = reportedHwRev; /* this is a QZ2 */
+				}
+
+			} else {
+				/* it's not A0 or Z2, use what's reported by the hardware */
+				revision = reportedHwRev;
+			}
+		} else if (MTD_IS_X33X0_BASE(baseType)) {
+			/* all 33X0 devices report correct revision */
+			revision = reportedHwRev;
+		}
+
+		/* have to use what's reported by the hardware */
+		*numPorts = (MTD_U8)numports;
+		*thisPort = (MTD_U8)thisport;
+	} else {
+		/* there is firmware loaded/running in internal processor */
+		/* can get device revision reported by firmware */
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_TUNIT_PHY_REV_INFO_REG, &temp));
+		ATTEMPT(mtdHwGetRegFieldFromWord(temp, 0, 4, &revision));
+		ATTEMPT(mtdHwGetRegFieldFromWord(temp, 4, 3, &fwNumports));
+		ATTEMPT(mtdHwGetRegFieldFromWord(temp, 7, 3, &fwThisport));
+		if (fwNumports == numports && fwThisport == thisport) {
+			*numPorts = (MTD_U8)numports;
+			*thisPort = (MTD_U8)thisport;
+		} else {
+			*phyRev = MTD_REV_UNKNOWN;
+			*numPorts = 0;
+			*thisPort = 0;
+			return MTD_FAIL; /* firmware and hardware are reporting different values */
+		}
+	}
+
+	/* now have correct information to build up the MTD_DEVICE_ID */
+	if (MTD_IS_X32X0_BASE(baseType)) {
+		temp =  MTD_X32X0_BASE;
+	} else if (MTD_IS_X33X0_BASE(baseType)) {
+		temp = MTD_X33X0_BASE;
+	} else {
+		*phyRev = MTD_REV_UNKNOWN;
+		*numPorts = 0;
+		*thisPort = 0;
+		return MTD_FAIL;
+	}
+
+	if (hasMacsec) {
+		temp |= MTD_MACSEC_CAPABLE;
+	}
+
+	if (hasCopper) {
+		temp |= MTD_COPPER_CAPABLE;
+	}
+
+	if (MTD_IS_X33X0_BASE(baseType) && isE20X0Device) {
+		temp |= MTD_E20X0_DEVICE;
+	}
+
+	temp |= (revision & 0xF);
+
+	*phyRev = (MTD_DEVICE_ID)temp;
+
+	/* make sure we got a good one */
+	if (mtdIsPhyRevisionValid(*phyRev) == MTD_OK) {
+		return MTD_OK;
+	} else {
+		return MTD_FAIL; /* unknown or unsupported, if recognized but unsupported, value is still valid */
+	}
+}
+
+MTD_STATUS mtdIsPhyRevisionValid(IN MTD_DEVICE_ID phyRev)
+{
+	switch (phyRev) {
+	/* list must match MTD_DEVICE_ID */
+	case MTD_REV_3240P_Z2:
+	case MTD_REV_3240P_A0:
+	case MTD_REV_3240P_A1:
+	case MTD_REV_3220P_Z2:
+	case MTD_REV_3220P_A0:
+
+	case MTD_REV_3240_Z2:
+	case MTD_REV_3240_A0:
+	case MTD_REV_3240_A1:
+	case MTD_REV_3220_Z2:
+	case MTD_REV_3220_A0:
+
+	case MTD_REV_3310P_A0:
+	case MTD_REV_3320P_A0:
+	case MTD_REV_3340P_A0:
+	case MTD_REV_3310_A0:
+	case MTD_REV_3320_A0:
+	case MTD_REV_3340_A0:
+
+	case MTD_REV_E2010P_A0:
+	case MTD_REV_E2020P_A0:
+	case MTD_REV_E2040P_A0:
+	case MTD_REV_E2010_A0:
+	case MTD_REV_E2020_A0:
+	case MTD_REV_E2040_A0:
+
+	case MTD_REV_2340P_A1:
+	case MTD_REV_2320P_A0:
+	case MTD_REV_2340_A1:
+	case MTD_REV_2320_A0:
+		return MTD_OK;
+		break;
+
+	/* unsupported PHYs */
+	case MTD_REV_3310P_Z1:
+	case MTD_REV_3320P_Z1:
+	case MTD_REV_3340P_Z1:
+	case MTD_REV_3310_Z1:
+	case MTD_REV_3320_Z1:
+	case MTD_REV_3340_Z1:
+
+	case MTD_REV_3310P_Z2:
+	case MTD_REV_3320P_Z2:
+	case MTD_REV_3340P_Z2:
+	case MTD_REV_3310_Z2:
+	case MTD_REV_3320_Z2:
+	case MTD_REV_3340_Z2:
+
+
+	case MTD_REV_E2010P_Z2:
+	case MTD_REV_E2020P_Z2:
+	case MTD_REV_E2040P_Z2:
+	case MTD_REV_E2010_Z2:
+	case MTD_REV_E2020_Z2:
+	case MTD_REV_E2040_Z2:
+	default:
+		return MTD_FAIL; /* is either MTD_REV_UNKNOWN or not in the above list */
+		break;
+	}
+}
+
+/* mtdCunit.c */
+MTD_STATUS mtdCunitSwReset(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port)
+{
+	return mtdHwSetPhyRegField(devPtr, port, MTD_CUNIT_PORT_CTRL, 15, 1, 1);
+}
+
+/* mtdHxunit.c */
+MTD_STATUS mtdRerunSerdesAutoInitializationUseAutoMode(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port)
+{
+	MTD_U16 temp, temp2, temp3;
+	MTD_U16 waitCounter;
+
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_SERDES_CTRL_STATUS, &temp));
+
+	ATTEMPT(mtdHwSetRegFieldToWord(temp, 3, 14, 2, &temp2));  /* execute bits and disable bits set */
+
+	ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_SERDES_CTRL_STATUS, temp2));
+
+	/* wait for it to be done */
+	waitCounter = 0;
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_SERDES_CTRL_STATUS, &temp3));
+	while ((temp3 & 0x8000) && (waitCounter < 100)) {
+		ATTEMPT(mtdWait(1));
+		ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_SERDES_CTRL_STATUS, &temp3));
+		waitCounter++;
+	}
+
+	/* if speed changed, let it stay. that's the speed that it ended up changing to/serdes was initialied to */
+	if (waitCounter >= 100) {
+		return MTD_FAIL; /* execute timed out */
+	}
+
+	return MTD_OK;
+}
+
+
+/* mtdHunit.c */
+/******************************************************************************
+ Mac Interface functions
+******************************************************************************/
+
+MTD_STATUS mtdSetMacInterfaceControl(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 macType,
+	IN MTD_BOOL macIfPowerDown,
+	IN MTD_U16 macIfSnoopSel,
+	IN MTD_U16 macIfActiveLaneSelect,
+	IN MTD_U16 macLinkDownSpeed,
+	IN MTD_U16 macMaxIfSpeed, /* 33X0/E20X0 devices only */
+	IN MTD_BOOL doSwReset,
+	IN MTD_BOOL rerunSerdesInitialization)
+{
+	MTD_U16 cunitPortCtrl, cunitModeConfig;
+
+	/* do range checking on parameters */
+	if ((macType > MTD_MAC_LEAVE_UNCHANGED)) {
+		return MTD_FAIL;
+	}
+
+	if ((macIfSnoopSel > MTD_MAC_SNOOP_LEAVE_UNCHANGED) ||
+		(macIfSnoopSel == 1)) {
+		return MTD_FAIL;
+	}
+
+	if (macIfActiveLaneSelect > 1) {
+		return MTD_FAIL;
+	}
+
+	if (macLinkDownSpeed > MTD_MAC_SPEED_LEAVE_UNCHANGED) {
+		return MTD_FAIL;
+	}
+
+	if (!(macMaxIfSpeed == MTD_MAX_MAC_SPEED_10G ||
+			macMaxIfSpeed == MTD_MAX_MAC_SPEED_5G ||
+			macMaxIfSpeed == MTD_MAX_MAC_SPEED_2P5G ||
+			macMaxIfSpeed == MTD_MAX_MAC_SPEED_LEAVE_UNCHANGED ||
+			macMaxIfSpeed == MTD_MAX_MAC_SPEED_NOT_APPLICABLE)) {
+		return MTD_FAIL;
+	}
+
+
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_CUNIT_PORT_CTRL, &cunitPortCtrl));
+	ATTEMPT(mtdHwXmdioRead(devPtr, port, MTD_CUNIT_MODE_CONFIG, &cunitModeConfig));
+
+	/* Because writes of some of these bits don't show up in the register on a read
+	 * until after the software reset, we can't do repeated read-modify-writes
+	 * to the same register or we will lose those changes.
+
+	 * This approach also cuts down on IO and speeds up the code
+	 */
+
+	if (macType < MTD_MAC_LEAVE_UNCHANGED) {
+		ATTEMPT(mtdHwSetRegFieldToWord(cunitPortCtrl, macType, 0, 3, &cunitPortCtrl));
+	}
+
+	ATTEMPT(mtdHwSetRegFieldToWord(cunitModeConfig, (MTD_U16)macIfPowerDown, 3, 1, &cunitModeConfig));
+
+	if (macIfSnoopSel < MTD_MAC_SNOOP_LEAVE_UNCHANGED) {
+		ATTEMPT(mtdHwSetRegFieldToWord(cunitModeConfig, macIfSnoopSel, 8, 2, &cunitModeConfig));
+	}
+
+	ATTEMPT(mtdHwSetRegFieldToWord(cunitModeConfig, macIfActiveLaneSelect, 10, 1, &cunitModeConfig));
+
+	if (macLinkDownSpeed < MTD_MAC_SPEED_LEAVE_UNCHANGED) {
+		ATTEMPT(mtdHwSetRegFieldToWord(cunitModeConfig, macLinkDownSpeed, 6, 2, &cunitModeConfig));
+	}
+
+	/* Now write changed values */
+	ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_CUNIT_PORT_CTRL, cunitPortCtrl));
+	ATTEMPT(mtdHwXmdioWrite(devPtr, port, MTD_CUNIT_MODE_CONFIG, cunitModeConfig));
+
+	if (MTD_IS_X33X0_BASE(devPtr->deviceId)) {
+		if (macMaxIfSpeed != MTD_MAX_MAC_SPEED_LEAVE_UNCHANGED) {
+			ATTEMPT(mtdHwSetPhyRegField(devPtr, port, 31, 0xF0A8, 0, 2, macMaxIfSpeed));
+		}
+	}
+
+	if (doSwReset == MTD_TRUE) {
+		ATTEMPT(mtdCunitSwReset(devPtr, port));
+
+		if (macLinkDownSpeed < MTD_MAC_SPEED_LEAVE_UNCHANGED) {
+			ATTEMPT(mtdCunitSwReset(devPtr, port)); /* need 2x for changes to macLinkDownSpeed */
+		}
+
+		if (rerunSerdesInitialization == MTD_TRUE) {
+			ATTEMPT(mtdRerunSerdesAutoInitializationUseAutoMode(devPtr, port));
+		}
+	}
+
+	return MTD_OK;
+}
+
+
+/*******************************************************************************
+* mtdSemCreate
+*
+* DESCRIPTION:
+*	   Create semaphore.
+*
+* INPUTS:
+*		state - beginning state of the semaphore, either MTD_SEM_EMPTY or MTD_SEM_FULL
+*
+* OUTPUTS:
+*	   None
+*
+* RETURNS:
+*	   MTD_SEM if success. Otherwise, NULL
+*
+* COMMENTS:
+*	   None
+*
+*******************************************************************************/
+MTD_SEM mtdSemCreate(
+	IN MTD_DEV * dev,
+	IN MTD_SEM_BEGIN_STATE state)
+{
+	if (dev->semCreate)
+		return dev->semCreate(state);
+
+	return 1; /* should return any value other than 0 to let it keep going */
+}
+
+/*******************************************************************************
+* mtdSemDelete
+*
+* DESCRIPTION:
+*	   Delete semaphore.
+*
+* INPUTS:
+*	   smid - semaphore Id
+*
+* OUTPUTS:
+*	   None
+*
+* RETURNS:
+*	   MTD_OK   - on success
+*	   MTD_FAIL - on error
+*
+* COMMENTS:
+*	   None
+*
+*******************************************************************************/
+MTD_STATUS mtdSemDelete(
+	IN MTD_DEV * dev,
+	IN MTD_SEM smid)
+{
+	if ((dev->semDelete) && (smid))
+		if (dev->semDelete(smid))
+		  return MTD_FAIL;
+
+	return MTD_OK;
+}
+
+
+
+MTD_STATUS mtdLoadDriver(
+	IN FMTD_READ_MDIO	 readMdio,
+	IN FMTD_WRITE_MDIO	writeMdio,
+	IN MTD_BOOL		   macsecIndirectAccess,
+	IN FMTD_SEM_CREATE	semCreate,
+	IN FMTD_SEM_DELETE	semDelete,
+	IN FMTD_SEM_TAKE	  semTake,
+	IN FMTD_SEM_GIVE	  semGive,
+	IN MTD_U16			anyPort,
+	OUT MTD_DEV		  * dev)
+{
+	MTD_U16 data;
+
+	MTD_DBG_INFO("mtdLoadDriver Called.\n");
+
+	/* Check for parameters validity */
+	if (dev == NULL) {
+		MTD_DBG_ERROR("MTD_DEV pointer is NULL.\n");
+		return MTD_API_ERR_DEV;
+	}
+
+	/* The initialization was already done. */
+	if (dev->devEnabled) {
+		MTD_DBG_ERROR("Device Driver already loaded.\n");
+		return MTD_API_ERR_DEV_ALREADY_EXIST;
+	}
+
+	/* Make sure mtdWait() was implemented */
+	if (mtdWait(1) == MTD_FAIL) {
+		MTD_DBG_ERROR("mtdWait() not implemented.\n");
+		return MTD_FAIL;
+	}
+
+	dev->fmtdReadMdio =  readMdio;
+	dev->fmtdWriteMdio = writeMdio;
+
+	dev->semCreate = semCreate;
+	dev->semDelete = semDelete;
+	dev->semTake   = semTake;
+	dev->semGive   = semGive;
+	dev->macsecIndirectAccess = macsecIndirectAccess;  /* 88X33X0 and later force direct access */
+
+	/* try to read 1.0 */
+	if ((mtdHwXmdioRead(dev, anyPort, 1, 0, &data)) != MTD_OK) {
+		MTD_DBG_ERROR("Reading to reg %x failed.\n", 0);
+		return MTD_API_FAIL_READ_REG;
+	}
+
+	MTD_DBG_INFO("mtdLoadDriver successful.\n");
+
+	/* Initialize the MACsec Register Access semaphore.	*/
+	if ((dev->multiAddrSem = mtdSemCreate(dev, MTD_SEM_FULL)) == 0) {
+		MTD_DBG_ERROR("semCreate Failed.\n");
+		return MTD_API_FAIL_SEM_CREATE;
+	}
+
+	if (dev->msec_ctrl.msec_rev == MTD_MSEC_REV_FPGA) {
+		dev->deviceId = MTD_REV_3310P_Z2; /* verification: change if needed */
+		dev->numPorts = 1; /* verification: change if needed */
+		dev->thisPort = 0;
+	} else {
+		/* After everything else is done, can fill in the device id */
+		if ((mtdGetPhyRevision(dev, anyPort,
+							   &(dev->deviceId),
+							   &(dev->numPorts),
+							   &(dev->thisPort))) != MTD_OK) {
+			MTD_DBG_ERROR("mtdGetPhyRevision Failed.\n");
+			return MTD_FAIL;
+		}
+	}
+
+
+	if (MTD_IS_X33X0_BASE(dev->deviceId)) {
+		dev->macsecIndirectAccess = MTD_FALSE; /* bug was fixed in 88X33X0 and later revisions, go direct */
+	}
+
+	dev->devEnabled = MTD_TRUE;
+
+	MTD_DBG_INFO("mtdLoadDriver successful !!!.\n");
+
+	return MTD_OK;
+}
+
+/*******************************************************************************
+* mtdUnloadDriver
+*
+* DESCRIPTION:
+*	   This function clears MTD_DEV structure.
+*
+* INPUTS:
+*	   None.
+*
+* OUTPUTS:
+*	   None.
+*
+* RETURNS:
+*	   MTD_OK		   - on success
+*	   MTD_FAIL		 - on error
+*
+* COMMENTS:
+*	   1.  This function should be called only after successful execution of
+*		   mtdLoadDriver().
+*
+*******************************************************************************/
+MTD_STATUS mtdUnloadDriver(IN MTD_DEV * dev)
+{
+	MTD_DBG_INFO("mtdUnloadDriver Called.\n");
+
+	/* Delete the MACsec register access semaphore.	*/
+	if (mtdSemDelete(dev, dev->multiAddrSem) != MTD_OK) {
+		MTD_DBG_ERROR("SemDelete Failed.\n");
+		return MTD_API_FAIL_SEM_DELETE;
+	}
+
+	dev->fmtdReadMdio =  NULL;
+	dev->fmtdWriteMdio = NULL;
+
+	dev->semCreate = NULL;
+	dev->semDelete = NULL;
+	dev->semTake   = NULL;
+	dev->semGive   = NULL;
+
+	dev->devEnabled = MTD_FALSE;
+
+	return MTD_OK;
+}
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.h
new file mode 100644
index 000000000000..4c305e574c5d
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_mtd.h
@@ -0,0 +1,1683 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+
+#ifndef _TXGBE_MTD_H_
+#define _TXGBE_MTD_H_
+
+#define C_LINKAGE 1 /* set to 1 if C compile/linkage on C files is desired with C++ */
+
+#if C_LINKAGE
+#if defined __cplusplus
+	extern "C" {
+#endif
+#endif
+
+/* general */
+
+#undef IN
+#define IN
+#undef OUT
+#define OUT
+#undef INOUT
+#define INOUT
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+typedef void	  MTD_VOID;
+typedef char	  MTD_8;
+typedef short	 MTD_16;
+typedef long	  MTD_32;
+typedef long long MTD_64;
+
+typedef unsigned char  MTD_U8;
+typedef unsigned short MTD_U16;
+typedef unsigned long  MTD_U32;
+typedef unsigned int   MTD_UINT;
+typedef int			MTD_INT;
+typedef signed short   MTD_S16;
+
+typedef unsigned long long  MTD_U64;
+
+typedef enum {
+	MTD_FALSE = 0,
+	MTD_TRUE  = 1
+} MTD_BOOL;
+
+#define MTD_CONVERT_BOOL_TO_UINT(boolVar, uintVar)  \
+					{(boolVar) ? (uintVar = 1) : (uintVar = 0); }
+#define MTD_CONVERT_UINT_TO_BOOL(uintVar, boolVar)  \
+					{(uintVar) ? (boolVar = MTD_TRUE) : (boolVar = MTD_FALSE); }
+#define MTD_GET_BOOL_AS_BIT(boolVar) ((boolVar) ? 1 : 0)
+#define MTD_GET_BIT_AS_BOOL(uintVar) ((uintVar) ? MTD_TRUE : MTD_FALSE)
+
+typedef void	 (*MTD_VOIDFUNCPTR) (void); /* ptr to function returning void */
+typedef MTD_U32  (*MTD_INTFUNCPTR)  (void); /* ptr to function returning int  */
+
+typedef MTD_U32 MTD_STATUS;
+
+/* Defines for semaphore support */
+typedef MTD_U32 MTD_SEM;
+
+typedef enum {
+	MTD_SEM_EMPTY,
+	MTD_SEM_FULL
+} MTD_SEM_BEGIN_STATE;
+
+typedef MTD_SEM (*FMTD_SEM_CREATE)(MTD_SEM_BEGIN_STATE state);
+typedef MTD_STATUS (*FMTD_SEM_DELETE)(MTD_SEM semId);
+typedef MTD_STATUS (*FMTD_SEM_TAKE)(MTD_SEM semId, MTD_U32 timOut);
+typedef MTD_STATUS (*FMTD_SEM_GIVE)(MTD_SEM semId);
+
+/* Defines for mtdLoadDriver() mtdUnloadDriver() and all API functions which need MTD_DEV */
+typedef struct _MTD_DEV MTD_DEV;
+typedef MTD_DEV * MTD_DEV_PTR;
+
+typedef MTD_STATUS (*FMTD_READ_MDIO)(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 * value);
+typedef MTD_STATUS (*FMTD_WRITE_MDIO)(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 value);
+
+
+
+
+/* MTD_DEVICE_ID format:  */
+/* Bits 15:13 reserved */
+/* Bit 12: 1-> E20X0 device with max speed of 5G and no fiber interface */
+/* Bit 11: 1-> Macsec Capable (Macsec/PTP module included */
+/* Bit  10: 1-> Copper Capable (T unit interface included) */
+/* Bits 9:4 0x18 -> X32X0 base, 0x1A 0x33X0 base */
+/* Bits 3:0 revision/number of ports indication, see list */
+/* Following defines are for building MTD_DEVICE_ID */
+#define MTD_E20X0_DEVICE (1<<12)   /* whether this is an E20X0 device group */
+#define MTD_MACSEC_CAPABLE (1<<11) /* whether the device has a Macsec/PTP module */
+#define MTD_COPPER_CAPABLE (1<<10) /* whether the device has a copper (T unit) module */
+#define MTD_X32X0_BASE (0x18<<4)   /* whether the device uses X32X0 firmware base */
+#define MTD_X33X0_BASE (0x1A<<4)   /* whether the device uses X33X0 firmware base */
+
+/* Following macros are to test MTD_DEVICE_ID for various features */
+#define MTD_IS_E20X0_DEVICE(mTdrevId) ((MTD_BOOL)(mTdrevId & MTD_E20X0_DEVICE))
+#define MTD_IS_MACSEC_CAPABLE(mTdrevId) ((MTD_BOOL)(mTdrevId & MTD_MACSEC_CAPABLE))
+#define MTD_IS_COPPER_CAPABLE(mTdrevId) ((MTD_BOOL)(mTdrevId & MTD_COPPER_CAPABLE))
+#define MTD_IS_X32X0_BASE(mTdrevId) ((MTD_BOOL)((mTdrevId & (0x3F<<4)) == MTD_X32X0_BASE))
+#define MTD_IS_X33X0_BASE(mTdrevId) ((MTD_BOOL)((mTdrevId & (0x3F<<4)) == MTD_X33X0_BASE))
+
+#define MTD_X33X0BASE_SINGLE_PORTA0 0xA
+#define MTD_X33X0BASE_DUAL_PORTA0   0x6
+#define MTD_X33X0BASE_QUAD_PORTA0   0x2
+
+/* WARNING: If you add/modify this list, you must also modify mtdIsPhyRevisionValid() */
+typedef enum {
+	MTD_REV_UNKNOWN = 0,
+	MTD_REV_3240P_Z2 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x1),
+	MTD_REV_3240P_A0 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x2),
+	MTD_REV_3240P_A1 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x3),
+	MTD_REV_3220P_Z2 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x4),
+	MTD_REV_3220P_A0 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x5),
+	MTD_REV_3240_Z2 = (MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x1),
+	MTD_REV_3240_A0 = (MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x2),
+	MTD_REV_3240_A1 = (MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x3),
+	MTD_REV_3220_Z2 = (MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x4),
+	MTD_REV_3220_A0 = (MTD_COPPER_CAPABLE | MTD_X32X0_BASE | 0x5),
+
+	MTD_REV_3310P_Z1 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x8), /* 88X33X0 Z1 not supported starting with version 1.2 of API */
+	MTD_REV_3320P_Z1 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x4),
+	MTD_REV_3340P_Z1 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x0),
+	MTD_REV_3310_Z1 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x8),
+	MTD_REV_3320_Z1 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x4),
+	MTD_REV_3340_Z1 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x0),
+
+	MTD_REV_3310P_Z2 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x9),  /* 88X33X0 Z2 not supported starting with version 1.2 of API */
+	MTD_REV_3320P_Z2 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x5),
+	MTD_REV_3340P_Z2 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x1),
+	MTD_REV_3310_Z2 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x9),
+	MTD_REV_3320_Z2 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x5),
+	MTD_REV_3340_Z2 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x1),
+
+	MTD_REV_E2010P_Z2 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x9), /* E20X0 Z2 not supported starting with version 1.2 of API */
+	MTD_REV_E2020P_Z2 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x5),
+	MTD_REV_E2040P_Z2 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x1),
+	MTD_REV_E2010_Z2 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x9),
+	MTD_REV_E2020_Z2 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x5),
+	MTD_REV_E2040_Z2 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | 0x1),
+
+
+	MTD_REV_3310P_A0 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_SINGLE_PORTA0),
+	MTD_REV_3320P_A0 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_DUAL_PORTA0),
+	MTD_REV_3340P_A0 = (MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_QUAD_PORTA0),
+	MTD_REV_3310_A0 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_SINGLE_PORTA0),
+	MTD_REV_3320_A0 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_DUAL_PORTA0),
+	MTD_REV_3340_A0 = (MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_QUAD_PORTA0),
+
+	MTD_REV_E2010P_A0 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_SINGLE_PORTA0),
+	MTD_REV_E2020P_A0 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_DUAL_PORTA0),
+	MTD_REV_E2040P_A0 = (MTD_E20X0_DEVICE | MTD_MACSEC_CAPABLE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_QUAD_PORTA0),
+	MTD_REV_E2010_A0 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_SINGLE_PORTA0),
+	MTD_REV_E2020_A0 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_DUAL_PORTA0),
+	MTD_REV_E2040_A0 = (MTD_E20X0_DEVICE | MTD_COPPER_CAPABLE | MTD_X33X0_BASE | MTD_X33X0BASE_QUAD_PORTA0),
+
+	MTD_REV_2340P_A1 = (MTD_MACSEC_CAPABLE | MTD_X32X0_BASE | 0x3),
+	MTD_REV_2320P_A0 = (MTD_MACSEC_CAPABLE | MTD_X32X0_BASE | 0x5),
+	MTD_REV_2340_A1 = (MTD_X32X0_BASE | 0x3),
+	MTD_REV_2320_A0 = (MTD_X32X0_BASE | 0x5)
+} MTD_DEVICE_ID;
+
+typedef enum {
+	MTD_MSEC_REV_Z0A,
+	MTD_MSEC_REV_Y0A,
+	MTD_MSEC_REV_A0B,
+	MTD_MSEC_REV_FPGA,
+	MTD_MSEC_REV_UNKNOWN = -1
+} MTD_MSEC_REV;
+
+/* compatible for USB test */
+typedef struct  _MTD_MSEC_CTRL {
+	MTD_32 dev_num;	  /* indicates the device number (0 if only one) when multiple devices are present on SVB.*/
+	MTD_32 port_num;	 /* Indicates which port (0 to 4) is requesting CPU */
+	MTD_U16 prev_addr;   /* < Prev write address */
+	MTD_U16 prev_dataL;  /* < Prev dataL value */
+	MTD_MSEC_REV msec_rev;  /* revision */
+} MTD_MSEC_CTRL;
+
+struct _MTD_DEV {
+	MTD_DEVICE_ID   deviceId;	  /* type of device and capabilities */
+	MTD_BOOL		devEnabled;	/* whether mtdLoadDriver() called successfully */
+	MTD_U8		  numPorts;	  /* number of ports per device */
+	MTD_U8		  thisPort;	  /* relative port number on this device starting with 0 (not MDIO address) */
+	MTD_SEM		 multiAddrSem;
+
+	FMTD_READ_MDIO  fmtdReadMdio;
+	FMTD_WRITE_MDIO fmtdWriteMdio;
+
+	FMTD_SEM_CREATE semCreate;  /* create semapore */
+	FMTD_SEM_DELETE semDelete;  /* delete the semapore */
+	FMTD_SEM_TAKE   semTake;	/* try to get a semapore */
+	FMTD_SEM_GIVE   semGive;	/* return semaphore */
+
+	MTD_U8		  macsecIndirectAccess; /* if MTD_TRUE use internal processor to access Macsec */
+	MTD_MSEC_CTRL   msec_ctrl;  /* structure use for internal verification */
+
+	void *appData; /* application specific data, anything the host wants to pass to the low layer */
+};
+
+
+
+
+#define MTD_OK			0	/* Operation succeeded */
+#define MTD_FAIL		1	/* Operation failed	*/
+#define MTD_PENDING		2	/* Pending  */
+
+
+
+/* bit definition */
+#define MTD_BIT_0	   0x0001
+#define MTD_BIT_1	   0x0002
+#define MTD_BIT_2	   0x0004
+#define MTD_BIT_3	   0x0008
+#define MTD_BIT_4	   0x0010
+#define MTD_BIT_5	   0x0020
+#define MTD_BIT_6	   0x0040
+#define MTD_BIT_7	   0x0080
+#define MTD_BIT_8	   0x0100
+#define MTD_BIT_9	   0x0200
+#define MTD_BIT_10	  0x0400
+#define MTD_BIT_11	  0x0800
+#define MTD_BIT_12	  0x1000
+#define MTD_BIT_13	  0x2000
+#define MTD_BIT_14	  0x4000
+#define MTD_BIT_15	  0x8000
+
+
+
+
+
+#define MTD_DBG_ERROR(...)
+#define MTD_DBG_INFO(...)
+#define MTD_DBG_CRITIC_INFO(...)
+
+
+#define MTD_API_MAJOR_VERSION 2
+#define MTD_API_MINOR_VERSION 0
+
+/* This macro is handy for calling a function when you want to test the
+   return value and return MTD_FAIL, if the function returned MTD_FAIL,
+   otherwise continue */
+#define ATTEMPT(xFuncToTry) do { if (xFuncToTry == MTD_FAIL) {return MTD_FAIL; }} while (0)
+
+/* These defines are used for some registers which represent the copper
+   speed as a 2-bit binary number */
+#define MTD_CU_SPEED_10_MBPS	0 /* copper is 10BASE-T */
+#define MTD_CU_SPEED_100_MBPS   1 /* copper is 100BASE-TX */
+#define MTD_CU_SPEED_1000_MBPS  2 /* copper is 1000BASE-T */
+#define MTD_CU_SPEED_10_GBPS	3 /* copper is 10GBASE-T */
+
+/* for 88X33X0 family: */
+#define MTD_CU_SPEED_NBT		3 /* copper is NBASE-T */
+#define MTD_CU_SPEED_NBT_10G	0 /* copper is 10GBASE-T */
+#define MTD_CU_SPEED_NBT_5G	 2 /* copper is 5GBASE-T */
+#define MTD_CU_SPEED_NBT_2P5G   1 /* copper is 2.5GBASE-T */
+
+#define MTD_ADV_NONE		   0x0000 /* No speeds to be advertised */
+#define MTD_SPEED_10M_HD	   0x0001 /* 10BT half-duplex */
+#define MTD_SPEED_10M_FD	   0x0002 /* 10BT full-duplex */
+#define MTD_SPEED_100M_HD	   0x0004 /* 100BASE-TX half-duplex */
+#define MTD_SPEED_100M_FD	   0x0008 /* 100BASE-TX full-duplex */
+#define MTD_SPEED_1GIG_HD	   0x0010 /* 1000BASE-T half-duplex */
+#define MTD_SPEED_1GIG_FD	   0x0020 /* 1000BASE-T full-duplex */
+#define MTD_SPEED_10GIG_FD	   0x0040 /* 10GBASE-T full-duplex */
+#define MTD_SPEED_2P5GIG_FD	   0x0800 /* 2.5GBASE-T full-duplex, 88X33X0/88E20X0 family only */
+#define MTD_SPEED_5GIG_FD	   0x1000 /* 5GBASE-T full-duplex, 88X33X0/88E20X0 family only */
+#define MTD_SPEED_ALL		   (MTD_SPEED_10M_HD | \
+								MTD_SPEED_10M_FD | \
+								MTD_SPEED_100M_HD | \
+								MTD_SPEED_100M_FD | \
+								MTD_SPEED_1GIG_HD | \
+								MTD_SPEED_1GIG_FD | \
+								MTD_SPEED_10GIG_FD)
+#define MTD_SPEED_ALL_33X0	   (MTD_SPEED_10M_HD | \
+								MTD_SPEED_10M_FD | \
+								MTD_SPEED_100M_HD | \
+								MTD_SPEED_100M_FD | \
+								MTD_SPEED_1GIG_HD | \
+								MTD_SPEED_1GIG_FD | \
+								MTD_SPEED_10GIG_FD | \
+								MTD_SPEED_2P5GIG_FD |\
+								MTD_SPEED_5GIG_FD)
+
+/* these bits are for forcing the speed and disabling autonegotiation */
+#define MTD_SPEED_10M_HD_AN_DIS  0x0080 /* Speed forced to 10BT half-duplex */
+#define MTD_SPEED_10M_FD_AN_DIS  0x0100 /* Speed forced to 10BT full-duplex */
+#define MTD_SPEED_100M_HD_AN_DIS 0x0200 /* Speed forced to 100BT half-duplex */
+#define MTD_SPEED_100M_FD_AN_DIS 0x0400 /* Speed forced to 100BT full-duplex */
+
+/* this value is returned for the speed when the link status is checked and the speed has been */
+/* forced to one speed but the link is up at a different speed. it indicates an error. */
+#define MTD_SPEED_MISMATCH	   0x8000 /* Speed is forced to one speed, but status indicates another */
+
+
+/* for macType */
+#define MTD_MAC_TYPE_RXAUI_SGMII_AN_EN  (0x0) /* X32X0/X33x0, but not E20x0 */
+#define MTD_MAC_TYPE_RXAUI_SGMII_AN_DIS (0x1) /* X32x0/X3340/X3320, but not X3310/E20x0 */
+#define MTD_MAC_TYPE_XAUI_RATE_ADAPT	(0x1) /* X3310,E2010 only */
+#define MTD_MAC_TYPE_RXAUI_RATE_ADAPT   (0x2)
+#define MTD_MAC_TYPE_XAUI			   (0x3) /* X3310,E2010 only */
+#define MTD_MAC_TYPE_XFI_SGMII_AN_EN	(0x4) /* XFI at 10G, X33x0/E20x0 also use 5GBASE-R/2500BASE-X */
+#define MTD_MAC_TYPE_XFI_SGMII_AN_DIS   (0x5) /* XFI at 10G, X33x0/E20x0 also use 5GBASE-R/2500BASE-X */
+#define MTD_MAC_TYPE_XFI_RATE_ADAPT	 (0x6)
+#define MTD_MAC_TYPE_USXGMII			(0x7) /* X33x0 only */
+#define MTD_MAC_LEAVE_UNCHANGED		 (0x8) /* use this option to not touch these bits */
+
+/* for macIfSnoopSel */
+#define MTD_MAC_SNOOP_FROM_NETWORK	  (0x2)
+#define MTD_MAC_SNOOP_FROM_HOST		 (0x3)
+#define MTD_MAC_SNOOP_OFF			   (0x0)
+#define MTD_MAC_SNOOP_LEAVE_UNCHANGED   (0x4) /* use this option to not touch these bits */
+/* for macLinkDownSpeed */
+#define MTD_MAC_SPEED_10_MBPS			MTD_CU_SPEED_10_MBPS
+#define MTD_MAC_SPEED_100_MBPS		   MTD_CU_SPEED_100_MBPS
+#define MTD_MAC_SPEED_1000_MBPS		  MTD_CU_SPEED_1000_MBPS
+#define MTD_MAC_SPEED_10_GBPS			MTD_CU_SPEED_10_GBPS
+#define MTD_MAC_SPEED_LEAVE_UNCHANGED	(0x4)
+/* X33X0/E20X0 devices only for macMaxIfSpeed */
+#define MTD_MAX_MAC_SPEED_10G  (0)
+#define MTD_MAX_MAC_SPEED_5G   (2)
+#define MTD_MAX_MAC_SPEED_2P5G (3)
+#define MTD_MAX_MAC_SPEED_LEAVE_UNCHANGED (4)
+#define MTD_MAX_MAC_SPEED_NOT_APPLICABLE  (4) /* 32X0 devices can pass this */
+
+/* 88X3240/3220 Device Number Definitions */
+#define MTD_T_UNIT_PMA_PMD  1
+#define MTD_T_UNIT_PCS_CU   3
+#define MTD_X_UNIT		  3
+#define MTD_H_UNIT		  4
+#define MTD_T_UNIT_AN	   7
+#define MTD_XFI_DSP		 30
+#define MTD_C_UNIT_GENERAL  31
+#define MTD_M_UNIT		  31
+
+/* 88X3240/3220 Device Number Definitions Host Redundant Mode */
+#define MTD_BASER_LANE_0  MTD_H_UNIT
+#define MTD_BASER_LANE_1  MTD_X_UNIT
+
+/* 88X3240/3220 T Unit Registers MMD 1 */
+#define MTD_TUNIT_IEEE_PMA_CTRL1	   MTD_T_UNIT_PMA_PMD, 0x0000 /* do not enclose in parentheses */
+#define MTD_TUNIT_IEEE_PMA_DEVID2	  MTD_T_UNIT_PMA_PMD, 0x0003 /* do not enclose in parentheses */
+#define MTD_TUNIT_PHY_EXT_CTRL_1	   MTD_T_UNIT_PMA_PMD, 0xC000 /* do not enclose in parentheses */
+#define MTD_TUNIT_XG_EXT_STATUS		MTD_T_UNIT_PMA_PMD, 0xC001 /* do not enclose in parentheses */
+#define MTD_TUNIT_BIST_STATUS_REG	  MTD_T_UNIT_PMA_PMD, 0xC00C /* do not enclose in parentheses */
+#define MTD_TUNIT_PHY_REV_INFO_REG	 MTD_T_UNIT_PMA_PMD, 0xC04E /* do not enclose in parentheses */
+#define MTD_BOOT_STATUS_REG			MTD_T_UNIT_PMA_PMD, 0xC050 /* do not enclose in parentheses */
+
+#define MTD_TUNIT_IEEE_PCS_CTRL1	   MTD_T_UNIT_PCS_CU, 0x0000 /* do not enclose in parentheses */
+/* control/status for serdes initialization */
+#define MTD_SERDES_CTRL_STATUS MTD_T_UNIT_AN, 0x800F /* do not enclose in parentheses */
+/* 88X3240/3220 C Unit Registers MMD 31 */
+#define MTD_CUNIT_MODE_CONFIG		  MTD_C_UNIT_GENERAL, 0xF000 /* do not enclose in parentheses */
+#define MTD_CUNIT_PORT_CTRL			MTD_C_UNIT_GENERAL, 0xF001 /* do not enclose in parentheses */
+
+#define MTD_API_FAIL_SEM_CREATE			(0x18<<24) /*semCreate Failed. */
+#define MTD_API_FAIL_SEM_DELETE			(0x19<<24) /*semDelete Failed. */
+#define MTD_API_FAIL_READ_REG			(0x16<<16) /*Reading from phy reg failed. */
+#define MTD_API_ERR_DEV					(0x3c<<16) /*driver struture is NULL. */
+#define MTD_API_ERR_DEV_ALREADY_EXIST	(0x3e<<16) /*Device Driver already loaded. */
+
+
+#define MTD_CLEAR_PAUSE	 0 /*  clears both pause bits */
+#define MTD_SYM_PAUSE	   1 /*  for symmetric pause only */
+#define MTD_ASYM_PAUSE	  2 /*  for asymmetric pause only */
+#define MTD_SYM_ASYM_PAUSE  3 /*  for both */
+
+
+/*******************************************************************************
+  mtdLoadDriver
+
+  DESCRIPTION:
+		Marvell X32X0  Driver Initialization Routine.
+		This is the first routine that needs be called by system software.
+		It takes parameters from system software, and retures a pointer (*dev)
+		to a data structure which includes infomation related to this Marvell Phy
+		device. This pointer (*dev) is then used for all the API functions.
+		The following is the job performed by this routine:
+			1. store MDIO read/write function into the given MTD_DEV structure
+			2. run any device specific initialization routine
+			3. create semaphore if required
+			4. Initialize the deviceId
+
+
+  INPUTS:
+	readMdio - pointer to host's function to do MDIO read
+	writeMdio - point to host's function to do MDIO write
+	macsecIndirectAccess - MTD_TRUE to access MacSec through T-unit processor
+						   MTD_FALSE to do direct register access
+	semCreate - pointer to host's function to create a semaphore, NULL
+				if not used
+	semDelete - pointer to host's function to create a semaphore, NULL
+				if not used
+	semTake - pointer to host's function to take a semaphore, NULL
+			  if not used
+	semGive - pointer to host's function to give a semaphore, NULL
+			  if not used
+	anyPort - port address of any port for this device
+
+  OUTPUTS:
+		dev  - pointer to holds device information to be used for each API call.
+
+  RETURNS:
+		MTD_OK			   - on success
+		MTD_FAIL			 - on error
+
+  COMMENTS:
+		mtdUnloadDriver is also provided to do driver cleanup.
+
+		An MTD_DEV is required for each type of X32X0 device in the system. For
+		example, if there are 16 ports of X3240 and 4 ports of X3220,
+		two MTD_DEV are required, and one call to mtdLoadDriver() must
+		be made with one of the X3240 ports, and one with one of the X3220
+		ports.
+*******************************************************************************/
+MTD_STATUS mtdLoadDriver
+(
+	IN FMTD_READ_MDIO	 readMdio,
+	IN FMTD_WRITE_MDIO	writeMdio,
+	IN MTD_BOOL		   macsecIndirectAccess,
+	IN FMTD_SEM_CREATE	semCreate,
+	IN FMTD_SEM_DELETE	semDelete,
+	IN FMTD_SEM_TAKE	  semTake,
+	IN FMTD_SEM_GIVE	  semGive,
+	IN MTD_U16			anyPort,
+	OUT MTD_DEV		  * dev
+);
+
+/*******************************************************************************
+* mtdUnloadDriver
+*
+* DESCRIPTION:
+*	   This function frees semaphore created by Marvell X2*** Driver,
+*	   disables Device interrupt, and clears MTD_DEV structure.
+*
+* INPUTS:
+*	   None.
+*
+* OUTPUTS:
+*	   None.
+*
+* RETURNS:
+*	   MTD_OK		   - on success
+*	   MTD_FAIL		 - on error
+*
+* COMMENTS:
+*	   1.  This function should be called only after successful execution of
+*		   mtdLoadDriver().
+*
+*******************************************************************************/
+MTD_STATUS mtdUnloadDriver
+(
+	IN MTD_DEV * dev
+);
+
+/******************************************************************************
+MTD_STATUS mtdHwXmdioWrite
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 dev,
+	IN MTD_U16 reg,
+	IN MTD_U16 value
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	dev - MMD device address, 0-31
+	reg - MMD register address
+	value - data to write
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK - wrote successfully
+	MTD_FAIL - an error occurred
+
+ Description:
+	Writes a 16-bit word to the MDIO
+	Address is in format X.Y.Z, where X selects the MDIO port (0-31), Y selects
+	the MMD/Device (0-31), and Z selects the register.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	None
+
+******************************************************************************/
+MTD_STATUS mtdHwXmdioWrite
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 dev,
+	IN MTD_U16 reg,
+	IN MTD_U16 value
+);
+
+/******************************************************************************
+ MTD_STATUS mtdHwXmdioRead
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port,
+	 IN MTD_U16 dev,
+	 IN MTD_U16 reg,
+	 OUT MTD_U16 *data
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	dev - MMD device address, 0-31
+	reg - MMD register address
+
+ Outputs:
+	data - Returns 16 bit word from the MDIO
+
+ Returns:
+	MTD_OK - read successful
+	MTD_FAIL - read was unsuccessful
+
+ Description:
+	Reads a 16-bit word from the MDIO
+	Address is in format X.Y.Z, where X selects the MDIO port (0-31), Y selects the
+	MMD/Device (0-31), and Z selects the register.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	None
+
+******************************************************************************/
+MTD_STATUS mtdHwXmdioRead
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 dev,
+	IN MTD_U16 reg,
+	OUT MTD_U16 *data
+);
+
+
+/*******************************************************************************
+  MTD_STATUS mtdHwGetPhyRegField
+  (
+	  IN  MTD_DEV_PTR devPtr,
+	  IN  MTD_U16	  port,
+	  IN  MTD_U16	  dev,
+	  IN  MTD_U16	  regAddr,
+	  IN  MTD_U8	   fieldOffset,
+	  IN  MTD_U8	   fieldLength,
+	  OUT MTD_U16	  *data
+  );
+
+  Inputs:
+		devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+		port	   - The port number, 0-31
+		dev		- The MMD device, 0-31
+		regAddr	- The register's address
+		fieldOffset - The field start bit index. (0 - 15)
+		fieldLength - Number of bits to read
+
+  Outputs:
+		data		- The read register field
+
+  Returns:
+		MTD_OK on success, or
+		MTD_FAIL  - on error
+
+  Description:
+		This function reads a specified field from a port's phy register.
+		It first reads the register, then returns the specified bit
+		field from what was read.
+
+  Side effects:
+	 None
+
+  Notes/Warnings:
+		The sum of fieldOffset & fieldLength parameters must be smaller-
+		equal to 16
+
+		Reading a register with latched bits may clear the latched bits.
+		Use with caution for registers with latched bits.
+
+		To operate on several bits within a register which has latched bits
+		before reading the register again, first read the register with
+		mtdHwXmdioRead() to get the register value, then operate on the
+		register data repeatedly using mtdHwGetRegFieldFromWord() to
+		take apart the bit fields without re-reading the register again.
+
+		This approach should also be used to reduce IO to the PHY when reading
+		multiple bit fields (do a single read, then grab different fields
+		from the register by using mtdHwGetRegFieldFromWord() repeatedly).
+
+*******************************************************************************/
+MTD_STATUS mtdHwGetPhyRegField
+(
+	IN  MTD_DEV_PTR devPtr,
+	IN  MTD_U16	  port,
+	IN  MTD_U16	  dev,
+	IN  MTD_U16	  regAddr,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data
+);
+
+/*******************************************************************************
+  MTD_STATUS mtdHwSetPhyRegField
+  (
+	  IN MTD_DEV_PTR devPtr,
+	  IN MTD_U16	  port,
+	  IN MTD_U16	  dev,
+	  IN MTD_U16	  regAddr,
+	  IN MTD_U8	   fieldOffset,
+	  IN MTD_U8	   fieldLength,
+	  IN MTD_U16	  data
+  );
+
+  Inputs:
+		devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+		port	   - The port number, 0-31
+		dev		- The MMD device, 0-31
+		regAddr	-  The register's address
+		fieldOffset - The field start bit index. (0 - 15)
+		fieldLength - Number of bits to write
+		data		- Data to be written.
+
+  Outputs:
+		None.
+
+  Returns:
+		MTD_OK on success, or
+		MTD_FAIL  - on error
+
+  Description:
+		This function writes to specified field in a port's phy register.
+
+  Side effects:
+	 None
+
+  Notes/Warnings:
+		The sum of fieldOffset & fieldLength parameters must be smaller-
+		equal to 16.
+
+*******************************************************************************/
+MTD_STATUS mtdHwSetPhyRegField
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16	  port,
+	IN MTD_U16	  dev,
+	IN MTD_U16	  regAddr,
+	IN MTD_U8	   fieldOffset,
+	IN MTD_U8	   fieldLength,
+	IN MTD_U16	  data
+);
+
+/*******************************************************************************
+  MTD_STATUS mtdHwGetRegFieldFromWord
+  (
+	  IN  MTD_U16	  regData,
+	  IN  MTD_U8	   fieldOffset,
+	  IN  MTD_U8	   fieldLength,
+	  OUT MTD_U16	  *data
+  );
+
+  Inputs:
+		regData	- The data previously read from the register
+		fieldOffset - The field start bit index. (0 - 15)
+		fieldLength - Number of bits to read
+
+  Outputs:
+		data		- The data from the associated bit field
+
+  Returns:
+		MTD_OK always
+
+  Description:
+		This function grabs a value from a bitfield within a word. It could
+		be used to get the value of a bitfield within a word which was previously
+		read from the PHY.
+
+  Side effects:
+	 None
+
+  Notes/Warnings:
+		The sum of fieldOffset & fieldLength parameters must be smaller-
+		equal to 16
+
+		This register acts on data passed in. It does no hardware access.
+
+		This function is useful if you want to do 1 register access and then
+		get different bit fields without doing another register access either
+		because there are latched bits in the register to avoid another read,
+		or to keep hardware IO down to improve performance/throughput.
+
+		Example:
+
+		MTD_U16 aword, nibble1, nibble2;
+
+		mtdHwXmdioRead(devPtr,0,MTD_TUNIT_IEEE_PCS_CTRL1,&aword); // Read 3.0 from port 0
+		mtdHwGetRegFieldFromWord(aword,0,4,&nibble1); // grab first nibble
+		mtdHwGetRegFieldFromWord(aword,4,4,&nibble2); // grab second nibble
+
+*******************************************************************************/
+MTD_STATUS mtdHwGetRegFieldFromWord
+(
+	IN  MTD_U16	  regData,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data
+);
+
+/*******************************************************************************
+  MTD_STATUS mtdHwSetRegFieldToWord
+  (
+	  IN  MTD_U16	  regData,
+	  IN  MTD_U16	  bitFieldData,
+	  IN  MTD_U8	   fieldOffset,
+	  IN  MTD_U8	   fieldLength,
+	  OUT MTD_U16	  *data
+  );
+
+  Inputs:
+		regData - original word to modify
+		bitFieldData   - The data to set the register field to
+					 (must be <= largest value for that bit field,
+					  no range checking is done by this function)
+		fieldOffset - The field start bit index. (0 - 15)
+		fieldLength - Number of bits to write to regData
+
+  Outputs:
+		This function grabs a value from a bitfield within a word. It could
+		be used to get the value of a bitfield within a word which was previously
+		read from the PHY.
+
+  Side effects:
+	 None
+
+  Notes/Warnings:
+		The sum of fieldOffset & fieldLength parameters must be smaller-
+		equal to 16
+
+		This register acts on data passed in. It does no hardware access.
+
+		This function is useful if you want to do 1 register access and then
+		get different bit fields without doing another register access either
+		because there are latched bits in the register to avoid another read,
+		or to keep hardware IO down to improve performance/throughput.
+
+		Example:
+
+		MTD_U16 aword, nibble1, nibble2;
+
+		mtdHwXmdioRead(devPtr,0,MTD_TUNIT_IEEE_PCS_CTRL1,&aword); // Read 3.0 from port 0
+		mtdHwGetRegFieldFromWord(aword,0,4,&nibble1); // grab first nibble
+		mtdHwGetRegFieldFromWord(aword,4,4,&nibble2); // grab second nibble
+
+*******************************************************************************/
+MTD_STATUS mtdHwGetRegFieldFromWord
+(
+	IN  MTD_U16	  regData,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data
+);
+
+/*******************************************************************************
+  MTD_STATUS mtdHwSetRegFieldToWord
+  (
+	  IN  MTD_U16	  regData,
+	  IN  MTD_U16	  bitFieldData,
+	  IN  MTD_U8	   fieldOffset,
+	  IN  MTD_U8	   fieldLength,
+	  OUT MTD_U16	  *data
+  );
+
+  Inputs:
+		regData - original word to modify
+		bitFieldData   - The data to set the register field to
+					 (must be <= largest value for that bit field,
+					  no range checking is done by this function)
+		fieldOffset - The field start bit index. (0 - 15)
+		fieldLength - Number of bits to write to regData
+
+  Outputs:
+		data		- The new/modified regData with the bitfield changed
+
+  Returns:
+		MTD_OK always
+
+  Description:
+		This function write a value to a bitfield within a word.
+
+  Side effects:
+	 None
+
+  Notes/Warnings:
+		The sum of fieldOffset & fieldLength parameters must be smaller-
+		equal to 16
+
+		This register acts on data passed in. It does no hardware access.
+
+		This function is useful to reduce IO if several bit fields of a register
+		that has been read is to be changed before writing it back.
+
+		MTD_U16 aword;
+
+		mtdHwXmdioRead(devPtr,0,MTD_TUNIT_IEEE_PCS_CTRL1,&aword); // Read 3.0 from port 0
+		mtdHwSetRegFieldToWord(aword,2,0,4,&aword); // Change first nibble to 2
+		mtdHwSetRegFieldToWord(aword,3,4,4,&aword); // Change second nibble to 3
+
+*******************************************************************************/
+MTD_STATUS mtdHwSetRegFieldToWord
+(
+	IN  MTD_U16	  regData,
+	IN  MTD_U16	  bitFieldData,
+	IN  MTD_U8	   fieldOffset,
+	IN  MTD_U8	   fieldLength,
+	OUT MTD_U16	  *data
+);
+
+
+/******************************************************************************
+MTD_STATUS mtdWait
+(
+	IN MTD_DEV_PTR devPtr,
+	IN unsigned x
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	x - number of milliseconds to wait
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK if wait was successful, MTD_FAIL otherwise
+
+ Description:
+	Waits X milliseconds
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	None
+
+******************************************************************************/
+MTD_STATUS mtdWait
+(
+	IN MTD_UINT x
+);
+
+/******************************************************************************
+MTD_STATUS mtdSoftwareReset
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 timeoutMs
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	timeoutMs - 0 will not wait for reset to complete, otherwise
+				waits 'timeout' milliseconds for reset to complete
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK or MTD_FAIL if IO error or timed out
+
+ Description:
+	Issues a software reset (1.0.15 <= 1) command. Resets firmware and
+	hardware state machines and returns non-retain bits to their hardware
+	reset values and retain bits keep their values through the reset.
+
+	If timeoutMs is 0, returns immediately. If timeoutMs is non-zero,
+	waits up to 'timeoutMs' milliseconds looking for the reset to complete
+	before returning. Returns MTD_FAIL if times out.
+
+ Side effects:
+	All "retain" bits keep their values through this reset. Non-"retain"-type
+	bits are returned to their hardware reset values following this reset.
+	See the Datasheet for a list of retain bits.
+
+ Notes/Warnings:
+	Use mtdIsPhyReadyAfterReset() to see if the software reset is complete
+	before issuing any other MDIO commands following this reset or pass
+	in non-zero timeoutMs to have this function do it for you.
+
+	This is a T unit software reset only. It may only be issued if the T
+	unit is ready (1.0.15 is 0) and the T unit is not in low power mode.
+
+******************************************************************************/
+MTD_STATUS mtdSoftwareReset
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 timeoutMs
+);
+
+MTD_STATUS mtdHardwareReset
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 timeoutMs
+);
+
+/******************************************************************************
+ MTD_STATUS mtdSetMacInterfaceControl
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port,
+	 IN MTD_U16 macType,
+	 IN MTD_BOOL macIfPowerDown,
+	 IN MTD_U16 macIfSnoopSel,
+	 IN MTD_U16 macIfActiveLaneSelect,
+	 IN MTD_U16 macLinkDownSpeed,
+	 IN MTD_U16 macMaxIfSpeed,  - 33X0/E20X0 devices only -
+	 IN MTD_BOOL doSwReset,
+	 IN MTD_BOOL rerunSerdesInitialization
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - port number, 0-31
+	macType - the type of MAC interface being used (the hardware interface). One of the following:
+		MTD_MAC_TYPE_RXAUI_SGMII_AN_EN - selects RXAUI with SGMII AN enabled
+		MTD_MAC_TYPE_RXAUI_SGMII_AN_DIS - selects RXAUI with SGMII AN disabled (not valid on X3310)
+		MTD_MAC_TYPE_XAUI_RATE_ADAPT - selects XAUI with rate matching (only valid on X3310)
+		MTD_MAC_TYPE_RXAUI_RATE_ADAPT  - selects RXAUI with rate matching
+		MTD_MAC_TYPE_XAUI - selects XAUI (only valid on X3310)
+		MTD_MAC_TYPE_XFI_SGMII_AN_EN - selects XFI with SGMII AN enabled
+		MTD_MAC_TYPE_XFI_SGMII_AN_DIS - selects XFI with SGMII AN disabled
+		MTD_MAC_TYPE_XFI_RATE_ADAPT  - selects XFI with rate matching
+		MTD_MAC_TYPE_USXGMII - selects USXGMII
+		MTD_MAC_LEAVE_UNCHANGED - option to leave this parameter unchanged/as it is
+	macIfPowerDown - MTD_TRUE if the host interface is always to be powered up
+					 MTD_FALSE if the host interface can be powered down under
+						 certain circumstances (see datasheet)
+	macIfSnoopSel - If snooping is requested on the other lane, selects the source
+		MTD_MAC_SNOOP_FROM_NETWORK - source of snooped data is to come from the network
+		MTD_MAC_SNOOP_FROM_HOST - source of snooped data is to come from the host
+		MTD_MAC_SNOOP_OFF - snooping is to be turned off
+		MTD_MAC_SNOOP_LEAVE_UNCHANGED - option to leave this parameter unchanged/as it is
+	macIfActiveLaneSelect - For redundant host mode, this selects the active lane. 0 or 1
+		only. 0 selects 0 as the active lane and 1 as the standby. 1 selects the other way.
+	macLinkDownSpeed - The speed the mac interface should run when the media side is
+		link down. One of the following:
+			MTD_MAC_SPEED_10_MBPS
+			MTD_MAC_SPEED_100_MBPS
+			MTD_MAC_SPEED_1000_MBPS
+			MTD_MAC_SPEED_10_GBPS
+			MTD_MAC_SPEED_LEAVE_UNCHANGED
+	macMaxIfSpeed - For X33X0/E20X0 devices only. Can be used to limit the Mac interface speed
+			MTD_MAX_MAC_SPEED_10G
+			MTD_MAX_MAC_SPEED_5G
+			MTD_MAX_MAC_SPEED_2P5G
+			MTD_MAX_MAC_SPEED_LEAVE_UNCHANGED
+			MTD_MAX_MAC_SPEED_NOT_APPLICABLE (for 32X0 devices pass this)
+	doSwReset - MTD_TRUE if a software reset (31.F001.15) should be done after these changes
+		have been made, or MTD_FALSE otherwise. See note below.
+	rerunSerdesInitialization - MTD_TRUE if any parameter that is likely to change the speed
+		of the serdes interface was performed like macLinkDownSpeed or macType will attempt
+		to reset the H unit serdes (this needs to be done AFTER the soft reset, so if doSwReset
+		is passed as MTD_FALSE, host must later call
+		mtdRerunSerdesAutoInitializationUseAutoMode() eventually to re-init the serdes).
+
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK or MTD_FAIL if a bad parameter was passed, or an IO error occurs.
+
+ Description:
+	Changes the above parameters as indicated in 31.F000 and 31.F001 and
+	optionally does a software reset afterwards for those bits which require a
+	software reset to take effect.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	These bits are actually in the C unit, but pertain to the host interface
+	control so the API called was placed here.
+
+	Changes to the MAC type (31.F001.2:0) do not take effect until a software
+	reset is performed on the port.
+
+	Changes to macLinkDownSpeed (31.F001.7:6) require 2 software resets to
+	take effect. This function will do 2 resets if doSwReset is MTD_TRUE
+	and macLinkDownSpeed is being changed.
+
+	IMPORTANT: the readback reads back the last written value following
+	a software reset. Writes followed by reads without an intervening
+	software reset will read back the old bit value for all those bits
+	requiring a software.
+
+	Because of this, read-modify-writes to different bitfields must have an
+	intervening software reset to pick up the latest value before doing
+	another read-modify-write to the register, otherwise the bitfield
+	may lose the value.
+
+	Suggest always setting doSwReset to MTD_TRUE to avoid problems of
+	possibly losing changes.
+
+******************************************************************************/
+MTD_STATUS mtdSetMacInterfaceControl
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 macType,
+	IN MTD_BOOL macIfPowerDown,
+	IN MTD_U16 macIfSnoopSel,
+	IN MTD_U16 macIfActiveLaneSelect,
+	IN MTD_U16 macLinkDownSpeed,
+	IN MTD_U16 macMaxIfSpeed, /* 33X0/E20X0 devices only */
+	IN MTD_BOOL doSwReset,
+	IN MTD_BOOL rerunSerdesInitialization
+);
+
+/******************************************************************************
+ MTD_STATUS mtdEnableSpeeds
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port,
+	 IN MTD_U16 speed_bits,
+	 IN MTD_BOOL anRestart
+ );
+
+ Inputs: 2
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	speed_bits - speeds to be advertised during auto-negotiation. One or more
+				 of the following (bits logically OR together):
+				MTD_ADV_NONE (no bits set)
+				MTD_SPEED_10M_HD
+				MTD_SPEED_10M_FD
+				MTD_SPEED_100M_HD
+				MTD_SPEED_100M_FD
+				MTD_SPEED_1GIG_HD
+				MTD_SPEED_1GIG_FD
+				MTD_SPEED_10GIG_FD
+				MTD_SPEED_2P5GIG_FD (88X33X0/88E20X0 family only)
+				MTD_SPEED_5GIG_FD (88X33X0/88E20X0 family only)
+				MTD_SPEED_ALL
+				MTD_SPEED_ALL_33X0 (88X33X0/88E20X0 family only)
+
+	anRestart - this takes the value of MTD_TRUE or MTD_FALSE and indicates
+				if auto-negotiation should be restarted following the speed
+				enable change. If this is MTD_FALSE, the change will not
+				take effect until AN is restarted in some other way (link
+				drop, toggle low power, toggle AN enable, toggle soft reset).
+
+				If this is MTD_TRUE and AN has been disabled, it will be
+				enabled before being restarted.
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK if action was successfully taken, MTD_FAIL if not. Also returns
+	MTD_FAIL if try to force the speed or try to advertise a speed not supported
+	on this PHY.
+
+ Description:
+	This function allows the user to select the speeds to be advertised to the
+	link partner during auto-negotiation.
+
+	First, this function enables auto-negotiation and XNPs by calling
+	mtdUndoForcedSpeed().
+
+	The function takes in a 16 bit value and sets the appropriate bits in MMD
+	7 to have those speeds advertised.
+
+	The function also checks if the input parameter is MTD_ADV_NONE, in which case
+	all speeds are disabled effectively disabling the phy from training
+	(but not disabling auto-negotiation).
+
+	If anRestart is MTD_TRUE, an auto-negotiation restart is issued making the change
+	immediate. If anRestart is MTD_FALSE, the change will not take effect until the
+	next time auto-negotiation restarts.
+
+ Side effects:
+	Setting speed in 1.0 to 10GBASE-T has the effect of enabling XNPs in 7.0 and
+	enabling auto-negotiation in 7.0.
+
+ Notes/Warnings:
+
+	Example:
+	To train the highest speed matching the far end among
+	either 1000BASE-T Full-duplex or 10GBASE-T:
+	mtdEnableSpeeds(devPtr,port,MTD_SPEED_1GIG_FD | MTD_SPEED_10GIG_FD, MTD_TRUE);
+
+	To allow only 10GBASE-T to train:
+	mtdEnableSpeeds(devPtr,port,MTD_SPEED_10GIG_FD, MTD_TRUE);
+
+	To disable all speeds (but AN will still be running, just advertising no
+	speeds)
+	mtdEnableSpeeds(devPtr,port,MTD_ADV_NONE, MTD_TRUE);
+
+	This function is not to be used to disable autonegotiation and force the speed
+	to 10BASE-T or 100BASE-TX. Use mtdForceSpeed() for this.
+
+	88X33X0 Z1/Z2 and E20X0 Z2 are not supported starting with API version 1.2.
+	Version 1.2 and later require A0 revision of these devices.
+
+******************************************************************************/
+MTD_STATUS mtdEnableSpeeds
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U16 speed_bits,
+	IN MTD_BOOL anRestart
+);
+
+MTD_STATUS mtdGetAutonegSpeedDuplexResolution
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U16 *speedResolution
+);
+
+MTD_STATUS mtdAutonegIsSpeedDuplexResolutionDone
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *anSpeedResolutionDone
+);
+
+/******************************************************************************
+MTD_STATUS mtdIsBaseTUp(
+	IN MTD_DEV_PTR devPtr,
+	MTD_U16 port,
+	MTD_U16 *speed,
+	MTD_BOOL *linkUp
+);
+
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	speed - which speed was resolved or will be resolved by auto-negotiation,
+			one of following
+			 MTD_ADV_NONE - autonegotiation is in progress or disabled
+			 MTD_SPEED_10M_HD - speed is resolved to 10BT half-duplex
+			 MTD_SPEED_10M_FD - speed is resolved to 10BT full-duplex
+			 MTD_SPEED_100M_HD - speed is resolved to 100BASE-TX half-duplex
+			 MTD_SPEED_100M_FD - speed is resolved to 100BASE-TX full-duplex
+			 MTD_SPEED_1GIG_HD - speed is resolved to 1000BASE-T half-duplex
+			 MTD_SPEED_1GIG_FD - speed is resolved to 1000BASE-T full-duplex
+			 MTD_SPEED_10GIG_FD - speed is resolved to 10GBASE-T
+			 MTD_SPEED_2P5GIG_FD - speed is resolved to 2.5GBASE-T (88X33X0/88E20X0 family only)
+			 MTD_SPEED_5GIG_FD - speed is resolved to 5GBASE-T (88X33X0/88E20X0 family only)
+
+			 MTD_SPEED_10M_HD_AN_DIS - speed forced to 10BT half-duplex
+			 MTD_SPEED_10M_FD_AN_DIS - speed forced to 10BT full-duplex
+			 MTD_SPEED_100M_HD_AN_DIS - speed forced to 100BT half-duplex
+			 MTD_SPEED_100M_FD_AN_DIS - speed forced to 100BT full-duplex
+			 MTD_SPEED_MISMATCH - speed is forced to one of above speeds, but
+								  indicated up at a different speed (this is an error)
+
+	linkUp - MTD_TRUE if the copper link is up at the speed above
+			 MTD_FALSE if the link is down or autonegotiation is in progress or
+			 there's an error
+
+ Returns:
+	MTD_OK, if query was successful, MTD_FAIL if query was unsuccessful or if there
+	was an error such as MTD_SPEED_MISMATCH. MTD_OK indicates speed and link
+	status are valid. MTD_FAIL indicates speed and link status are invalid.
+
+ Description:
+
+	First checks if the speed is forced to 10BT or 100BTX, and if it is returns
+	one of the following combinations
+
+	Speed Forced Value		   Link Status	Status
+	------------------		   -----------	------
+	MTD_SPEED_10M_HD_AN_DIS	  MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_10M_FD_AN_DIS	  MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_100M_HD_AN_DIS	 MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_100M_FD_AN_DIS	 MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	any of the above with		MTD_FALSE	  MTD_FAIL - query failed
+
+	MTD_SPEED_MISMATCH		   MTD_FALSE	  MTD_FAIL - link at different speed than forced value
+												This is an error. Link may be up at wrong speed
+												or training at wrong speed.
+
+	If speed is not forced, then checks if autonegotation is resolved or in-progress and
+	returns one of the following combinations:
+
+	Autonegotation Result		Link Status	Status
+	---------------------		-----------	------
+	MTD_ADV_NONE				 MTD_FALSE	  MTD_OK - autonegotiation is in progress (link is down)
+	MTD_SPEED_10M_HD			 MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_10M_FD			 MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_100M_HD			MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_100M_FD			MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_1GIG_HD			MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_1GIG_FD			MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_10GIG_FD		   MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_2P5GIG_FD		  MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+	MTD_SPEED_5GIG_FD			MTD_TRUE/FALSE MTD_OK - query successful, link status/speed valid
+
+	any of the above with		MTD_FALSE	  MTD_FAIL - query failed
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	Gives current real-time status of the copper interface.
+******************************************************************************/
+MTD_STATUS mtdIsBaseTUp(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U16 *speed,
+	OUT MTD_BOOL *linkUp
+);
+
+
+
+/****************************************************************************/
+/*******************************************************************
+  Firmware Version
+ *******************************************************************/
+/****************************************************************************/
+
+/******************************************************************************
+MTD_STATUS mtdGetFirmwareVersion
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *major,
+	OUT MTD_U8 *minor,
+	OUT MTD_U8 *inc,
+	OUT MTD_U8 *test
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	major - major version, X.Y.Z.W, the X
+	minor - minor version, X.Y.Z.W, the Y
+	inc   - incremental version, X.Y.Z.W, the Z
+	test  - test version, X.Y.Z.W, the W, should be 0 for released code,
+			non-zero indicates this is a non-released code
+
+ Returns:
+	MTD_FAIL if version can't be queried or firmware is in download mode
+	(meaning all version numbers are 0), MTD_OK otherwise
+
+ Description:
+	This function reads the firmware version number and stores it in the
+	pointers passed in by the user.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	This function returns all 0's if the phy is in download mode. The phy
+	application code must have started and be ready before issuing this
+	command.
+
+******************************************************************************/
+MTD_STATUS mtdGetFirmwareVersion
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *major,
+	OUT MTD_U8 *minor,
+	OUT MTD_U8 *inc,
+	OUT MTD_U8 *test
+);
+
+/******************************************************************************
+MTD_STATUS mtdSetPauseAdvertisement
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U8 pauseType,
+	IN MTD_BOOL anRestart
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	pauseType - one of the following:
+				MTD_SYM_PAUSE,
+				MTD_ASYM_PAUSE,
+				MTD_SYM_ASYM_PAUSE or
+				MTD_CLEAR_PAUSE.
+	anRestart - this takes the value of MTD_TRUE or MTD_FALSE and indicates
+				if auto-negotiation should be restarted following the speed
+				enable change. If this is MTD_FALSE, the change will not
+				take effect until AN is restarted in some other way (link
+				drop, toggle low power, toggle AN enable, toggle soft reset).
+
+				If this is MTD_TRUE and AN has been disabled, it will be
+				enabled before being restarted.
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK or MTD_FAIL, if action was successful or failed
+
+ Description:
+	This function sets the asymmetric and symmetric pause bits in the technology
+	ability field in the AN Advertisement register and optionally restarts
+	auto-negotiation to use the new values. This selects what type of pause
+	is to be advertised to the far end MAC during auto-negotiation. If
+	auto-negotiation is restarted, it is enabled first.
+
+	Sets entire 2-bit field to the value passed in pauseType.
+
+	To clear both bits, pass in MTD_CLEAR_PAUSE.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	This function will not take effect unless the auto-negotiation is restarted.
+
+******************************************************************************/
+MTD_STATUS mtdSetPauseAdvertisement
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_U32 pauseType,
+	IN MTD_BOOL anRestart
+);
+
+
+/******************************************************************************
+MTD_STATUS mtdGetLPAdvertisedPause
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *pauseBits
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	pauseBits - setting of link partner's pause bits based on bit definitions above in
+				mtdmtdSetPauseAdvertisement()
+
+ Returns:
+	MTD_OK or MTD_FAIL, based on whether the query succeeded or failed. Returns
+	MTD_FAIL and MTD_CLEAR_PAUSE if AN is not complete.
+
+ Description:
+	This function reads 7.19 (LP Base page ability) and returns the advertised
+	pause setting that was received from the link partner.
+
+ Side effects:
+	None
+
+ Notes/Warnings:
+	The user must make sure auto-negotiation has completed by calling
+	mtdAutonegIsCompleted() prior to calling this function.
+
+******************************************************************************/
+MTD_STATUS mtdGetLPAdvertisedPause
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_U8 *pauseBits
+);
+
+
+
+/******************************************************************************
+MTD_STATUS mtdGetPhyRevision
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_DEVICE_ID *phyRev,
+	OUT MTD_U8 *numPorts,
+	OUT MTD_U8 *thisPort
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	phyRev - revision of this chip, see MTD_DEVICE_ID definition for
+			 a list of chip revisions with different options
+	numPorts - number of ports on this chip (see note below)
+	thisPort - this port number 0-1, or 0-4
+
+ Returns:
+	MTD_OK if query was successful, MTD_FAIL if not.
+
+	Will return MTD_FAIL on an unsupported PHY (but will attempt to
+	return correct version). See below for a list of unsupported PHYs.
+
+ Description:
+	Determines the PHY revision and returns the value in phyRev.
+	See definition of MTD_DEVICE_ID for a list of available
+	devices and capabilities.
+
+ Side effects:
+	None.
+
+ Notes/Warnings:
+	The phyRev can be used to determine number PHY revision,
+	number of ports, which port this is from PHY perspective
+	(0-based indexing 0...3 or 0..2) and what capabilities
+	the PHY has.
+
+	If phyRev is MTD_REV_UNKNOWN, numPorts and thisPort will be returned
+	as 0 and the function will return MTD_FAIL.
+
+	If T-unit is in download mode, thisPort will be returned as 0.
+
+	88X33X0 Z1/Z2 is not supported starting with version 1.2 of API.
+	E20X0 Z2 is not supported starting with version 1.2 of API.
+
+******************************************************************************/
+MTD_STATUS mtdGetPhyRevision
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_DEVICE_ID *phyRev,
+	OUT MTD_U8 *numPorts,
+	OUT MTD_U8 *thisPort
+);
+
+
+
+/*****************************************************************************
+MTD_STATUS mtdGetForcedSpeed
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *speedIsForced,
+	OUT MTD_U16 *forcedSpeed
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	speedIsForced - MTD_TRUE if an is disabled (1.0.12 == 0) AND
+		the speed in 1.0.13/6 is set to 10BT or 100BT (speeds which do
+		not require an to train).
+	forcedSpeed - one of the following if speedIsForced is MTD_TRUE
+		MTD_SPEED_10M_HD_AN_DIS  - speed forced to 10BT half-duplex
+		MTD_SPEED_10M_FD_AN_DIS  - speed forced to 10BT full-duplex
+		MTD_SPEED_100M_HD_AN_DIS - speed forced to 100BT half-duplex
+		MTD_SPEED_100M_FD_AN_DIS - speed forced to 100BT full-duplex
+
+ Returns:
+	MTD_OK if the query was successful, or MTD_FAIL if not
+
+ Description:
+	Checks if AN is disabled (7.0.12=0) and if the speed select in
+	register 1.0.13 and 1.0.6 is set to either 10BT or 100BT speeds. If
+	all of this is true, returns MTD_TRUE in speedIsForced along with
+	the speed/duplex setting in forcedSpeedBits. If any of this is
+	false (AN is enabled, or the speed is set to 1000BT or 10GBT), then
+	speedIsForced is returned MTD_FALSE and the forcedSpeedBit value
+	is invalid.
+
+ Notes/Warnings:
+	None.
+
+******************************************************************************/
+MTD_STATUS mtdGetForcedSpeed
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	OUT MTD_BOOL *speedIsForced,
+	OUT MTD_U16 *forcedSpeed
+);
+
+
+/*****************************************************************************
+MTD_STATUS mtdUndoForcedSpeed
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_BOOL anRestart
+);
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+	anRestart - this takes the value of MTD_TRUE or MTD_FALSE and indicates
+				if auto-negotiation should be restarted following the speed
+				enable change. If this is MTD_FALSE, the change will not
+				take effect until AN is restarted in some other way (link
+				drop, toggle low power, toggle AN enable, toggle soft reset).
+
+				If this is MTD_TRUE and AN has been disabled, it will be
+				enabled before being restarted.
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK if the change was successful, or MTD_FAIL if not
+
+ Description:
+	Sets the speed bits in 1.0 back to the power-on default of 11b
+	(10GBASE-T). Enables auto-negotiation.
+
+	Does a software reset of the T unit and wait until it is complete before
+	enabling AN and returning.
+
+ Notes/Warnings:
+	None.
+
+******************************************************************************/
+MTD_STATUS mtdUndoForcedSpeed
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port,
+	IN MTD_BOOL anRestart
+);
+
+
+/******************************************************************************
+ MTD_STATUS mtdAutonegEnable
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK or MTD_FAIL, if action was successful or not
+
+ Description:
+	Re-enables auto-negotiation.
+
+ Side effects:
+
+ Notes/Warnings:
+	Restart autonegation will not take effect if AN is disabled.
+
+******************************************************************************/
+MTD_STATUS mtdAutonegEnable
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port
+);
+
+
+
+/******************************************************************************
+ MTD_STATUS mtdAutonegRestart
+ (
+	 IN MTD_DEV_PTR devPtr,
+	 IN MTD_U16 port
+ );
+
+ Inputs:
+	devPtr - pointer to MTD_DEV initialized by mtdLoadDriver() call
+	port - MDIO port address, 0-31
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK or MTD_FAIL, depending on if action was successful
+
+ Description:
+	Restarts auto-negotiation. The bit is self-clearing. If the link is up,
+	the link will drop and auto-negotiation will start again.
+
+ Side effects:
+	None.
+
+ Notes/Warnings:
+	Restarting auto-negotiation will have no effect if auto-negotiation is
+	disabled.
+
+	This function is important as it is necessary to restart auto-negotiation
+	after changing many auto-negotiation settings before the changes will take
+	effect.
+
+******************************************************************************/
+MTD_STATUS mtdAutonegRestart
+(
+	IN MTD_DEV_PTR devPtr,
+	IN MTD_U16 port
+);
+
+
+
+/******************************************************************************
+MTD_STATUS mtdIsPhyRevisionValid
+(
+	IN MTD_DEVICE_ID phyRev
+);
+
+
+ Inputs:
+	phyRev - a revision id to be checked against MTD_DEVICE_ID type
+
+ Outputs:
+	None
+
+ Returns:
+	MTD_OK if phyRev is a valid revision, MTD_FAIL otherwise
+
+ Description:
+	Takes phyRev and returns MTD_OK if it is one of the MTD_DEVICE_ID
+	type, otherwise returns MTD_FAIL.
+
+ Side effects:
+	None.
+
+ Notes/Warnings:
+	None
+
+******************************************************************************/
+MTD_STATUS mtdIsPhyRevisionValid
+(
+	IN MTD_DEVICE_ID phyRev
+);
+
+
+
+
+
+#if C_LINKAGE
+#if defined __cplusplus
+}
+#endif
+#endif
+
+#endif /* _TXGBE_MTD_H_ */
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_osdep.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_osdep.h
new file mode 100644
index 000000000000..402b04d71f0f
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_osdep.h
@@ -0,0 +1,227 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_osdep.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+/* glue for the OS independent part of txgbe
+ * includes register access macros
+ */
+
+#ifndef _TXGBE_OSDEP_H_
+#define _TXGBE_OSDEP_H_
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/sched.h>
+#include "kcompat.h"
+
+#define TXGBE_CPU_TO_BE16(_x) cpu_to_be16(_x)
+#define TXGBE_BE16_TO_CPU(_x) be16_to_cpu(_x)
+#define TXGBE_CPU_TO_BE32(_x) cpu_to_be32(_x)
+#define TXGBE_BE32_TO_CPU(_x) be32_to_cpu(_x)
+
+#define msec_delay(_x) msleep(_x)
+
+#define usec_delay(_x) udelay(_x)
+
+#define STATIC static
+
+#define IOMEM __iomem
+
+#define TXGBE_NAME "txgbe"
+
+/* #define DBG 1 */
+
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+	((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+	printk(KERN_##klevel TXGBE_NAME ": %s: %s: " fmt, \
+		adapter->netdev->name, \
+		__func__, ## args)))
+
+#ifndef _WIN32
+#define txgbe_emerg(fmt, ...)   printk(KERN_EMERG fmt, ## __VA_ARGS__)
+#define txgbe_alert(fmt, ...)   printk(KERN_ALERT fmt, ## __VA_ARGS__)
+#define txgbe_crit(fmt, ...)    printk(KERN_CRIT fmt, ## __VA_ARGS__)
+#define txgbe_error(fmt, ...)   printk(KERN_ERR fmt, ## __VA_ARGS__)
+#define txgbe_warn(fmt, ...)    printk(KERN_WARNING fmt, ## __VA_ARGS__)
+#define txgbe_notice(fmt, ...)  printk(KERN_NOTICE fmt, ## __VA_ARGS__)
+#define txgbe_info(fmt, ...)    printk(KERN_INFO fmt, ## __VA_ARGS__)
+#define txgbe_print(fmt, ...)   printk(KERN_DEBUG fmt, ## __VA_ARGS__)
+#define txgbe_trace(fmt, ...)   printk(KERN_INFO fmt, ## __VA_ARGS__)
+#else /* _WIN32 */
+#define txgbe_error(lvl, fmt, ...) \
+	DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \
+		"%s-error: %s@%d, " fmt, \
+		"txgbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
+#endif /* !_WIN32 */
+
+#ifdef DBG
+#ifndef _WIN32
+#define txgbe_debug(fmt, ...) \
+	printk(KERN_DEBUG \
+		"%s-debug: %s@%d, " fmt, \
+		"txgbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
+#else /* _WIN32 */
+#define txgbe_debug(fmt, ...) \
+	DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \
+		"%s-debug: %s@%d, " fmt, \
+		"txgbe", __FUNCTION__, __LINE__, ## __VA_ARGS__)
+#endif /* _WIN32 */
+#else /* DBG */
+#define txgbe_debug(fmt, ...) do {} while (0)
+#endif /* DBG */
+
+
+#ifdef DBG
+#define ASSERT(_x)              BUG_ON(!(_x))
+#define DEBUGOUT(S)             printk(KERN_DEBUG S)
+#define DEBUGOUT1(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGOUT2(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGOUT3(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGOUT4(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGOUT5(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGOUT6(S, A...)      printk(KERN_DEBUG S, ## A)
+#define DEBUGFUNC(fmt, ...)     txgbe_debug(fmt, ## __VA_ARGS__)
+#else
+#define ASSERT(_x)              do {} while (0)
+#define DEBUGOUT(S)             do {} while (0)
+#define DEBUGOUT1(S, A...)      do {} while (0)
+#define DEBUGOUT2(S, A...)      do {} while (0)
+#define DEBUGOUT3(S, A...)      do {} while (0)
+#define DEBUGOUT4(S, A...)      do {} while (0)
+#define DEBUGOUT5(S, A...)      do {} while (0)
+#define DEBUGOUT6(S, A...)      do {} while (0)
+#define DEBUGFUNC(fmt, ...)     do {} while (0)
+#endif
+
+#define TXGBE_SFP_DETECT_RETRIES        2
+
+struct txgbe_hw;
+struct txgbe_msg {
+	u16 msg_enable;
+};
+struct net_device *txgbe_hw_to_netdev(const struct txgbe_hw *hw);
+struct txgbe_msg *txgbe_hw_to_msg(const struct txgbe_hw *hw);
+
+#define hw_dbg(hw, format, arg...) \
+	netdev_dbg(txgbe_hw_to_netdev(hw), format, ## arg)
+#define hw_err(hw, format, arg...) \
+	netdev_err(txgbe_hw_to_netdev(hw), format, ## arg)
+#define e_dev_info(format, arg...) \
+	dev_info(pci_dev_to_dev(adapter->pdev), format, ## arg)
+#define e_dev_warn(format, arg...) \
+	dev_warn(pci_dev_to_dev(adapter->pdev), format, ## arg)
+#define e_dev_err(format, arg...) \
+	dev_err(pci_dev_to_dev(adapter->pdev), format, ## arg)
+#define e_dev_notice(format, arg...) \
+	dev_notice(pci_dev_to_dev(adapter->pdev), format, ## arg)
+#define e_dbg(msglvl, format, arg...) \
+	netif_dbg(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_info(msglvl, format, arg...) \
+	netif_info(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_err(msglvl, format, arg...) \
+	netif_err(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_warn(msglvl, format, arg...) \
+	netif_warn(adapter, msglvl, adapter->netdev, format, ## arg)
+#define e_crit(msglvl, format, arg...) \
+	netif_crit(adapter, msglvl, adapter->netdev, format, ## arg)
+
+#define TXGBE_FAILED_READ_CFG_DWORD 0xffffffffU
+#define TXGBE_FAILED_READ_CFG_WORD  0xffffU
+#define TXGBE_FAILED_READ_CFG_BYTE  0xffU
+
+extern u32 txgbe_read_reg(struct txgbe_hw *hw, u32 reg, bool quiet);
+extern u16 txgbe_read_pci_cfg_word(struct txgbe_hw *hw, u32 reg);
+extern void txgbe_write_pci_cfg_word(struct txgbe_hw *hw, u32 reg, u16 value);
+
+#define TXGBE_READ_PCIE_WORD txgbe_read_pci_cfg_word
+#define TXGBE_WRITE_PCIE_WORD txgbe_write_pci_cfg_word
+#define TXGBE_R32_Q(h, r) txgbe_read_reg(h, r, true)
+
+#ifndef writeq
+#define writeq(val, addr)       do { writel((u32) (val), addr); \
+				     writel((u32) (val >> 32), (addr + 4)); \
+				} while (0);
+#endif
+
+#define TXGBE_EEPROM_GRANT_ATTEMPS 100
+#define TXGBE_HTONL(_i) htonl(_i)
+#define TXGBE_NTOHL(_i) ntohl(_i)
+#define TXGBE_NTOHS(_i) ntohs(_i)
+#define TXGBE_CPU_TO_LE32(_i) cpu_to_le32(_i)
+#define TXGBE_LE32_TO_CPUS(_i) le32_to_cpus(_i)
+
+enum {
+	TXGBE_ERROR_SOFTWARE,
+	TXGBE_ERROR_POLLING,
+	TXGBE_ERROR_INVALID_STATE,
+	TXGBE_ERROR_UNSUPPORTED,
+	TXGBE_ERROR_ARGUMENT,
+	TXGBE_ERROR_CAUTION,
+};
+
+#define ERROR_REPORT(level, format, arg...) do {                               \
+	switch (level) {                                                       \
+	case TXGBE_ERROR_SOFTWARE:                                             \
+	case TXGBE_ERROR_CAUTION:                                              \
+	case TXGBE_ERROR_POLLING:                                              \
+		netif_warn(txgbe_hw_to_msg(hw), drv, txgbe_hw_to_netdev(hw),   \
+			   format, ## arg);                                    \
+		break;                                                         \
+	case TXGBE_ERROR_INVALID_STATE:                                        \
+	case TXGBE_ERROR_UNSUPPORTED:                                          \
+	case TXGBE_ERROR_ARGUMENT:                                             \
+		netif_err(txgbe_hw_to_msg(hw), hw, txgbe_hw_to_netdev(hw),     \
+			  format, ## arg);                                     \
+		break;                                                         \
+	default:                                                               \
+		break;                                                         \
+	}                                                                      \
+} while (0)
+
+#define ERROR_REPORT1 ERROR_REPORT
+#define ERROR_REPORT2 ERROR_REPORT
+#define ERROR_REPORT3 ERROR_REPORT
+
+#define UNREFERENCED_XPARAMETER
+#define UNREFERENCED_1PARAMETER(_p) do {                \
+	uninitialized_var(_p);                          \
+} while (0)
+#define UNREFERENCED_2PARAMETER(_p, _q) do {            \
+	uninitialized_var(_p);                          \
+	uninitialized_var(_q);                          \
+} while (0)
+#define UNREFERENCED_3PARAMETER(_p, _q, _r) do {        \
+	uninitialized_var(_p);                          \
+	uninitialized_var(_q);                          \
+	uninitialized_var(_r);                          \
+} while (0)
+#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s) do {    \
+	uninitialized_var(_p);                          \
+	uninitialized_var(_q);                          \
+	uninitialized_var(_r);                          \
+	uninitialized_var(_s);                          \
+} while (0)
+#define UNREFERENCED_PARAMETER(_p) UNREFERENCED_1PARAMETER(_p)
+
+#endif /* _TXGBE_OSDEP_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_param.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_param.c
new file mode 100644
index 000000000000..e3b426a0d3d5
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_param.c
@@ -0,0 +1,1569 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_param.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+#include "txgbe.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define TXGBE_MAX_NIC   32
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+#define STRINGIFY(foo)  #foo /* magic for getting defines into strings */
+#define XSTRINGIFY(bar) STRINGIFY(bar)
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define TXGBE_PARAM_INIT { [0 ... TXGBE_MAX_NIC] = OPTION_UNSET }
+#ifndef module_param_array
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when txgbe_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labelled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
+#define TXGBE_PARAM(X, desc) \
+	static const int __devinitconst X[TXGBE_MAX_NIC+1] = TXGBE_PARAM_INIT; \
+	MODULE_PARM(X, "1-" __MODULE_STRING(TXGBE_MAX_NIC) "i"); \
+	MODULE_PARM_DESC(X, desc);
+#else /* !module_param_array */
+#define TXGBE_PARAM(X, desc) \
+	static int __devinitdata X[TXGBE_MAX_NIC+1] = TXGBE_PARAM_INIT; \
+	static unsigned int num_##X; \
+	module_param_array_named(X, X, int, &num_##X, 0); \
+	MODULE_PARM_DESC(X, desc);
+#endif /* module_param_array */
+
+/* ffe_main (KR/KX4/KX/SFI)
+ *
+ * Valid Range: 0-60
+ *
+ * Default Value: 27
+ */
+TXGBE_PARAM(an73_train_mode, "an73_train_mode to different switch(0 to centc, 1 to other)");
+#define TXGBE_DEFAULT_FFE_AN73_TRAIN_MODE   0
+
+
+/* ffe_main (KR/KX4/KX/SFI)
+ *
+ * Valid Range: 0-60
+ *
+ * Default Value: 27
+ */
+TXGBE_PARAM(FFE_MAIN, "TX_EQ MAIN (0 - 40)");
+#define TXGBE_DEFAULT_FFE_MAIN              27
+
+/* ffe_pre
+ *
+ * Valid Range: 0-60
+ *
+ * Default Value: 8
+ */
+TXGBE_PARAM(FFE_PRE, "TX_EQ PRE (0 - 40)");
+#define TXGBE_DEFAULT_FFE_PRE              8
+
+/* ffe_post (VF Alloc Mode)
+ *
+ * Valid Range: 0-60
+ *
+ * Default Value: 44
+ */
+TXGBE_PARAM(FFE_POST, "TX_EQ POST (0 - 40)");
+#define TXGBE_DEFAULT_FFE_POST              44
+
+/* ffe_set 
+ *
+ * Valid Range: 0-4
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(FFE_SET, "TX_EQ SET must choose to take effect (0 = NULL, 1 = sfi, 2 = kr, 3 = kx4, 4 = kx)");
+#define TXGBE_DEFAULT_FFE_SET              0
+
+/* backplane_mode 
+ *
+ * Valid Range: 0-4
+ *  - 0 - NULL
+ *  - 1 - sfi
+ *  - 2 - kr
+ *  - 3 - kx4
+ *  - 4 - kx
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(backplane_mode, "Backplane Mode Support(0 = NULL, 1 = sfi, 2 = kr, 3 = kx4, 4 = kx)");
+#define TXGBE_BP_NULL                      0
+#define TXGBE_BP_SFI                       1
+#define TXGBE_BP_KR                        2
+#define TXGBE_BP_KX4                       3
+#define TXGBE_BP_KX                        4
+#define TXGBE_DEFAULT_BP_MODE              TXGBE_BP_NULL
+
+/* backplane_auto
+ *
+ * Valid Range: 0-1
+ *  - 0 - NO AUTO
+ *  - 1 - AUTO
+ * Default Value: 0
+ */
+TXGBE_PARAM(backplane_auto, "Backplane AUTO mode (0 = NO AUTO, 1 = AUTO)");
+#define TXGBE_BP_NAUTO                       0
+#define TXGBE_BP_AUTO                        1
+#define TXGBE_DEFAULT_BP_AUTO                -1
+
+/* VF_alloc_mode (VF Alloc Mode)
+ *
+ * Valid Range: 0-1
+ *  - 0 - 2 * 64
+ *  - 1 - 4 * 32
+ *  - 2 - 8 * 16
+ *
+ * Default Value: 2
+ */
+TXGBE_PARAM(vf_alloc_mode, "Change VF Alloc Mode (0 = 2*64, 1 = 4*32, 2 = 8*16)");
+#define TXGBE_2Q                	0
+#define TXGBE_4Q                   	1
+#define TXGBE_8Q                  	2
+#define TXGBE_DEFAULT_NUMQ              TXGBE_2Q
+
+/* IntMode (Interrupt Mode)
+ *
+ * Valid Range: 0-2
+ *  - 0 - Legacy Interrupt
+ *  - 1 - MSI Interrupt
+ *  - 2 - MSI-X Interrupt(s)
+ *
+ * Default Value: 2
+ */
+TXGBE_PARAM(InterruptType, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), "
+	    "default IntMode (deprecated)");
+TXGBE_PARAM(IntMode, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), "
+	    "default 2");
+#define TXGBE_INT_LEGACY                0
+#define TXGBE_INT_MSI                   1
+#define TXGBE_INT_MSIX                  2
+#define TXGBE_DEFAULT_INT               TXGBE_INT_MSIX
+
+/* MQ - Multiple Queue enable/disable
+ *
+ * Valid Range: 0, 1
+ *  - 0 - disables MQ
+ *  - 1 - enables MQ
+ *
+ * Default Value: 1
+ */
+
+TXGBE_PARAM(MQ, "Disable or enable Multiple Queues, default 1");
+
+#if IS_ENABLED(CONFIG_TPH)
+/* TPH - TLP Processing Hints
+ *
+ * This option allows the device to hint to TPH enabled processors
+ * which CPU should have its cache warmed with the data being
+ * transferred over PCIe.  This can increase performance by reducing
+ * cache misses.  txgbe hardware supports TPH for:
+ * tx descriptor writeback
+ * rx descriptor writeback
+ * rx data
+ * rx data header only (in packet split mode)
+ *
+ * enabling option 2 can cause cache thrash in some tests, particularly
+ * if the CPU is completely utilized
+ *
+ * Valid Range: 0 - 2
+ *  - 0 - disables TPH
+ *  - 1 - enables TPH
+ *  - 2 - enables TPH with rx data included
+ *
+ * Default Value: 2
+ */
+
+#define TXGBE_MAX_TPH 2
+
+TXGBE_PARAM(TPH, "Disable or enable TLP Processing Hints, 0=disabled, "
+	    "1=descriptor only, 2=descriptor and data");
+#endif /* CONFIG_TPH */
+
+/* RSS - Receive-Side Scaling (RSS) Descriptor Queues
+ *
+ * Valid Range: 0-64
+ *  - 0 - enables RSS and sets the Desc. Q's to min(64, num_online_cpus()).
+ *  - 1-64 - enables RSS and sets the Desc. Q's to the specified value.
+ *
+ * Default Value: 0
+ */
+
+TXGBE_PARAM(RSS, "Number of Receive-Side Scaling Descriptor Queues, "
+	    "default 0=number of cpus");
+
+/* VMDQ - Virtual Machine Device Queues (VMDQ)
+ *
+ * Valid Range: 1-16
+ *  - 1 Disables VMDQ by allocating only a single queue.
+ *  - 2-16 - enables VMDQ and sets the Desc. Q's to the specified value.
+ *
+ * Default Value: 1
+ */
+
+#define TXGBE_DEFAULT_NUM_VMDQ 8
+
+TXGBE_PARAM(VMDQ, "Number of Virtual Machine Device Queues: 0/1 = disable, "
+	    "2-16 enable (default=" XSTRINGIFY(TXGBE_DEFAULT_NUM_VMDQ) ")");
+
+#ifdef CONFIG_PCI_IOV
+/* max_vfs - SR I/O Virtualization
+ *
+ * Valid Range: 0-63
+ *  - 0 Disables SR-IOV
+ *  - 1-63 - enables SR-IOV and sets the number of VFs enabled
+ *
+ * Default Value: 0
+ */
+
+#define MAX_SRIOV_VFS 63
+
+TXGBE_PARAM(max_vfs, "Number of Virtual Functions: 0 = disable (default), "
+	    "1-" XSTRINGIFY(MAX_SRIOV_VFS) " = enable "
+	    "this many VFs");
+
+/* VEPA - Set internal bridge to VEPA mode
+ *
+ * Valid Range: 0-1
+ *  - 0 Set bridge to VEB mode
+ *  - 1 Set bridge to VEPA mode
+ *
+ * Default Value: 0
+ */
+/*
+ *Note:
+ *=====
+ * This provides ability to ensure VEPA mode on the internal bridge even if
+ * the kernel does not support the netdev bridge setting operations.
+*/
+TXGBE_PARAM(VEPA, "VEPA Bridge Mode: 0 = VEB (default), 1 = VEPA");
+#endif
+
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 980-500000 (0=off, 1=dynamic)
+ *
+ * Default Value: 1
+ */
+#define DEFAULT_ITR             (TXGBE_STATIC_ITR == 0) || \
+	(TXGBE_STATIC_ITR == 1)?TXGBE_STATIC_ITR:(u16)((1000000/TXGBE_STATIC_ITR) << 2)
+
+TXGBE_PARAM(InterruptThrottleRate, "Maximum interrupts per second, per vector, "
+	    "(0,1,980-500000), default 1");
+#define MAX_ITR         TXGBE_MAX_INT_RATE
+#define MIN_ITR         TXGBE_MIN_INT_RATE
+
+#ifndef TXGBE_NO_LLI
+
+/* LLIPort (Low Latency Interrupt TCP Port)
+ *
+ * Valid Range: 0 - 65535
+ *
+ * Default Value: 0 (disabled)
+ */
+TXGBE_PARAM(LLIPort, "Low Latency Interrupt TCP Port (0-65535)");
+
+#define DEFAULT_LLIPORT         0
+#define MAX_LLIPORT             0xFFFF
+#define MIN_LLIPORT             0
+
+
+/* LLISize (Low Latency Interrupt on Packet Size)
+ *
+ * Valid Range: 0 - 1500
+ *
+ * Default Value: 0 (disabled)
+ */
+TXGBE_PARAM(LLISize, "Low Latency Interrupt on Packet Size (0-1500)");
+
+#define DEFAULT_LLISIZE         0
+#define MAX_LLISIZE             1500
+#define MIN_LLISIZE             0
+
+/* LLIEType (Low Latency Interrupt Ethernet Type)
+ *
+ * Valid Range: 0 - 0x8fff
+ *
+ * Default Value: 0 (disabled)
+ */
+TXGBE_PARAM(LLIEType, "Low Latency Interrupt Ethernet Protocol Type");
+
+#define DEFAULT_LLIETYPE        0
+#define MAX_LLIETYPE            0x8fff
+#define MIN_LLIETYPE            0
+
+/* LLIVLANP (Low Latency Interrupt on VLAN priority threshold)
+ *
+ * Valid Range: 0 - 7
+ *
+ * Default Value: 0 (disabled)
+ */
+TXGBE_PARAM(LLIVLANP, "Low Latency Interrupt on VLAN priority threshold");
+
+#define DEFAULT_LLIVLANP        0
+#define MAX_LLIVLANP            7
+#define MIN_LLIVLANP            0
+
+#endif /* TXGBE_NO_LLI */
+#ifdef HAVE_TX_MQ
+/* Flow Director packet buffer allocation level
+ *
+ * Valid Range: 1-3
+ *   1 = 8k hash/2k perfect,
+ *   2 = 16k hash/4k perfect,
+ *   3 = 32k hash/8k perfect
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(FdirPballoc, "Flow Director packet buffer allocation level:\n"
+	    "\t\t\t1 = 8k hash filters or 2k perfect filters\n"
+	    "\t\t\t2 = 16k hash filters or 4k perfect filters\n"
+	    "\t\t\t3 = 32k hash filters or 8k perfect filters");
+
+#define TXGBE_DEFAULT_FDIR_PBALLOC TXGBE_FDIR_PBALLOC_64K
+
+/* Software ATR packet sample rate
+ *
+ * Valid Range: 0-255  0 = off, 1-255 = rate of Tx packet inspection
+ *
+ * Default Value: 20
+ */
+TXGBE_PARAM(AtrSampleRate, "Software ATR Tx packet sample rate");
+
+#define TXGBE_MAX_ATR_SAMPLE_RATE       255
+#define TXGBE_MIN_ATR_SAMPLE_RATE       1
+#define TXGBE_ATR_SAMPLE_RATE_OFF       0
+#define TXGBE_DEFAULT_ATR_SAMPLE_RATE   20
+#endif /* HAVE_TX_MQ */
+
+#if IS_ENABLED(CONFIG_FCOE)
+/* FCoE - Fibre Channel over Ethernet Offload  Enable/Disable
+ *
+ * Valid Range: 0, 1
+ *  - 0 - disables FCoE Offload
+ *  - 1 - enables FCoE Offload
+ *
+ * Default Value: 1
+ */
+TXGBE_PARAM(FCoE, "Disable or enable FCoE Offload, default 1");
+#endif /* CONFIG_FCOE */
+
+/* Enable/disable Large Receive Offload
+ *
+ * Valid Values: 0(off), 1(on)
+ *
+ * Default Value: 1
+ */
+TXGBE_PARAM(LRO, "Large Receive Offload (0,1), default 1 = on");
+
+/* Enable/disable support for untested SFP+ modules on adapters
+ *
+ * Valid Values: 0(Disable), 1(Enable)
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(allow_unsupported_sfp, "Allow unsupported and untested "
+	    "SFP+ modules on adapters, default 0 = Disable");
+
+TXGBE_PARAM(Fdir, "Support Flow director, default 1 = Enable, 0 = Disable ");
+/* Enable/disable support for DMA coalescing
+ *
+ * Valid Values: 0(off), 41 - 10000(on)
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(dmac_watchdog,
+	    "DMA coalescing watchdog in microseconds (0,41-10000),"
+	    "default 0 = off");
+
+/* Enable/disable support for VXLAN rx checksum offload
+ *
+ * Valid Values: 0(Disable), 1(Enable)
+ *
+ * Default Value: 1 on hardware that supports it
+ */
+TXGBE_PARAM(vxlan_rx,
+	    "VXLAN receive checksum offload (0,1), default 1 = Enable");
+
+/* Rx buffer mode
+ *
+ * Valid Range: 0-1 0 = no header split, 1 = hdr split
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(RxBufferMode, "0=(default)no header split\n"
+			  "\t\t\t1=hdr split for recognized packet\n");
+
+#define TXGBE_RXBUFMODE_NO_HEADER_SPLIT                 0
+#define TXGBE_RXBUFMODE_HEADER_SPLIT                    1
+#define TXGBE_DEFAULT_RXBUFMODE   TXGBE_RXBUFMODE_NO_HEADER_SPLIT
+
+/* Cloud Switch mode
+ *
+ * Valid Range: 0-1 0 = disable Cloud Switch, 1 = enable Cloud Switch
+ *
+ * Default Value: 0
+ */
+TXGBE_PARAM(CloudSwitch, "Cloud Switch (0,1), default 0 = disable, 1 = enable");
+
+
+struct txgbe_option {
+	enum { enable_option, range_option, list_option } type;
+	const char *name;
+	const char *err;
+	const char *msg;
+	int def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+		struct { /* list_option info */
+			int nr;
+			const struct txgbe_opt_list {
+				int i;
+				char *str;
+			} *p;
+		} l;
+	} arg;
+};
+
+static int __devinit txgbe_validate_option(u32 *value,
+					   struct txgbe_option *opt)
+{
+	int val = (int)*value;
+
+	if (val == OPTION_UNSET) {
+		txgbe_info("txgbe: Invalid %s specified (%d),  %s\n",
+			opt->name, val, opt->err);
+		*value = (u32)opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (val) {
+		case OPTION_ENABLED:
+			txgbe_info("txgbe: %s Enabled\n", opt->name);
+			return 0;
+		case OPTION_DISABLED:
+			txgbe_info("txgbe: %s Disabled\n", opt->name);
+			return 0;
+		}
+		break;
+	case range_option:
+		if ((val >= opt->arg.r.min && val <= opt->arg.r.max) ||
+		    val == opt->def) {
+			if (opt->msg)
+				txgbe_info("txgbe: %s set to %d, %s\n",
+				       opt->name, val, opt->msg);
+			else
+				txgbe_info("txgbe: %s set to %d\n",
+				       opt->name, val);
+			return 0;
+		}
+		break;
+	case list_option: {
+		int i;
+		const struct txgbe_opt_list *ent;
+
+		for (i = 0; i < opt->arg.l.nr; i++) {
+			ent = &opt->arg.l.p[i];
+			if (val == ent->i) {
+				if (ent->str[0] != '\0')
+					txgbe_info("%s\n", ent->str);
+				return 0;
+			}
+		}
+	}
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	txgbe_info("txgbe: Invalid %s specified (%d),  %s\n",
+	       opt->name, val, opt->err);
+	*value = (u32)opt->def;
+	return -1;
+}
+
+/**
+ * txgbe_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ **/
+void __devinit txgbe_check_options(struct txgbe_adapter *adapter)
+{
+	u32 bd = adapter->bd_number;
+	u32 *aflags = &adapter->flags;
+	struct txgbe_ring_feature *feature = adapter->ring_feature;
+	u32 vmdq;
+
+	if (bd >= TXGBE_MAX_NIC) {
+		txgbe_notice(
+		       "Warning: no configuration for board #%d\n", bd);
+		txgbe_notice("Using defaults for all values\n");
+#ifndef module_param_array
+		bd = TXGBE_MAX_NIC;
+#endif
+	}
+		{ /* MAIN */
+			u32 an73_mode;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "an73_train_mode",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_FFE_AN73_TRAIN_MODE),
+				.def = TXGBE_DEFAULT_FFE_AN73_TRAIN_MODE,
+				.arg = { .r = { .min = 0,
+						.max = 1} }
+			};
+		
+#ifdef module_param_array
+			if (num_an73_train_mode > bd ) {
+#endif
+				an73_mode = an73_train_mode[bd];
+				if (an73_mode == OPTION_UNSET)
+					an73_mode = an73_train_mode[bd];
+				txgbe_validate_option(&an73_mode, &opt);
+				adapter->an73_mode = an73_mode;
+#ifdef module_param_array
+			} else {
+				adapter->an73_mode = 0;
+			}
+#endif
+		}
+
+		{ /* MAIN */
+			u32 ffe_main;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "FFE_MAIN",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_FFE_MAIN),
+				.def = TXGBE_DEFAULT_FFE_MAIN,
+				.arg = { .r = { .min = 0,
+						.max = 60} }
+			};
+	
+#ifdef module_param_array
+			if (num_FFE_MAIN > bd ) {
+#endif
+				ffe_main = FFE_MAIN[bd];
+				if (ffe_main == OPTION_UNSET)
+					ffe_main = FFE_MAIN[bd];
+				txgbe_validate_option(&ffe_main, &opt);
+				adapter->ffe_main = ffe_main;
+#ifdef module_param_array
+			} else {
+						adapter->ffe_main = 27;
+			}
+#endif
+		}
+
+		{ /* PRE */
+			u32 ffe_pre;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "FFE_PRE",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_FFE_PRE),
+				.def = TXGBE_DEFAULT_FFE_PRE,
+				.arg = { .r = { .min = 0,
+						.max = 60} }
+			};
+	
+#ifdef module_param_array
+			if (num_FFE_PRE > bd ) {
+#endif
+				ffe_pre = FFE_PRE[bd];
+				if (ffe_pre == OPTION_UNSET)
+					ffe_pre = FFE_PRE[bd];
+				txgbe_validate_option(&ffe_pre, &opt);
+				adapter->ffe_pre = ffe_pre;
+#ifdef module_param_array
+			} else {
+						adapter->ffe_pre = 8;
+			}
+#endif
+		}
+
+		{ /* POST */
+			u32 ffe_post;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "FFE_POST",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_FFE_POST),
+				.def = TXGBE_DEFAULT_FFE_POST,
+				.arg = { .r = { .min = 0,
+						.max = 60} }
+			};
+	
+#ifdef module_param_array
+			if (num_FFE_POST > bd ) {
+#endif
+				ffe_post = FFE_POST[bd];
+				if (ffe_post == OPTION_UNSET)
+					ffe_post = FFE_POST[bd];
+				txgbe_validate_option(&ffe_post, &opt);
+				adapter->ffe_post = ffe_post;
+#ifdef module_param_array
+			} else {
+						adapter->ffe_post = 44;
+			}
+#endif
+		}
+
+			{ /* ffe_set */
+			u32 ffe_set;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "FFE_SET",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_FFE_SET),
+				.def = TXGBE_DEFAULT_FFE_SET,
+				.arg = { .r = { .min = 0,
+						.max = 4} }
+			};
+	
+#ifdef module_param_array
+			if (num_FFE_SET > bd ) {
+#endif
+				ffe_set = FFE_SET[bd];
+				if (ffe_set == OPTION_UNSET)
+					ffe_set = FFE_SET[bd];
+				txgbe_validate_option(&ffe_set, &opt);
+				adapter->ffe_set = ffe_set;
+#ifdef module_param_array
+			} else {
+						adapter->ffe_set = 0;
+			}
+#endif
+		}
+
+		{ /* backplane_mode */
+			u32 bp_mode;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "backplane_mode",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_BP_MODE),
+				.def = TXGBE_DEFAULT_BP_MODE,
+				.arg = { .r = { .min = 0,
+						.max = 4} }
+			};
+	
+#ifdef module_param_array
+			if (num_backplane_mode > bd ) {
+#endif
+				bp_mode = backplane_mode[bd];
+				if (bp_mode == OPTION_UNSET)
+					bp_mode = backplane_mode[bd];
+				txgbe_validate_option(&bp_mode, &opt);
+				adapter->backplane_mode = bp_mode;
+#ifdef module_param_array
+			} else {
+						adapter->backplane_mode = 0;
+			}
+#endif
+		}
+
+		{ /* auto mode */
+			u32 bp_auto;
+			static struct txgbe_option opt = {
+				.type = range_option,
+				.name = "bp_auto",
+				.err =
+				  "using default of "__MODULE_STRING(TXGBE_DEFAULT_BP_AUTO),
+				.def = TXGBE_DEFAULT_BP_AUTO,
+				.arg = { .r = { .min = 0,
+						.max = 2} }
+			};
+	
+#ifdef module_param_array
+			if (num_backplane_auto > bd ) {
+#endif
+				bp_auto = backplane_auto[bd];
+				if (bp_auto == OPTION_UNSET)
+					bp_auto = backplane_auto[bd];
+				txgbe_validate_option(&bp_auto, &opt);
+				adapter->backplane_auto = bp_auto;
+#ifdef module_param_array
+			} else {
+						adapter->backplane_auto = -1;
+			}
+#endif
+		}
+
+	{ /* VF_alloc_mode */
+		u32 vf_mode;
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "vf_alloc_mode",
+			.err =
+			  "using default of "__MODULE_STRING(TXGBE_DEFAULT_NUMQ),
+			.def = TXGBE_DEFAULT_NUMQ,
+			.arg = { .r = { .min = TXGBE_2Q,
+					.max = TXGBE_8Q} }
+		};
+
+#ifdef module_param_array
+		if (num_vf_alloc_mode > bd ) {
+#endif
+			vf_mode = vf_alloc_mode[bd];
+			if (vf_mode == OPTION_UNSET)
+				vf_mode = vf_alloc_mode[bd];
+			txgbe_validate_option(&vf_mode, &opt);
+			switch (vf_mode) {
+			case TXGBE_8Q:
+					adapter->vf_mode = 15;
+				break;
+			case TXGBE_4Q:
+					adapter->vf_mode = 31;
+				break;
+			case TXGBE_2Q:
+			default:
+					adapter->vf_mode = 63;
+				break;
+			}
+#ifdef module_param_array
+		} else {
+					adapter->vf_mode = 63;
+		}
+#endif
+	}
+	{ /* Interrupt Mode */
+		u32 int_mode;
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Interrupt Mode",
+			.err =
+			  "using default of "__MODULE_STRING(TXGBE_DEFAULT_INT),
+			.def = TXGBE_DEFAULT_INT,
+			.arg = { .r = { .min = TXGBE_INT_LEGACY,
+					.max = TXGBE_INT_MSIX} }
+		};
+
+#ifdef module_param_array
+		if (num_IntMode > bd || num_InterruptType > bd) {
+#endif
+			int_mode = IntMode[bd];
+			if (int_mode == OPTION_UNSET)
+				int_mode = InterruptType[bd];
+			txgbe_validate_option(&int_mode, &opt);
+			switch (int_mode) {
+			case TXGBE_INT_MSIX:
+				if (!(*aflags & TXGBE_FLAG_MSIX_CAPABLE))
+					txgbe_info(
+					       "Ignoring MSI-X setting; "
+					       "support unavailable\n");
+				break;
+			case TXGBE_INT_MSI:
+				if (!(*aflags & TXGBE_FLAG_MSI_CAPABLE)) {
+					txgbe_info(
+					       "Ignoring MSI setting; "
+					       "support unavailable\n");
+				} else {
+					*aflags &= ~TXGBE_FLAG_MSIX_CAPABLE;
+				}
+				break;
+			case TXGBE_INT_LEGACY:
+			default:
+				*aflags &= ~TXGBE_FLAG_MSIX_CAPABLE;
+				*aflags &= ~TXGBE_FLAG_MSI_CAPABLE;
+				break;
+			}
+#ifdef module_param_array
+		} else {
+			/* default settings */
+			if (opt.def == TXGBE_INT_MSIX &&
+			    *aflags & TXGBE_FLAG_MSIX_CAPABLE) {
+				*aflags |= TXGBE_FLAG_MSIX_CAPABLE;
+				*aflags |= TXGBE_FLAG_MSI_CAPABLE;
+			} else if (opt.def == TXGBE_INT_MSI &&
+			    *aflags & TXGBE_FLAG_MSI_CAPABLE) {
+				*aflags &= ~TXGBE_FLAG_MSIX_CAPABLE;
+				*aflags |= TXGBE_FLAG_MSI_CAPABLE;
+			} else {
+				*aflags &= ~TXGBE_FLAG_MSIX_CAPABLE;
+				*aflags &= ~TXGBE_FLAG_MSI_CAPABLE;
+			}
+		}
+#endif
+	}
+	{ /* Multiple Queue Support */
+		static struct txgbe_option opt = {
+			.type = enable_option,
+			.name = "Multiple Queue Support",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
+		};
+
+#ifdef module_param_array
+		if (num_MQ > bd) {
+#endif
+			u32 mq = MQ[bd];
+			txgbe_validate_option(&mq, &opt);
+			if (mq)
+				*aflags |= TXGBE_FLAG_MQ_CAPABLE;
+			else
+				*aflags &= ~TXGBE_FLAG_MQ_CAPABLE;
+#ifdef module_param_array
+		} else {
+			if (opt.def == OPTION_ENABLED)
+				*aflags |= TXGBE_FLAG_MQ_CAPABLE;
+			else
+				*aflags &= ~TXGBE_FLAG_MQ_CAPABLE;
+		}
+#endif
+		/* Check Interoperability */
+		if ((*aflags & TXGBE_FLAG_MQ_CAPABLE) &&
+		    !(*aflags & TXGBE_FLAG_MSIX_CAPABLE)) {
+			DPRINTK(PROBE, INFO,
+				"Multiple queues are not supported while MSI-X "
+				"is disabled.  Disabling Multiple Queues.\n");
+			*aflags &= ~TXGBE_FLAG_MQ_CAPABLE;
+		}
+	}
+
+#if IS_ENABLED(CONFIG_TPH)
+	{ /* TLP Processing Hints */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "TLP Processing Hints(TPH)",
+			.err  = "defaulting to Enabled",
+			.def  = TXGBE_MAX_TPH,
+			.arg  = { .r = { .min = OPTION_DISABLED,
+					 .max = TXGBE_MAX_TPH} }
+		};
+		u32 tph = opt.def;
+
+#ifdef module_param_array
+		if (num_TPH > bd) {
+#endif
+			tph = TPH[bd];
+			txgbe_validate_option(&tph, &opt);
+			if (!tph)
+				*aflags &= ~TXGBE_FLAG_TPH_CAPABLE;
+
+			/* Check Interoperability */
+			if (!(*aflags & TXGBE_FLAG_TPH_CAPABLE)) {
+				DPRINTK(PROBE, INFO, "TPH is disabled\n");
+				*aflags &= ~TXGBE_FLAG_TPH_ENABLED;
+			}
+
+			if (tph == TXGBE_MAX_TPH) {
+				DPRINTK(PROBE, INFO,
+					"TPH enabled for rx data\n");
+				adapter->flags |= TXGBE_FLAG_TPH_ENABLED_DATA;
+			}
+#ifdef module_param_array
+		} else {
+			/* make sure to clear the capability flag if the
+			 * option is disabled by default above */
+			if (opt.def == OPTION_DISABLED)
+				*aflags &= ~TXGBE_FLAG_TPH_CAPABLE;
+		}
+#endif
+		if (tph == TXGBE_MAX_TPH)
+			adapter->flags |= TXGBE_FLAG_TPH_ENABLED_DATA;
+	}
+#endif /* CONFIG_TPH */
+	{ /* Receive-Side Scaling (RSS) */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Receive-Side Scaling (RSS)",
+			.err  = "using default.",
+			.def  = 0,
+			.arg  = { .r = { .min = 0,
+					 .max = 1} }
+		};
+		u32 rss = RSS[bd];
+		/* adjust Max allowed RSS queues based on MAC type */
+		opt.arg.r.max = min_t(int, txgbe_max_rss_indices(adapter),
+						     num_online_cpus());
+
+#ifdef module_param_array
+		if (num_RSS > bd) {
+#endif
+			txgbe_validate_option(&rss, &opt);
+			/* base it off num_online_cpus() with hardware limit */
+			if (!rss)
+				rss = min_t(int, opt.arg.r.max,
+					    num_online_cpus());
+			else
+				feature[RING_F_FDIR].limit = (u16)rss;
+
+			feature[RING_F_RSS].limit = (u16)rss;
+#ifdef module_param_array
+		} else if (opt.def == 0) {
+			rss = min_t(int, txgbe_max_rss_indices(adapter),
+				    num_online_cpus());
+			feature[RING_F_FDIR].limit = (u16)rss;
+			feature[RING_F_RSS].limit = rss;
+		}
+#endif
+		/* Check Interoperability */
+		if (rss > 1) {
+			if (!(*aflags & TXGBE_FLAG_MQ_CAPABLE)) {
+				DPRINTK(PROBE, INFO,
+					"Multiqueue is disabled.  "
+					"Limiting RSS.\n");
+				feature[RING_F_RSS].limit = 1;
+			}
+		}
+		adapter->flags2 |= TXGBE_FLAG2_RSS_ENABLED;
+	}
+	{ /* Virtual Machine Device Queues (VMDQ) */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Virtual Machine Device Queues (VMDQ)",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_DISABLED,
+			.arg  = { .r = { .min = OPTION_DISABLED,
+					 .max = TXGBE_MAX_VMDQ_INDICES
+				} }
+		};
+
+#ifdef module_param_array
+		if (num_VMDQ > bd) {
+#endif
+			vmdq = VMDQ[bd];
+
+			txgbe_validate_option(&vmdq, &opt);
+
+			/* zero or one both mean disabled from our driver's
+			 * perspective */
+			if (vmdq > 1) {
+				*aflags |= TXGBE_FLAG_VMDQ_ENABLED;
+			} else
+				*aflags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+
+			feature[RING_F_VMDQ].limit = (u16)vmdq;
+#ifdef module_param_array
+		} else {
+			if (opt.def == OPTION_DISABLED)
+				*aflags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+			else
+				*aflags |= TXGBE_FLAG_VMDQ_ENABLED;
+
+			feature[RING_F_VMDQ].limit = opt.def;
+		}
+#endif
+		/* Check Interoperability */
+		if (*aflags & TXGBE_FLAG_VMDQ_ENABLED) {
+			if (!(*aflags & TXGBE_FLAG_MQ_CAPABLE)) {
+				DPRINTK(PROBE, INFO,
+					"VMDQ is not supported while multiple "
+					"queues are disabled.  "
+					"Disabling VMDQ.\n");
+				*aflags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+				feature[RING_F_VMDQ].limit = 0;
+			}
+		}
+	}
+#ifdef CONFIG_PCI_IOV
+	{ /* Single Root I/O Virtualization (SR-IOV) */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "I/O Virtualization (IOV)",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_DISABLED,
+			.arg  = { .r = { .min = OPTION_DISABLED,
+					 .max = MAX_SRIOV_VFS} }
+		};
+
+#ifdef module_param_array
+		if (num_max_vfs > bd) {
+#endif
+			u32 vfs = max_vfs[bd];
+			if (txgbe_validate_option(&vfs, &opt)) {
+				vfs = 0;
+				DPRINTK(PROBE, INFO,
+					"max_vfs out of range "
+					"Disabling SR-IOV.\n");
+			}
+
+			adapter->num_vfs = vfs;
+
+			if (vfs)
+				*aflags |= TXGBE_FLAG_SRIOV_ENABLED;
+			else
+				*aflags &= ~TXGBE_FLAG_SRIOV_ENABLED;
+#ifdef module_param_array
+		} else {
+			if (opt.def == OPTION_DISABLED) {
+				adapter->num_vfs = 0;
+				*aflags &= ~TXGBE_FLAG_SRIOV_ENABLED;
+			} else {
+				adapter->num_vfs = opt.def;
+				*aflags |= TXGBE_FLAG_SRIOV_ENABLED;
+			}
+		}
+#endif
+
+		/* Check Interoperability */
+		if (*aflags & TXGBE_FLAG_SRIOV_ENABLED) {
+			if (!(*aflags & TXGBE_FLAG_SRIOV_CAPABLE)) {
+				DPRINTK(PROBE, INFO,
+					"IOV is not supported on this "
+					"hardware.  Disabling IOV.\n");
+				*aflags &= ~TXGBE_FLAG_SRIOV_ENABLED;
+				adapter->num_vfs = 0;
+			} else if (!(*aflags & TXGBE_FLAG_MQ_CAPABLE)) {
+				DPRINTK(PROBE, INFO,
+					"IOV is not supported while multiple "
+					"queues are disabled.  "
+					"Disabling IOV.\n");
+				*aflags &= ~TXGBE_FLAG_SRIOV_ENABLED;
+				adapter->num_vfs = 0;
+			}
+		}
+	}
+	{ /* VEPA Bridge Mode enable for SR-IOV mode */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "VEPA Bridge Mode Enable",
+			.err  = "defaulting to disabled",
+			.def  = OPTION_DISABLED,
+			.arg  = { .r = { .min = OPTION_DISABLED,
+					 .max = OPTION_ENABLED} }
+		};
+
+#ifdef module_param_array
+		if (num_VEPA > bd) {
+#endif
+			u32 vepa = VEPA[bd];
+			txgbe_validate_option(&vepa, &opt);
+			if (vepa)
+				adapter->flags |=
+					TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
+#ifdef module_param_array
+		} else {
+			if (opt.def == OPTION_ENABLED)
+				adapter->flags |=
+					TXGBE_FLAG_SRIOV_VEPA_BRIDGE_MODE;
+		}
+#endif
+	}
+#endif /* CONFIG_PCI_IOV */
+	{ /* Interrupt Throttling Rate */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Interrupt Throttling Rate (ints/sec)",
+			.err  = "using default of "__MODULE_STRING(DEFAULT_ITR),
+			.def  = DEFAULT_ITR,
+			.arg  = { .r = { .min = MIN_ITR,
+					 .max = MAX_ITR } }
+		};
+
+#ifdef module_param_array
+		if (num_InterruptThrottleRate > bd) {
+#endif
+			u32 itr = InterruptThrottleRate[bd];
+			switch (itr) {
+			case 0:
+				DPRINTK(PROBE, INFO, "%s turned off\n",
+					opt.name);
+				adapter->rx_itr_setting = 0;
+				break;
+			case 1:
+				DPRINTK(PROBE, INFO, "dynamic interrupt "
+					"throttling enabled\n");
+				adapter->rx_itr_setting = 1;
+				break;
+			default:
+				txgbe_validate_option(&itr, &opt);
+				/* the first bit is used as control */
+				adapter->rx_itr_setting = (u16)((1000000/itr) << 2);
+				break;
+			}
+			adapter->tx_itr_setting = adapter->rx_itr_setting;
+#ifdef module_param_array
+		} else {
+			adapter->rx_itr_setting = opt.def;
+			adapter->tx_itr_setting = opt.def;
+		}
+#endif
+	}
+#ifndef TXGBE_NO_LLI
+	{ /* Low Latency Interrupt TCP Port*/
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Low Latency Interrupt TCP Port",
+			.err  = "using default of "
+					__MODULE_STRING(DEFAULT_LLIPORT),
+			.def  = DEFAULT_LLIPORT,
+			.arg  = { .r = { .min = MIN_LLIPORT,
+					 .max = MAX_LLIPORT } }
+		};
+
+#ifdef module_param_array
+		if (num_LLIPort > bd) {
+#endif
+			adapter->lli_port = LLIPort[bd];
+			if (adapter->lli_port) {
+				txgbe_validate_option(&adapter->lli_port, &opt);
+			} else {
+				DPRINTK(PROBE, INFO, "%s turned off\n",
+					opt.name);
+			}
+#ifdef module_param_array
+		} else {
+			adapter->lli_port = opt.def;
+		}
+#endif
+	}
+	{ /* Low Latency Interrupt on Packet Size */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Low Latency Interrupt on Packet Size",
+			.err  = "using default of "
+					__MODULE_STRING(DEFAULT_LLISIZE),
+			.def  = DEFAULT_LLISIZE,
+			.arg  = { .r = { .min = MIN_LLISIZE,
+					 .max = MAX_LLISIZE } }
+		};
+
+#ifdef module_param_array
+		if (num_LLISize > bd) {
+#endif
+			adapter->lli_size = LLISize[bd];
+			if (adapter->lli_size) {
+				txgbe_validate_option(&adapter->lli_size, &opt);
+			} else {
+				DPRINTK(PROBE, INFO, "%s turned off\n",
+					opt.name);
+			}
+#ifdef module_param_array
+		} else {
+			adapter->lli_size = opt.def;
+		}
+#endif
+	}
+	{ /* Low Latency Interrupt EtherType*/
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Low Latency Interrupt on Ethernet Protocol "
+				"Type",
+			.err  = "using default of "
+					__MODULE_STRING(DEFAULT_LLIETYPE),
+			.def  = DEFAULT_LLIETYPE,
+			.arg  = { .r = { .min = MIN_LLIETYPE,
+					 .max = MAX_LLIETYPE } }
+		};
+
+#ifdef module_param_array
+		if (num_LLIEType > bd) {
+#endif
+			adapter->lli_etype = LLIEType[bd];
+			if (adapter->lli_etype) {
+				txgbe_validate_option(&adapter->lli_etype,
+						      &opt);
+			} else {
+				DPRINTK(PROBE, INFO, "%s turned off\n",
+					opt.name);
+			}
+#ifdef module_param_array
+		} else {
+			adapter->lli_etype = opt.def;
+		}
+#endif
+	}
+	{ /* LLI VLAN Priority */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Low Latency Interrupt on VLAN priority "
+				"threshold",
+			.err  = "using default of "
+					__MODULE_STRING(DEFAULT_LLIVLANP),
+			.def  = DEFAULT_LLIVLANP,
+			.arg  = { .r = { .min = MIN_LLIVLANP,
+					 .max = MAX_LLIVLANP } }
+		};
+
+#ifdef module_param_array
+		if (num_LLIVLANP > bd) {
+#endif
+			adapter->lli_vlan_pri = LLIVLANP[bd];
+			if (adapter->lli_vlan_pri) {
+				txgbe_validate_option(&adapter->lli_vlan_pri,
+						      &opt);
+			} else {
+				DPRINTK(PROBE, INFO, "%s turned off\n",
+					opt.name);
+			}
+#ifdef module_param_array
+		} else {
+			adapter->lli_vlan_pri = opt.def;
+		}
+#endif
+	}
+#endif /* TXGBE_NO_LLI */
+#ifdef HAVE_TX_MQ
+	{ /* Flow Director packet buffer allocation */
+		u32 fdir_pballoc_mode;
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Flow Director packet buffer allocation",
+			.err = "using default of "
+				__MODULE_STRING(TXGBE_DEFAULT_FDIR_PBALLOC),
+			.def = TXGBE_DEFAULT_FDIR_PBALLOC,
+			.arg = {.r = {.min = TXGBE_FDIR_PBALLOC_64K,
+				      .max = TXGBE_FDIR_PBALLOC_256K} }
+		};
+		const char *pstring;
+
+		if (num_FdirPballoc > bd) {
+			fdir_pballoc_mode = FdirPballoc[bd];
+			txgbe_validate_option(&fdir_pballoc_mode, &opt);
+			switch (fdir_pballoc_mode) {
+			case TXGBE_FDIR_PBALLOC_256K:
+				adapter->fdir_pballoc = TXGBE_FDIR_PBALLOC_256K;
+				pstring = "256kB";
+				break;
+			case TXGBE_FDIR_PBALLOC_128K:
+				adapter->fdir_pballoc = TXGBE_FDIR_PBALLOC_128K;
+				pstring = "128kB";
+				break;
+			case TXGBE_FDIR_PBALLOC_64K:
+			default:
+				adapter->fdir_pballoc = TXGBE_FDIR_PBALLOC_64K;
+				pstring = "64kB";
+				break;
+			}
+			DPRINTK(PROBE, INFO, "Flow Director will be allocated "
+				"%s of packet buffer\n", pstring);
+		} else {
+			adapter->fdir_pballoc = opt.def;
+		}
+
+	}
+	{ /* Flow Director ATR Tx sample packet rate */
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Software ATR Tx packet sample rate",
+			.err = "using default of "
+				__MODULE_STRING(TXGBE_DEFAULT_ATR_SAMPLE_RATE),
+			.def = TXGBE_DEFAULT_ATR_SAMPLE_RATE,
+			.arg = {.r = {.min = TXGBE_ATR_SAMPLE_RATE_OFF,
+				      .max = TXGBE_MAX_ATR_SAMPLE_RATE} }
+		};
+		static const char atr_string[] =
+					    "ATR Tx Packet sample rate set to";
+
+		if (num_AtrSampleRate > bd) {
+			adapter->atr_sample_rate = AtrSampleRate[bd];
+
+			if (adapter->atr_sample_rate) {
+				txgbe_validate_option(&adapter->atr_sample_rate,
+						      &opt);
+				DPRINTK(PROBE, INFO, "%s %d\n", atr_string,
+					adapter->atr_sample_rate);
+			}
+		} else {
+			adapter->atr_sample_rate = opt.def;
+		}
+	}
+#endif /* HAVE_TX_MQ */
+#if IS_ENABLED(CONFIG_FCOE)
+	{
+		*aflags &= ~TXGBE_FLAG_FCOE_CAPABLE;
+
+		 {
+			struct txgbe_option opt = {
+				.type = enable_option,
+				.name = "Enabled/Disable FCoE offload",
+				.err = "defaulting to Enabled",
+				.def = OPTION_ENABLED
+			};
+#ifdef module_param_array
+			if (num_FCoE > bd) {
+#endif
+				u32 fcoe = FCoE[bd];
+
+				txgbe_validate_option(&fcoe, &opt);
+				if (fcoe)
+					*aflags |= TXGBE_FLAG_FCOE_CAPABLE;
+#ifdef module_param_array
+			} else {
+				if (opt.def == OPTION_ENABLED)
+					*aflags |= TXGBE_FLAG_FCOE_CAPABLE;
+			}
+#endif
+			DPRINTK(PROBE, INFO, "FCoE Offload feature %sabled\n",
+				(*aflags & TXGBE_FLAG_FCOE_CAPABLE) ?
+				"en" : "dis");
+		}
+
+	}
+#endif /* CONFIG_FCOE */
+	{ /* LRO - Set Large Receive Offload */
+		struct txgbe_option opt = {
+			.type = enable_option,
+			.name = "LRO - Large Receive Offload",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_ENABLED
+		};
+		struct net_device *netdev = adapter->netdev;
+
+#ifdef TXGBE_NO_LRO
+		if (!(adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE))
+			opt.def = OPTION_DISABLED;
+
+#endif
+#ifdef module_param_array
+		if (num_LRO > bd) {
+#endif
+			u32 lro = LRO[bd];
+			txgbe_validate_option(&lro, &opt);
+			if (lro)
+				netdev->features |= NETIF_F_LRO;
+			else
+				netdev->features &= ~NETIF_F_LRO;
+#ifdef module_param_array
+		} else if (opt.def == OPTION_ENABLED) {
+			netdev->features |= NETIF_F_LRO;
+		} else {
+			netdev->features &= ~NETIF_F_LRO;
+		}
+#endif
+#ifdef TXGBE_NO_LRO
+		if ((netdev->features & NETIF_F_LRO) &&
+		    !(adapter->flags2 & TXGBE_FLAG2_RSC_CAPABLE)) {
+			DPRINTK(PROBE, INFO,
+				"RSC is not supported on this "
+				"hardware.  Disabling RSC.\n");
+			netdev->features &= ~NETIF_F_LRO;
+		}
+#endif /* TXGBE_NO_LRO */
+	}
+	{ /*
+	   * allow_unsupported_sfp - Enable/Disable support for unsupported
+	   * and untested SFP+ modules.
+	   */
+	struct txgbe_option opt = {
+			.type = enable_option,
+			.name = "allow_unsupported_sfp",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_DISABLED
+		};
+#ifdef module_param_array
+		if (num_allow_unsupported_sfp > bd) {
+#endif
+			u32 enable_unsupported_sfp =
+						      allow_unsupported_sfp[bd];
+			txgbe_validate_option(&enable_unsupported_sfp, &opt);
+			if (enable_unsupported_sfp) {
+				adapter->hw.allow_unsupported_sfp = true;
+			} else {
+				adapter->hw.allow_unsupported_sfp = false;
+			}
+#ifdef module_param_array
+		} else if (opt.def == OPTION_ENABLED) {
+				adapter->hw.allow_unsupported_sfp = true;
+		} else {
+				adapter->hw.allow_unsupported_sfp = false;
+		}
+#endif
+	}
+
+	{
+	struct txgbe_option opt = {
+			.type = enable_option,
+			.name = "Fdir",
+			.err  = "defaulting to disabled",
+			.def  = OPTION_DISABLED
+		};
+#ifdef module_param_array
+		if (num_Fdir > bd) {
+#endif
+			u32 enable_Fdir = Fdir[bd];
+				txgbe_validate_option(&enable_Fdir, &opt);
+				if (enable_Fdir) {
+					adapter->hw.Fdir_enabled = true;
+				} else {
+					adapter->hw.Fdir_enabled = false;
+				}
+#ifdef module_param_array
+			} else if (opt.def == OPTION_ENABLED) {
+					adapter->hw.Fdir_enabled = true;
+			} else {
+					adapter->hw.Fdir_enabled = false;
+			}
+#endif
+	}
+
+	{ /* DMA Coalescing */
+		struct txgbe_option opt = {
+			.type = range_option,
+			.name = "dmac_watchdog",
+			.err  = "defaulting to 0 (disabled)",
+			.def  = 0,
+			.arg  = { .r = { .min = 41, .max = 10000 } },
+		};
+		const char *cmsg = "DMA coalescing not supported on this "
+				   "hardware";
+
+		opt.err = cmsg;
+		opt.msg = cmsg;
+		opt.arg.r.min = 0;
+		opt.arg.r.max = 0;
+
+#ifdef module_param_array
+		if (num_dmac_watchdog > bd) {
+#endif
+			u32 dmac_wd = dmac_watchdog[bd];
+
+			txgbe_validate_option(&dmac_wd, &opt);
+			adapter->hw.mac.dmac_config.watchdog_timer = (u16)dmac_wd;
+#ifdef module_param_array
+		} else {
+			adapter->hw.mac.dmac_config.watchdog_timer = opt.def;
+		}
+#endif
+	}
+	{ /* VXLAN rx offload */
+		struct txgbe_option opt = {
+			.type = range_option,
+			.name = "vxlan_rx",
+			.err  = "defaulting to 1 (enabled)",
+			.def  = 1,
+			.arg  = { .r = { .min = 0, .max = 1 } },
+		};
+		const char *cmsg = "VXLAN rx offload not supported on this "
+				   "hardware";
+		const u32 flag = TXGBE_FLAG_VXLAN_OFFLOAD_ENABLE;
+
+		if (!(adapter->flags & TXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) {
+			opt.err = cmsg;
+			opt.msg = cmsg;
+			opt.def = 0;
+			opt.arg.r.max = 0;
+		}
+#ifdef module_param_array
+		if (num_vxlan_rx > bd) {
+#endif
+			u32 enable_vxlan_rx = vxlan_rx[bd];
+
+			txgbe_validate_option(&enable_vxlan_rx, &opt);
+			if (enable_vxlan_rx)
+				adapter->flags |= flag;
+			else
+				adapter->flags &= ~flag;
+#ifdef module_param_array
+		} else if (opt.def) {
+			adapter->flags |= flag;
+		} else {
+			adapter->flags &= ~flag;
+		}
+#endif
+	}
+
+	{ /* Rx buffer mode */
+		u32 rx_buf_mode;
+		static struct txgbe_option opt = {
+			.type = range_option,
+			.name = "Rx buffer mode",
+			.err = "using default of "
+				__MODULE_STRING(TXGBE_DEFAULT_RXBUFMODE),
+			.def = TXGBE_DEFAULT_RXBUFMODE,
+			.arg = {.r = {.min = TXGBE_RXBUFMODE_NO_HEADER_SPLIT,
+							.max = TXGBE_RXBUFMODE_HEADER_SPLIT} }
+
+		};
+
+#ifdef module_param_array
+		if (num_RxBufferMode > bd) {
+#endif
+			rx_buf_mode = RxBufferMode[bd];
+			txgbe_validate_option(&rx_buf_mode, &opt);
+			switch (rx_buf_mode) {
+			case TXGBE_RXBUFMODE_NO_HEADER_SPLIT:
+				*aflags &= ~TXGBE_FLAG_RX_HS_ENABLED;
+				break;
+			case TXGBE_RXBUFMODE_HEADER_SPLIT:
+				*aflags |= TXGBE_FLAG_RX_HS_ENABLED;
+				break;
+			default:
+				break;
+			}
+#ifdef module_param_array
+		} else {
+			*aflags &= ~TXGBE_FLAG_RX_HS_ENABLED;
+		}
+#endif
+
+	}
+	{ /* Cloud Switch */
+		struct txgbe_option opt = {
+			.type = range_option,
+			.name = "CloudSwitch",
+			.err  = "defaulting to 0 (disabled)",
+			.def  = 0,
+			.arg  = { .r = { .min = 0, .max = 1 } },
+		};
+
+#ifdef module_param_array
+		if (num_CloudSwitch > bd) {
+#endif
+			u32 enable_cloudswitch = CloudSwitch[bd];
+
+			txgbe_validate_option(&enable_cloudswitch, &opt);
+			if (enable_cloudswitch)
+				adapter->flags |=
+					TXGBE_FLAG2_CLOUD_SWITCH_ENABLED;
+			else
+				adapter->flags &=
+					~TXGBE_FLAG2_CLOUD_SWITCH_ENABLED;
+#ifdef module_param_array
+		} else if (opt.def) {
+			adapter->flags |= TXGBE_FLAG2_CLOUD_SWITCH_ENABLED;
+		} else {
+			adapter->flags &= ~TXGBE_FLAG2_CLOUD_SWITCH_ENABLED;
+		}
+#endif
+	}
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.c
new file mode 100644
index 000000000000..e79474973320
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.c
@@ -0,0 +1,294 @@
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "txgbe_pcierr.h"
+#include "txgbe.h"
+#define TXGBE_ROOT_PORT_INTR_ON_MESG_MASK	(PCI_ERR_ROOT_CMD_COR_EN|	\
+					PCI_ERR_ROOT_CMD_NONFATAL_EN|	\
+					PCI_ERR_ROOT_CMD_FATAL_EN)
+
+#ifndef PCI_ERS_RESULT_NO_AER_DRIVER
+/* No AER capabilities registered for the driver */
+#define PCI_ERS_RESULT_NO_AER_DRIVER ((__force pci_ers_result_t) 6)
+#endif
+
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))
+/* redefinition because centos 6 can't use pci_walk_bus in pci.h*/
+
+struct rw_semaphore pci_bus_sem;
+
+/** pci_walk_bus - walk devices on/under bus, calling callback.
+ *  @top      bus whose devices should be walked
+ *  @cb       callback to be called for each device found
+ *  @userdata arbitrary pointer to be passed to callback.
+ *
+ *  Walk the given bus, including any bridged devices
+ *  on buses under this bus.  Call the provided callback
+ *  on each device found.
+ *
+ *  We check the return of @cb each time. If it returns anything
+ *  other than 0, we break out.
+ *
+ */
+void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
+		  void *userdata)
+{
+	struct pci_dev *dev;
+	struct pci_bus *bus;
+	struct list_head *next;
+	int retval;
+
+	bus = top;
+	down_read(&pci_bus_sem);
+	next = top->devices.next;
+	for (;;) {
+		if (next == &bus->devices) {
+			/* end of this bus, go up or finish */
+			if (bus == top)
+				break;
+			next = bus->self->bus_list.next;
+			bus = bus->self->bus;
+			continue;
+		}
+		dev = list_entry(next, struct pci_dev, bus_list);
+		if (dev->subordinate) {
+			/* this is a pci-pci bridge, do its devices next */
+			next = dev->subordinate->devices.next;
+			bus = dev->subordinate;
+		} else
+			next = dev->bus_list.next;
+
+		retval = cb(dev, userdata);
+		if (retval)
+			break;
+	}
+	up_read(&pci_bus_sem);
+}
+#endif
+
+static pci_ers_result_t merge_result(enum pci_ers_result orig,
+						  enum pci_ers_result new)
+{
+	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
+		return PCI_ERS_RESULT_NO_AER_DRIVER;
+	if (new == PCI_ERS_RESULT_NONE)
+		return orig;
+	switch (orig) {
+	case PCI_ERS_RESULT_CAN_RECOVER:
+	case PCI_ERS_RESULT_RECOVERED:
+		orig = new;
+		break;
+	case PCI_ERS_RESULT_DISCONNECT:
+		if (new == PCI_ERS_RESULT_NEED_RESET)
+			orig = PCI_ERS_RESULT_NEED_RESET;
+		break;
+	default:
+		break;
+	}
+	return orig;
+}
+
+static int txgbe_report_error_detected(struct pci_dev *dev,
+				 pci_channel_state_t state,
+				 enum pci_ers_result *result)
+{
+	pci_ers_result_t vote;
+	const struct pci_error_handlers *err_handler;
+
+	device_lock(&dev->dev);
+	if (
+		!dev->driver ||
+		!dev->driver->err_handler ||
+		!dev->driver->err_handler->error_detected) {
+		/*
+		 * If any device in the subtree does not have an error_detected
+		 * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
+		 * error callbacks of "any" device in the subtree, and will
+		 * exit in the disconnected error state.
+		 */
+		if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+			vote = PCI_ERS_RESULT_NO_AER_DRIVER;
+		else
+			vote = PCI_ERS_RESULT_NONE;
+	} else {
+		err_handler = dev->driver->err_handler;
+		vote = err_handler->error_detected(dev, state);
+	}
+
+	*result = merge_result(*result, vote);
+	device_unlock(&dev->dev);
+	return 0;
+}
+
+static int txgbe_report_frozen_detected(struct pci_dev *dev, void *data)
+{
+	return txgbe_report_error_detected(dev, pci_channel_io_frozen, data);
+}
+
+static int txgbe_report_mmio_enabled(struct pci_dev *dev, void *data)
+{
+	pci_ers_result_t vote, *result = data;
+	const struct pci_error_handlers *err_handler;
+
+	device_lock(&dev->dev);
+	if (!dev->driver ||
+		!dev->driver->err_handler ||
+		!dev->driver->err_handler->mmio_enabled)
+		goto out;
+
+	err_handler = dev->driver->err_handler;
+	vote = err_handler->mmio_enabled(dev);
+	*result = merge_result(*result, vote);
+out:
+	device_unlock(&dev->dev);
+	return 0;
+}
+
+static int txgbe_report_slot_reset(struct pci_dev *dev, void *data)
+{
+	pci_ers_result_t vote, *result = data;
+	const struct pci_error_handlers *err_handler;
+
+	device_lock(&dev->dev);
+	if (!dev->driver ||
+		!dev->driver->err_handler ||
+		!dev->driver->err_handler->slot_reset)
+		goto out;
+
+	err_handler = dev->driver->err_handler;
+	vote = err_handler->slot_reset(dev);
+	*result = merge_result(*result, vote);
+out:
+	device_unlock(&dev->dev);
+	return 0;
+}
+
+static int txgbe_report_resume(struct pci_dev *dev, void *data)
+{
+	const struct pci_error_handlers *err_handler;
+
+	device_lock(&dev->dev);
+	dev->error_state = pci_channel_io_normal;
+	if (
+		!dev->driver ||
+		!dev->driver->err_handler ||
+		!dev->driver->err_handler->resume)
+		goto out;
+
+	err_handler = dev->driver->err_handler;
+	err_handler->resume(dev);
+out:
+	device_unlock(&dev->dev);
+	return 0;
+}
+
+
+void txgbe_pcie_do_recovery(struct pci_dev *dev)
+{
+	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
+	struct pci_bus *bus;
+	u32 reg32;
+	int pos;
+	int delay = 1;
+	u32 id;
+	u16 ctrl;
+	/*
+	 * Error recovery runs on all subordinates of the first downstream port.
+	 * If the downstream port detected the error, it is cleared at the end.
+	 */
+	if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+	      pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
+		dev = dev->bus->self;
+	bus = dev->subordinate;
+
+	pci_walk_bus(bus, txgbe_report_frozen_detected, &status);
+	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ 	if (pos) {			
+		/* Disable Root's interrupt in response to error messages */
+		pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
+		reg32 &= ~TXGBE_ROOT_PORT_INTR_ON_MESG_MASK;
+		pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
+	}
+
+	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+	ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+	/*
+	 * 	 * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms.  Double
+	 * 	 * this to 2ms to ensure that we meet the minimum requirement.
+	 * 	 */
+
+	msleep(2);
+	ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+	/*
+	 * 	 * Trhfa for conventional PCI is 2^25 clock cycles.
+	 * 	 * Assuming a minimum 33MHz clock this results in a 1s
+	 * 	 * delay before we can consider subordinate devices to
+	 * 	 * be re-initialized.  PCIe has some ways to shorten this,
+	 * 	 * but we don't make use of them yet.
+	 * 	 */				
+	ssleep(1);
+
+	pci_read_config_dword(dev, PCI_COMMAND, &id);
+	while (id == ~0) {
+		if (delay > 60000) {
+			pci_warn(dev, "not ready %dms after %s; giving up\n",
+				 delay - 1, "bus_reset");
+		 		return;
+		}
+
+		if (delay > 1000)
+			pci_info(dev, "not ready %dms after %s; waiting\n",
+				 delay - 1, "bus_reset");
+							
+		msleep(delay);
+		delay *= 2;
+		pci_read_config_dword(dev, PCI_COMMAND, &id);
+	}
+
+	if (delay > 1000)
+		pci_info(dev, "ready %dms after %s\n", delay - 1,
+				 "bus_reset");
+
+	pci_info(dev, "Root Port link has been reset\n");
+
+	if (pos) {
+	/* Clear Root Error Status */
+	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
+
+	/* Enable Root Port's interrupt in response to error messages */
+	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
+	reg32 |= TXGBE_ROOT_PORT_INTR_ON_MESG_MASK;
+	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
+	}
+	
+	if (status == PCI_ERS_RESULT_CAN_RECOVER) {
+		status = PCI_ERS_RESULT_RECOVERED;
+		pci_dbg(dev, "broadcast mmio_enabled message\n");
+		pci_walk_bus(bus, txgbe_report_mmio_enabled, &status);
+	}
+
+	if (status == PCI_ERS_RESULT_NEED_RESET) {
+		/*
+		 * TODO: Should call platform-specific
+		 * functions to reset slot before calling
+		 * drivers' slot_reset callbacks?
+		 */
+		status = PCI_ERS_RESULT_RECOVERED;
+		pci_dbg(dev, "broadcast slot_reset message\n");
+		pci_walk_bus(bus, txgbe_report_slot_reset, &status);
+	}
+
+	if (status != PCI_ERS_RESULT_RECOVERED)
+		goto failed;
+
+	pci_dbg(dev, "broadcast resume message\n");
+	pci_walk_bus(bus, txgbe_report_resume, &status);	
+	
+failed:
+	;
+}
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.h
new file mode 100644
index 000000000000..545e9bbea9da
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_pcierr.h
@@ -0,0 +1,6 @@
+#ifndef _TXGBE_PCIERR_H_
+#define _TXGBE_PCIERR_H_
+
+void txgbe_pcie_do_recovery(struct pci_dev *dev);
+#endif
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
new file mode 100644
index 000000000000..5f7b8f733e9c
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -0,0 +1,1165 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_phy.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+#include "txgbe_phy.h"
+#include "txgbe_mtd.h"
+
+/**
+ * txgbe_check_reset_blocked - check status of MNG FW veto bit
+ * @hw: pointer to the hardware structure
+ *
+ * This function checks the MMNGC.MNG_VETO bit to see if there are
+ * any constraints on link from manageability.  For MAC's that don't
+ * have this bit just return faluse since the link can not be blocked
+ * via this method.
+ **/
+s32 txgbe_check_reset_blocked(struct txgbe_hw *hw)
+{
+	u32 mmngc;
+
+	mmngc = rd32(hw, TXGBE_MIS_ST);
+	if (mmngc & TXGBE_MIS_ST_MNG_VETO) {
+		ERROR_REPORT1(TXGBE_ERROR_SOFTWARE,
+			      "MNG_VETO bit detected.\n");
+		return true;
+	}
+
+	return false;
+}
+
+
+/**
+ *  txgbe_get_phy_id - Get the phy type
+ *  @hw: pointer to hardware structure
+ *
+ **/
+s32 txgbe_get_phy_id(struct txgbe_hw *hw)
+{
+	u32 status;
+	u16 phy_id_high = 0;
+	u16 phy_id_low = 0;
+	u8 numport, thisport;
+
+	status = mtdHwXmdioRead(&hw->phy_dev, hw->phy.addr,
+				TXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				TXGBE_MDIO_PHY_ID_HIGH, &phy_id_high);
+
+	if (status == 0) {
+		hw->phy.id = (u32)(phy_id_high << 16);
+		status = mtdHwXmdioRead(&hw->phy_dev, hw->phy.addr,
+				TXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				TXGBE_MDIO_PHY_ID_LOW, &phy_id_low);
+		hw->phy.id |= (u32)(phy_id_low & TXGBE_PHY_REVISION_MASK);
+	}
+
+	if (status == 0) {
+		status = mtdGetPhyRevision(&hw->phy_dev, hw->phy.addr,
+			(MTD_DEVICE_ID *)&hw->phy.revision, &numport, &thisport);
+		if (status == MTD_FAIL) {
+			ERROR_REPORT1(TXGBE_ERROR_INVALID_STATE,
+				 "Error in mtdGetPhyRevision()\n");
+		}
+	}
+	return status;
+}
+
+/**
+ *  txgbe_get_phy_type_from_id - Get the phy type
+ *  @phy_id: PHY ID information
+ *
+ **/
+enum txgbe_phy_type txgbe_get_phy_type_from_id(struct txgbe_hw *hw)
+{
+	enum txgbe_phy_type phy_type;
+	u16 ext_ability = 0;
+
+	switch (hw->phy.id) {
+	case TN1010_PHY_ID:
+		phy_type = txgbe_phy_tn;
+		break;
+	case QT2022_PHY_ID:
+		phy_type = txgbe_phy_qt;
+		break;
+	case ATH_PHY_ID:
+		phy_type = txgbe_phy_nl;
+		break;
+	default:
+		phy_type = txgbe_phy_unknown;
+		break;
+	}
+	if (phy_type == txgbe_phy_unknown) {
+		mtdHwXmdioRead(&hw->phy_dev, hw->phy.addr,
+				TXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				TXGBE_MDIO_PHY_EXT_ABILITY, &ext_ability);
+
+		if (ext_ability & (TXGBE_MDIO_PHY_10GBASET_ABILITY |
+			TXGBE_MDIO_PHY_1000BASET_ABILITY))
+			phy_type = txgbe_phy_cu_unknown;
+		else
+			phy_type = txgbe_phy_generic;
+	}
+	return phy_type;
+}
+
+/**
+ *  txgbe_reset_phy - Performs a PHY reset
+ *  @hw: pointer to hardware structure
+ **/
+s32 txgbe_reset_phy(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+
+	if (status != 0 || hw->phy.type == txgbe_phy_none)
+		goto out;
+
+	/* Don't reset PHY if it's shut down due to overtemp. */
+	if (!hw->phy.reset_if_overtemp &&
+	    (TXGBE_ERR_OVERTEMP == TCALL(hw, phy.ops.check_overtemp)))
+		goto out;
+
+	/* Blocked by MNG FW so bail */
+	txgbe_check_reset_blocked(hw);
+	if(((hw->subsystem_device_id & TXGBE_NCSI_MASK) == TXGBE_NCSI_SUP)||
+		((hw->subsystem_device_id & TXGBE_WOL_MASK) == TXGBE_WOL_SUP))
+		goto out;
+
+	status = mtdHardwareReset(&hw->phy_dev, hw->phy.addr, 1000);
+
+out:
+	return status;
+}
+
+/**
+ *  txgbe_read_phy_mdi - Reads a value from a specified PHY register without
+ *  the SWFW lock
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit address of PHY register to read
+ *  @phy_data: Pointer to read data from PHY register
+ **/
+s32 txgbe_read_phy_reg_mdi(struct txgbe_hw *hw, u32 reg_addr, u32 device_type,
+		       u16 *phy_data)
+{
+	u32 command;
+	s32 status = 0;
+
+	/* setup and write the address cycle command */
+	command = TXGBE_MSCA_RA(reg_addr) |
+		TXGBE_MSCA_PA(hw->phy.addr) |
+		TXGBE_MSCA_DA(device_type);
+	wr32(hw, TXGBE_MSCA, command);
+
+	command = TXGBE_MSCC_CMD(TXGBE_MSCA_CMD_READ) | TXGBE_MSCC_BUSY;
+	wr32(hw, TXGBE_MSCC, command);
+
+	/* wait to complete */
+	status = po32m(hw, TXGBE_MSCC,
+		TXGBE_MSCC_BUSY, ~TXGBE_MSCC_BUSY,
+		TXGBE_MDIO_TIMEOUT, 10);
+	if (status != 0) {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			      "PHY address command did not complete.\n");
+		return TXGBE_ERR_PHY;
+	}
+
+	/* read data from MSCC */
+	*phy_data = 0xFFFF & rd32(hw, TXGBE_MSCC);
+
+	return 0;
+}
+
+/**
+ *  txgbe_read_phy_reg - Reads a value from a specified PHY register
+ *  using the SWFW lock - this function is needed in most cases
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit address of PHY register to read
+ *  @phy_data: Pointer to read data from PHY register
+ **/
+s32 txgbe_read_phy_reg(struct txgbe_hw *hw, u32 reg_addr,
+			       u32 device_type, u16 *phy_data)
+{
+	s32 status;
+	u32 gssr = hw->phy.phy_semaphore_mask;
+
+	if (0 == TCALL(hw, mac.ops.acquire_swfw_sync, gssr)) {
+		status = txgbe_read_phy_reg_mdi(hw, reg_addr, device_type,
+						phy_data);
+		TCALL(hw, mac.ops.release_swfw_sync, gssr);
+	} else {
+		status = TXGBE_ERR_SWFW_SYNC;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_write_phy_reg_mdi - Writes a value to specified PHY register
+ *  without SWFW lock
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 5 bit device type
+ *  @phy_data: Data to write to the PHY register
+ **/
+s32 txgbe_write_phy_reg_mdi(struct txgbe_hw *hw, u32 reg_addr,
+				u32 device_type, u16 phy_data)
+{
+	u32 command;
+	s32 status = 0;
+
+	/* setup and write the address cycle command */
+	command = TXGBE_MSCA_RA(reg_addr) |
+		TXGBE_MSCA_PA(hw->phy.addr) |
+		TXGBE_MSCA_DA(device_type);
+	wr32(hw, TXGBE_MSCA, command);
+
+	command = phy_data | TXGBE_MSCC_CMD(TXGBE_MSCA_CMD_WRITE) |
+		  TXGBE_MSCC_BUSY;
+	wr32(hw, TXGBE_MSCC, command);
+
+	/* wait to complete */
+	status = po32m(hw, TXGBE_MSCC,
+		TXGBE_MSCC_BUSY, ~TXGBE_MSCC_BUSY,
+		TXGBE_MDIO_TIMEOUT, 10);
+	if (status != 0) {
+		ERROR_REPORT1(TXGBE_ERROR_POLLING,
+			      "PHY address command did not complete.\n");
+		return TXGBE_ERR_PHY;
+	}
+
+	return 0;
+}
+
+/**
+ *  txgbe_write_phy_reg - Writes a value to specified PHY register
+ *  using SWFW lock- this function is needed in most cases
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 5 bit device type
+ *  @phy_data: Data to write to the PHY register
+ **/
+s32 txgbe_write_phy_reg(struct txgbe_hw *hw, u32 reg_addr,
+				u32 device_type, u16 phy_data)
+{
+	s32 status;
+	u32 gssr = hw->phy.phy_semaphore_mask;
+
+	if (TCALL(hw, mac.ops.acquire_swfw_sync, gssr) == 0) {
+		status = txgbe_write_phy_reg_mdi(hw, reg_addr, device_type,
+						 phy_data);
+		TCALL(hw, mac.ops.release_swfw_sync, gssr);
+	} else {
+		status = TXGBE_ERR_SWFW_SYNC;
+	}
+
+	return status;
+}
+
+MTD_STATUS txgbe_read_mdio(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 *value)
+{
+	struct txgbe_hw *hw = (struct txgbe_hw *)(dev->appData);
+
+	if (hw->phy.addr != port)
+		return MTD_FAIL;
+	return txgbe_read_phy_reg(hw, reg, mmd, value);
+}
+
+MTD_STATUS txgbe_write_mdio(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 value)
+{
+	struct txgbe_hw *hw = (struct txgbe_hw *)(dev->appData);
+
+	if (hw->phy.addr != port)
+		return MTD_FAIL;
+
+	return txgbe_write_phy_reg(hw, reg, mmd, value);
+}
+
+/*
+MTD_SEM txgbe_sem_create(MTD_SEM_BEGIN_STATE state)
+{
+	sema_init(struct semaphore * sem,int val)
+		mutex_init(mutex)
+}
+*/
+
+/**
+ *  txgbe_setup_phy_link - Set and restart auto-neg
+ *  @hw: pointer to hardware structure
+ *
+ *  Restart auto-negotiation and PHY and waits for completion.
+ **/
+u32 txgbe_setup_phy_link(struct txgbe_hw *hw, u32 speed_set, bool autoneg_wait_to_complete)
+{
+	u16 speed = MTD_ADV_NONE;
+	MTD_DEV_PTR devptr = &hw->phy_dev;
+	u16 port = hw->phy.addr;
+	int i = 0;
+	MTD_BOOL linkUp = MTD_FALSE;
+	u16 linkSpeed = MTD_ADV_NONE;
+
+	if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10GB_FULL)
+		speed |= MTD_SPEED_10GIG_FD;
+	if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_1GB_FULL)
+		speed |= MTD_SPEED_1GIG_FD;
+	if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_100_FULL)
+		speed |= MTD_SPEED_100M_FD;
+	if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10_FULL)
+		speed |= MTD_SPEED_10M_FD;
+	if (!autoneg_wait_to_complete) {
+		mtdGetAutonegSpeedDuplexResolution(devptr, port, &linkSpeed);
+		if (linkSpeed & speed) {
+			speed = linkSpeed;
+			goto out;
+		}
+	}
+
+	mtdEnableSpeeds(devptr, port, speed, MTD_TRUE);
+	msleep(10); 
+	speed = MTD_ADV_NONE;
+	for (i = 0; i < 300; i++) {
+		mtdIsBaseTUp(devptr, port ,&speed, &linkUp);
+		if (linkUp) {
+			break;
+		}
+		msleep(10);
+	}
+
+out:
+	switch (speed) {
+	case MTD_SPEED_10GIG_FD:
+		return TXGBE_LINK_SPEED_10GB_FULL;
+	case MTD_SPEED_1GIG_FD:
+		return TXGBE_LINK_SPEED_1GB_FULL;
+	case MTD_SPEED_100M_FD:
+		return TXGBE_LINK_SPEED_100_FULL;
+	case MTD_SPEED_10M_FD:
+		return TXGBE_LINK_SPEED_10_FULL;
+	default:
+		return TXGBE_LINK_SPEED_UNKNOWN;
+	}
+
+}
+
+/**
+ *  txgbe_setup_phy_link_speed - Sets the auto advertised capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ **/
+u32 txgbe_setup_phy_link_speed(struct txgbe_hw *hw,
+				       u32 speed,
+				       bool autoneg_wait_to_complete)
+{
+	/*
+	 * Clear autoneg_advertised and set new values based on input link
+	 * speed.
+	 */
+	hw->phy.autoneg_advertised = 0;
+
+	if (speed & TXGBE_LINK_SPEED_10GB_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10GB_FULL;
+
+	if (speed & TXGBE_LINK_SPEED_1GB_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_1GB_FULL;
+
+	if (speed & TXGBE_LINK_SPEED_100_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_100_FULL;
+
+	if (speed & TXGBE_LINK_SPEED_10_FULL)
+		hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10_FULL;
+
+	/* Setup link based on the new speed settings */
+	return txgbe_setup_phy_link(hw, speed, autoneg_wait_to_complete);
+}
+
+/**
+ *  txgbe_get_copper_link_capabilities - Determines link capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: boolean auto-negotiation value
+ *
+ *  Determines the supported link capabilities by reading the PHY auto
+ *  negotiation register.
+ **/
+s32 txgbe_get_copper_link_capabilities(struct txgbe_hw *hw,
+					       u32 *speed,
+					       bool *autoneg)
+{
+	s32 status;
+	u16 speed_ability;
+	*speed = 0;
+	*autoneg = true;
+
+	status = mtdHwXmdioRead(&hw->phy_dev, hw->phy.addr,
+				TXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				TXGBE_MDIO_PHY_SPEED_ABILITY, &speed_ability);
+
+	if (status == 0) {
+		if (speed_ability & TXGBE_MDIO_PHY_SPEED_10G)
+			*speed |= TXGBE_LINK_SPEED_10GB_FULL;
+		if (speed_ability & TXGBE_MDIO_PHY_SPEED_1G)
+			*speed |= TXGBE_LINK_SPEED_1GB_FULL;
+		if (speed_ability & TXGBE_MDIO_PHY_SPEED_100M)
+			*speed |= TXGBE_LINK_SPEED_100_FULL;
+		if (speed_ability & TXGBE_MDIO_PHY_SPEED_10M)
+			*speed |= TXGBE_LINK_SPEED_10_FULL;
+	}
+
+	return status;
+}
+
+
+/**
+ *  txgbe_get_phy_firmware_version - Gets the PHY Firmware Version
+ *  @hw: pointer to hardware structure
+ *  @firmware_version: pointer to the PHY Firmware Version
+ **/
+s32 txgbe_get_phy_firmware_version(struct txgbe_hw *hw,
+					   u16 *firmware_version)
+{
+	s32 status;
+	u8 major, minor, inc, test;
+
+	status = mtdGetFirmwareVersion(&hw->phy_dev, hw->phy.addr,
+		&major, &minor, &inc, &test);
+	if (status == 0)
+		*firmware_version = (major << 8) | minor;
+	return status;
+}
+
+/**
+ *  txgbe_identify_module - Identifies module type
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines HW type and calls appropriate function.
+ **/
+s32 txgbe_identify_module(struct txgbe_hw *hw)
+{
+	s32 status = TXGBE_ERR_SFP_NOT_PRESENT;
+
+	switch (TCALL(hw, mac.ops.get_media_type)) {
+	case txgbe_media_type_fiber:
+		status = txgbe_identify_sfp_module(hw);
+		break;
+
+	default:
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+		status = TXGBE_ERR_SFP_NOT_PRESENT;
+		break;
+	}
+
+	return status;
+}
+
+/**
+ *  txgbe_identify_sfp_module - Identifies SFP modules
+ *  @hw: pointer to hardware structure
+ *
+ *  Searches for and identifies the SFP module and assigns appropriate PHY type.
+ **/
+s32 txgbe_identify_sfp_module(struct txgbe_hw *hw)
+{
+	s32 status = TXGBE_ERR_PHY_ADDR_INVALID;
+	u32 vendor_oui = 0;
+	enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
+	u8 identifier = 0;
+	u8 comp_codes_1g = 0;
+	u8 comp_codes_10g = 0;
+	u8 oui_bytes[3] = {0, 0, 0};
+	u8 cable_tech = 0;
+	u8 cable_spec = 0;
+
+	if (TCALL(hw, mac.ops.get_media_type) != txgbe_media_type_fiber) {
+		hw->phy.sfp_type = txgbe_sfp_type_not_present;
+		status = TXGBE_ERR_SFP_NOT_PRESENT;
+		goto out;
+	}
+
+	/* LAN ID is needed for I2C access */
+	txgbe_init_i2c(hw);
+	status = TCALL(hw, phy.ops.read_i2c_eeprom,
+					     TXGBE_SFF_IDENTIFIER,
+					     &identifier);
+
+	if (status != 0)
+		goto err_read_i2c_eeprom;
+
+	if (identifier != TXGBE_SFF_IDENTIFIER_SFP) {
+		hw->phy.type = txgbe_phy_sfp_unsupported;
+		status = TXGBE_ERR_SFP_NOT_SUPPORTED;
+	} else {
+		status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						     TXGBE_SFF_1GBE_COMP_CODES,
+						     &comp_codes_1g);
+
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						     TXGBE_SFF_10GBE_COMP_CODES,
+						     &comp_codes_10g);
+
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+		status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						     TXGBE_SFF_CABLE_TECHNOLOGY,
+						     &cable_tech);
+
+		if (status != 0)
+			goto err_read_i2c_eeprom;
+
+		 /* ID Module
+		  * =========
+		  * 0   SFP_DA_CU
+		  * 1   SFP_SR
+		  * 2   SFP_LR
+		  * 3   SFP_DA_CORE0
+		  * 4   SFP_DA_CORE1
+		  * 5   SFP_SR/LR_CORE0
+		  * 6   SFP_SR/LR_CORE1
+		  * 7   SFP_act_lmt_DA_CORE0
+		  * 8   SFP_act_lmt_DA_CORE1
+		  * 9   SFP_1g_cu_CORE0
+		  * 10  SFP_1g_cu_CORE1
+		  * 11  SFP_1g_sx_CORE0
+		  * 12  SFP_1g_sx_CORE1
+		  */
+		{
+			if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						     txgbe_sfp_type_da_cu_core0;
+				else
+					hw->phy.sfp_type =
+						     txgbe_sfp_type_da_cu_core1;
+			} else if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE) {
+				TCALL(hw, phy.ops.read_i2c_eeprom,
+						TXGBE_SFF_CABLE_SPEC_COMP,
+						&cable_spec);
+				if (cable_spec &
+				    TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
+					if (hw->bus.lan_id == 0)
+						hw->phy.sfp_type =
+						txgbe_sfp_type_da_act_lmt_core0;
+					else
+						hw->phy.sfp_type =
+						txgbe_sfp_type_da_act_lmt_core1;
+				} else {
+					hw->phy.sfp_type =
+							txgbe_sfp_type_unknown;
+				}
+			} else if (comp_codes_10g &
+				   (TXGBE_SFF_10GBASESR_CAPABLE |
+				    TXGBE_SFF_10GBASELR_CAPABLE)) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						      txgbe_sfp_type_srlr_core0;
+				else
+					hw->phy.sfp_type =
+						      txgbe_sfp_type_srlr_core1;
+			} else if (comp_codes_1g & TXGBE_SFF_1GBASET_CAPABLE) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_cu_core0;
+				else
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_cu_core1;
+			} else if (comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_sx_core0;
+				else
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_sx_core1;
+			} else if (comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) {
+				if (hw->bus.lan_id == 0)
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_lx_core0;
+				else
+					hw->phy.sfp_type =
+						txgbe_sfp_type_1g_lx_core1;
+			} else {
+				hw->phy.sfp_type = txgbe_sfp_type_unknown;
+			}
+		}
+
+		if (hw->phy.sfp_type != stored_sfp_type)
+			hw->phy.sfp_setup_needed = true;
+
+		/* Determine if the SFP+ PHY is dual speed or not. */
+		hw->phy.multispeed_fiber = false;
+		if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) &&
+		   (comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) ||
+		   ((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) &&
+		   (comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE)))
+			hw->phy.multispeed_fiber = true;
+
+		/* Determine PHY vendor */
+		if (hw->phy.type != txgbe_phy_nl) {
+			hw->phy.id = identifier;
+			status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						    TXGBE_SFF_VENDOR_OUI_BYTE0,
+						    &oui_bytes[0]);
+
+			if (status != 0)
+				goto err_read_i2c_eeprom;
+
+			status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						    TXGBE_SFF_VENDOR_OUI_BYTE1,
+						    &oui_bytes[1]);
+
+			if (status != 0)
+				goto err_read_i2c_eeprom;
+
+			status = TCALL(hw, phy.ops.read_i2c_eeprom,
+						    TXGBE_SFF_VENDOR_OUI_BYTE2,
+						    &oui_bytes[2]);
+
+			if (status != 0)
+				goto err_read_i2c_eeprom;
+
+			vendor_oui =
+			  ((oui_bytes[0] << TXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
+			   (oui_bytes[1] << TXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
+			   (oui_bytes[2] << TXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
+
+			switch (vendor_oui) {
+			case TXGBE_SFF_VENDOR_OUI_TYCO:
+				if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE)
+					hw->phy.type =
+						    txgbe_phy_sfp_passive_tyco;
+				break;
+			case TXGBE_SFF_VENDOR_OUI_FTL:
+				if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE)
+					hw->phy.type = txgbe_phy_sfp_ftl_active;
+				else
+					hw->phy.type = txgbe_phy_sfp_ftl;
+				break;
+			case TXGBE_SFF_VENDOR_OUI_AVAGO:
+				hw->phy.type = txgbe_phy_sfp_avago;
+				break;
+			case TXGBE_SFF_VENDOR_OUI_INTEL:
+				hw->phy.type = txgbe_phy_sfp_intel;
+				break;
+			default:
+				if (cable_tech & TXGBE_SFF_DA_PASSIVE_CABLE)
+					hw->phy.type =
+						 txgbe_phy_sfp_passive_unknown;
+				else if (cable_tech & TXGBE_SFF_DA_ACTIVE_CABLE)
+					hw->phy.type =
+						txgbe_phy_sfp_active_unknown;
+				else
+					hw->phy.type = txgbe_phy_sfp_unknown;
+				break;
+			}
+		}
+
+		/* Allow any DA cable vendor */
+		if (cable_tech & (TXGBE_SFF_DA_PASSIVE_CABLE |
+		    TXGBE_SFF_DA_ACTIVE_CABLE)) {
+			status = 0;
+			goto out;
+		}
+
+		/* Verify supported 1G SFP modules */
+		if (comp_codes_10g == 0 &&
+		    !(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 ||
+		      hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) {
+			hw->phy.type = txgbe_phy_sfp_unsupported;
+			status = TXGBE_ERR_SFP_NOT_SUPPORTED;
+			goto out;
+		}
+	}
+
+out:
+	return status;
+
+err_read_i2c_eeprom:
+	hw->phy.sfp_type = txgbe_sfp_type_not_present;
+	if (hw->phy.type != txgbe_phy_nl) {
+		hw->phy.id = 0;
+		hw->phy.type = txgbe_phy_unknown;
+	}
+	return TXGBE_ERR_SFP_NOT_PRESENT;
+}
+
+s32 txgbe_init_i2c(struct txgbe_hw *hw)
+{
+
+	wr32(hw, TXGBE_I2C_ENABLE, 0);
+
+	wr32(hw, TXGBE_I2C_CON,
+		(TXGBE_I2C_CON_MASTER_MODE |
+		TXGBE_I2C_CON_SPEED(1) |
+		TXGBE_I2C_CON_RESTART_EN |
+		TXGBE_I2C_CON_SLAVE_DISABLE));
+	/* Default addr is 0xA0 ,bit 0 is configure for read/write! */
+	wr32(hw, TXGBE_I2C_TAR, TXGBE_I2C_SLAVE_ADDR);
+	wr32(hw, TXGBE_I2C_SS_SCL_HCNT, 600);
+	wr32(hw, TXGBE_I2C_SS_SCL_LCNT, 600);
+	wr32(hw, TXGBE_I2C_RX_TL, 0); /* 1byte for rx full signal */
+	wr32(hw, TXGBE_I2C_TX_TL, 4);
+	
+	wr32(hw, TXGBE_I2C_SCL_STUCK_TIMEOUT, 0xFFFFFF);
+	wr32(hw, TXGBE_I2C_SDA_STUCK_TIMEOUT, 0xFFFFFF);
+
+	wr32(hw, TXGBE_I2C_INTR_MASK, 0);
+	wr32(hw, TXGBE_I2C_ENABLE, 1);
+	return 0;
+}
+
+STATIC s32 txgbe_init_i2c_sfp_phy(struct txgbe_hw *hw)
+{
+
+	wr32(hw, TXGBE_I2C_ENABLE, 0);
+
+	wr32(hw, TXGBE_I2C_CON,
+		(TXGBE_I2C_CON_MASTER_MODE |
+		TXGBE_I2C_CON_SPEED(1) |
+		TXGBE_I2C_CON_RESTART_EN |
+		TXGBE_I2C_CON_SLAVE_DISABLE));
+	/* Default addr is 0xA0 ,bit 0 is configure for read/write! */
+	wr32(hw, TXGBE_I2C_TAR, TXGBE_I2C_SLAVE_ADDR);
+	wr32(hw, TXGBE_I2C_SS_SCL_HCNT, 600);
+	wr32(hw, TXGBE_I2C_SS_SCL_LCNT, 600);
+
+	wr32(hw, TXGBE_I2C_RX_TL, 1); /* 2bytes for rx full signal */
+	wr32(hw, TXGBE_I2C_TX_TL, 4);
+	
+	wr32(hw, TXGBE_I2C_SCL_STUCK_TIMEOUT, 0xFFFFFF);
+	wr32(hw, TXGBE_I2C_SDA_STUCK_TIMEOUT, 0xFFFFFF);
+
+	wr32(hw, TXGBE_I2C_INTR_MASK, 0);
+	wr32(hw, TXGBE_I2C_ENABLE, 1);
+	return 0;
+}
+
+
+s32 txgbe_clear_i2c(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+
+	/* wait for completion */
+	status = po32m(hw, TXGBE_I2C_STATUS,
+		TXGBE_I2C_STATUS_MST_ACTIVITY, ~TXGBE_I2C_STATUS_MST_ACTIVITY,
+		TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+		goto out;
+
+	wr32(hw, TXGBE_I2C_ENABLE, 0);
+
+out:
+	return status;
+}
+
+/**
+ *  txgbe_read_i2c_eeprom - Reads 8 bit EEPROM word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to read
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
+				  u8 *eeprom_data)
+{
+	txgbe_init_i2c(hw);
+	return TCALL(hw, phy.ops.read_i2c_byte, byte_offset,
+					 TXGBE_I2C_EEPROM_DEV_ADDR,
+					 eeprom_data);
+}
+
+/**
+ *  txgbe_read_i2c_sff8472 - Reads 8 bit word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset at address 0xA2
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+s32 txgbe_read_i2c_sff8472(struct txgbe_hw *hw, u8 byte_offset,
+					  u8 *sff8472_data)
+{
+	txgbe_init_i2c(hw);
+	return TCALL(hw, phy.ops.read_i2c_byte, byte_offset,
+					 TXGBE_I2C_EEPROM_DEV_ADDR2,
+					 sff8472_data);
+}
+					  
+/**
+ *  txgbe_read_i2c_sfp_phy - Reads 16 bit word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset at address 0xAC
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to Fiber to Copper SFP module 
+ *  internal phy over I2C
+ **/
+s32 txgbe_read_i2c_sfp_phy(struct txgbe_hw *hw, u16 byte_offset,
+					  u16 *avago_data)
+{
+	txgbe_init_i2c_sfp_phy(hw);
+
+	return txgbe_read_i2c_2bytes(hw, byte_offset,
+					 TXGBE_I2C_EEPROM_DEV_ADDR3,
+					 avago_data);
+}
+
+/**
+ *  txgbe_write_i2c_eeprom - Writes 8 bit EEPROM word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to write
+ *  @eeprom_data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface.
+ **/
+s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
+				   u8 eeprom_data)
+{
+	txgbe_init_i2c(hw);
+	return TCALL(hw, phy.ops.write_i2c_byte, byte_offset,
+					  TXGBE_I2C_EEPROM_DEV_ADDR,
+					  eeprom_data);
+}
+
+/**
+ *  txgbe_read_i2c_byte_int - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *  @lock: true if to take and release semaphore
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+STATIC s32 txgbe_read_i2c_byte_int(struct txgbe_hw *hw, u8 byte_offset,
+					   u8 dev_addr, u8 *data, bool lock)
+{
+	s32 status = 0;
+	u32 swfw_mask = hw->phy.phy_semaphore_mask;
+
+	UNREFERENCED_PARAMETER(dev_addr);
+
+	if (lock && 0 != TCALL(hw, mac.ops.acquire_swfw_sync, swfw_mask))
+		return TXGBE_ERR_SWFW_SYNC;
+
+	/* wait tx empty */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+		TXGBE_I2C_INTR_STAT_TX_EMPTY, TXGBE_I2C_INTR_STAT_TX_EMPTY,
+		TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+		goto out;
+
+	/* read data */
+	wr32(hw, TXGBE_I2C_DATA_CMD,
+			byte_offset | TXGBE_I2C_DATA_CMD_STOP);
+	wr32(hw, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ);
+
+	/* wait for read complete */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+		TXGBE_I2C_INTR_STAT_RX_FULL, TXGBE_I2C_INTR_STAT_RX_FULL,
+		TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+		goto out;
+
+	*data = 0xFF & rd32(hw, TXGBE_I2C_DATA_CMD);
+
+out:
+	if (lock)
+		TCALL(hw, mac.ops.release_swfw_sync, swfw_mask);
+	return status;
+}
+
+/**
+*  txgbe_read_i2c_2bytes_int - Reads 16 bit word over I2C
+*  @hw: pointer to hardware structure
+*  @byte_offset: byte offset to read
+*  @data: value read
+*  @lock: true if to take and release semaphore
+*
+*  Performs byte read operation to SFP module's EEPROM over I2C interface at
+*  a specified device address.
+**/
+STATIC s32 txgbe_read_i2c_2bytes_int(struct txgbe_hw *hw, u16 byte_offset,
+					  u8 dev_addr, u16 *data, bool lock)
+{
+	s32 status = 0;
+	u32 swfw_mask = hw->phy.phy_semaphore_mask;
+
+	UNREFERENCED_PARAMETER(dev_addr);
+
+	if (lock && 0 != TCALL(hw, mac.ops.acquire_swfw_sync, swfw_mask))
+	   return TXGBE_ERR_SWFW_SYNC;
+
+	/* reg offset format 0x000yyyyy */
+	byte_offset &= 0x1f;  
+	
+	/* wait tx empty */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+	   TXGBE_I2C_INTR_STAT_TX_EMPTY, TXGBE_I2C_INTR_STAT_TX_EMPTY,
+	   TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+	   goto out;
+
+	/* write reg_offset */
+	wr32(hw, TXGBE_I2C_DATA_CMD, byte_offset >> 8 | TXGBE_I2C_DATA_CMD_STOP);
+	wr32(hw, TXGBE_I2C_DATA_CMD, (u8)byte_offset);
+
+	/* wait for write complete */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+	   TXGBE_I2C_INTR_STAT_RX_FULL, TXGBE_I2C_INTR_STAT_RX_FULL,
+	   TXGBE_I2C_TIMEOUT, 10);
+	
+	/* wait tx empty */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+	   TXGBE_I2C_INTR_STAT_TX_EMPTY, TXGBE_I2C_INTR_STAT_TX_EMPTY,
+	   TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+	   goto out;
+
+	/* read data */
+	wr32(hw, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ | TXGBE_I2C_DATA_CMD_STOP);
+	wr32(hw, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ );
+
+	/* wait for read complete */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+	   TXGBE_I2C_INTR_STAT_RX_FULL, TXGBE_I2C_INTR_STAT_RX_FULL,
+	   TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+	   goto out;
+
+	*data = 0xFF & rd32(hw, TXGBE_I2C_DATA_CMD);
+	*data <<= 8;
+	*data += 0xFF & rd32(hw, TXGBE_I2C_DATA_CMD);
+out:
+	if (lock)
+	   TCALL(hw, mac.ops.release_swfw_sync, swfw_mask);
+	return status;
+}
+
+
+/**
+ *  txgbe_switch_i2c_slave_addr - Switch I2C slave address
+ *  @hw: pointer to hardware structure
+ *  @dev_addr: slave addr to switch
+ *
+ **/
+s32 txgbe_switch_i2c_slave_addr(struct txgbe_hw *hw, u8 dev_addr)
+{
+	wr32(hw, TXGBE_I2C_ENABLE, 0);
+	wr32(hw, TXGBE_I2C_TAR, dev_addr >> 1);
+	wr32(hw, TXGBE_I2C_ENABLE, 1);
+	return 0;
+}
+
+
+/**
+ *  txgbe_read_i2c_byte - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+				u8 dev_addr, u8 *data)
+{
+	txgbe_switch_i2c_slave_addr(hw, dev_addr);
+
+	return txgbe_read_i2c_byte_int(hw, byte_offset, dev_addr,
+					       data, true);
+}
+
+/**
+ *	txgbe_read_i2c_2bytes - Reads 16 bit word over I2C
+ *	@hw: pointer to hardware structure
+ *	@byte_offset: byte offset to read
+ *	@data: value read
+ *
+ *	Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *	a specified device address.
+ **/
+s32 txgbe_read_i2c_2bytes(struct txgbe_hw *hw, u16 byte_offset,
+				u8 dev_addr, u16 *data)
+{
+	txgbe_switch_i2c_slave_addr(hw, dev_addr);
+
+	return txgbe_read_i2c_2bytes_int(hw, byte_offset, dev_addr,
+						   data, true);
+}
+
+
+/**
+ *  txgbe_write_i2c_byte_int - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *  @lock: true if to take and release semaphore
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+STATIC s32 txgbe_write_i2c_byte_int(struct txgbe_hw *hw, u8 byte_offset,
+					    u8 dev_addr, u8 data, bool lock)
+{
+	s32 status = 0;
+	u32 swfw_mask = hw->phy.phy_semaphore_mask;
+
+	UNREFERENCED_PARAMETER(dev_addr);
+
+	if (lock && 0 != TCALL(hw, mac.ops.acquire_swfw_sync, swfw_mask))
+		return TXGBE_ERR_SWFW_SYNC;
+
+	/* wait tx empty */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+		TXGBE_I2C_INTR_STAT_TX_EMPTY, TXGBE_I2C_INTR_STAT_TX_EMPTY,
+		TXGBE_I2C_TIMEOUT, 10);
+	if (status != 0)
+		goto out;
+
+	wr32(hw, TXGBE_I2C_DATA_CMD,
+			byte_offset | TXGBE_I2C_DATA_CMD_STOP);
+	wr32(hw, TXGBE_I2C_DATA_CMD,
+			data | TXGBE_I2C_DATA_CMD_WRITE);
+
+	/* wait for write complete */
+	status = po32m(hw, TXGBE_I2C_RAW_INTR_STAT,
+		TXGBE_I2C_INTR_STAT_RX_FULL, TXGBE_I2C_INTR_STAT_RX_FULL,
+		TXGBE_I2C_TIMEOUT, 10);
+
+out:
+	if (lock)
+		TCALL(hw, mac.ops.release_swfw_sync, swfw_mask);
+
+	return status;
+}
+
+/**
+ *  txgbe_write_i2c_byte - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+				 u8 dev_addr, u8 data)
+{
+	return txgbe_write_i2c_byte_int(hw, byte_offset, dev_addr,
+						data, true);
+}
+
+
+
+/**
+ *  txgbe_tn_check_overtemp - Checks if an overtemp occurred.
+ *  @hw: pointer to hardware structure
+ *
+ *  Checks if the LASI temp alarm status was triggered due to overtemp
+ **/
+s32 txgbe_tn_check_overtemp(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+	u32 ts_state;
+
+	/* Check that the LASI temp alarm status was triggered */
+	ts_state = rd32(hw, TXGBE_TS_ALARM_ST);
+
+	if (ts_state & TXGBE_TS_ALARM_ST_DALARM)
+		status = TXGBE_ERR_UNDERTEMP;
+	else if (ts_state & TXGBE_TS_ALARM_ST_ALARM)
+		status = TXGBE_ERR_OVERTEMP;
+
+	return status;
+}
+
+
+s32 txgbe_init_external_phy(struct txgbe_hw *hw)
+{
+	s32 status = 0;
+
+	MTD_DEV_PTR  devptr = &(hw->phy_dev);
+
+	hw->phy.addr = 0;
+
+	devptr->appData = hw;
+	status = mtdLoadDriver(txgbe_read_mdio,
+		txgbe_write_mdio,
+		MTD_FALSE,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		hw->phy.addr,
+		devptr);
+	if (status != 0) {
+		ERROR_REPORT1(TXGBE_ERROR_INVALID_STATE,
+			      "External PHY initilization failed.\n");
+		return TXGBE_ERR_PHY;
+	}
+
+	return status;
+}
+
+
+s32 txgbe_uninit_external_phy(struct txgbe_hw *hw)
+{
+	return mtdUnloadDriver(&hw->phy_dev);
+}
+
+s32 txgbe_set_phy_pause_advertisement(struct txgbe_hw *hw, u32 pause_bit)
+{
+	return mtdSetPauseAdvertisement(&hw->phy_dev, hw->phy.addr,
+						(pause_bit>>10)&0x3, MTD_FALSE);
+}
+
+s32 txgbe_get_phy_advertised_pause(struct txgbe_hw *hw, u8 *pause_bit)
+{
+	u16 value;
+	s32 status = 0;
+
+	status = mtdHwXmdioRead(&hw->phy_dev, hw->phy.addr,
+				TXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+				TXGBE_MDIO_AUTO_NEG_ADVT, &value);
+	*pause_bit = (u8)((value>>10)&0x3);
+	return status;
+
+}
+
+s32 txgbe_get_lp_advertised_pause(struct txgbe_hw *hw, u8 *pause_bit)
+{
+	return mtdGetLPAdvertisedPause(&hw->phy_dev, hw->phy.addr, pause_bit);
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
new file mode 100644
index 000000000000..4dff52969197
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h
@@ -0,0 +1,208 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_phy.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#ifndef _TXGBE_PHY_H_
+#define _TXGBE_PHY_H_
+
+#include "txgbe_type.h"
+#define TXGBE_I2C_EEPROM_DEV_ADDR       0xA0
+#define TXGBE_I2C_EEPROM_DEV_ADDR2      0xA2
+#define TXGBE_I2C_EEPROM_BANK_LEN       0xFF
+
+/*fiber to copper module inter reg i2c addr */
+#define TXGBE_I2C_EEPROM_DEV_ADDR3      0xAC
+#define TXGBE_I2C_PHY_LOCAL_RX_STATUS   (0x1 << 12)
+#define TXGBE_I2C_PHY_REMOTE_RX_STATUS  (0x1 << 13)
+
+/* EEPROM byte offsets */
+#define TXGBE_SFF_IDENTIFIER            0x0
+#define TXGBE_SFF_IDENTIFIER_SFP        0x3
+#define TXGBE_SFF_VENDOR_OUI_BYTE0      0x25
+#define TXGBE_SFF_VENDOR_OUI_BYTE1      0x26
+#define TXGBE_SFF_VENDOR_OUI_BYTE2      0x27
+#define TXGBE_SFF_1GBE_COMP_CODES       0x6
+#define TXGBE_SFF_10GBE_COMP_CODES      0x3
+#define TXGBE_SFF_CABLE_TECHNOLOGY      0x8
+#define TXGBE_SFF_CABLE_SPEC_COMP       0x3C
+#define TXGBE_SFF_SFF_8472_SWAP         0x5C
+#define TXGBE_SFF_SFF_8472_COMP         0x5E
+#define TXGBE_SFF_SFF_8472_OSCB         0x6E
+#define TXGBE_SFF_SFF_8472_ESCB         0x76
+#define TXGBE_SFF_IDENTIFIER_QSFP_PLUS  0xD
+#define TXGBE_SFF_QSFP_VENDOR_OUI_BYTE0 0xA5
+#define TXGBE_SFF_QSFP_VENDOR_OUI_BYTE1 0xA6
+#define TXGBE_SFF_QSFP_VENDOR_OUI_BYTE2 0xA7
+#define TXGBE_SFF_QSFP_CONNECTOR        0x82
+#define TXGBE_SFF_QSFP_10GBE_COMP       0x83
+#define TXGBE_SFF_QSFP_1GBE_COMP        0x86
+#define TXGBE_SFF_QSFP_CABLE_LENGTH     0x92
+#define TXGBE_SFF_QSFP_DEVICE_TECH      0x93
+
+/* Bitmasks */
+#define TXGBE_SFF_DA_PASSIVE_CABLE      0x4
+#define TXGBE_SFF_DA_ACTIVE_CABLE       0x8
+#define TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING       0x4
+#define TXGBE_SFF_1GBASESX_CAPABLE      0x1
+#define TXGBE_SFF_1GBASELX_CAPABLE      0x2
+#define TXGBE_SFF_1GBASET_CAPABLE       0x8
+#define TXGBE_SFF_10GBASESR_CAPABLE     0x10
+#define TXGBE_SFF_10GBASELR_CAPABLE     0x20
+#define TXGBE_SFF_SOFT_RS_SELECT_MASK   0x8
+#define TXGBE_SFF_SOFT_RS_SELECT_10G    0x8
+#define TXGBE_SFF_SOFT_RS_SELECT_1G     0x0
+#define TXGBE_SFF_ADDRESSING_MODE       0x4
+#define TXGBE_SFF_QSFP_DA_ACTIVE_CABLE  0x1
+#define TXGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8
+#define TXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE  0x23
+#define TXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL   0x0
+#define TXGBE_I2C_EEPROM_READ_MASK      0x100
+#define TXGBE_I2C_EEPROM_STATUS_MASK    0x3
+#define TXGBE_I2C_EEPROM_STATUS_NO_OPERATION    0x0
+#define TXGBE_I2C_EEPROM_STATUS_PASS    0x1
+#define TXGBE_I2C_EEPROM_STATUS_FAIL    0x2
+#define TXGBE_I2C_EEPROM_STATUS_IN_PROGRESS     0x3
+
+#define TXGBE_CS4227                    0xBE    /* CS4227 address */
+#define TXGBE_CS4227_GLOBAL_ID_LSB      0
+#define TXGBE_CS4227_SCRATCH            2
+#define TXGBE_CS4227_GLOBAL_ID_VALUE    0x03E5
+#define TXGBE_CS4227_SCRATCH_VALUE      0x5aa5
+#define TXGBE_CS4227_RETRIES            5
+#define TXGBE_CS4227_LINE_SPARE22_MSB   0x12AD  /* Reg to program speed */
+#define TXGBE_CS4227_LINE_SPARE24_LSB   0x12B0  /* Reg to program EDC */
+#define TXGBE_CS4227_HOST_SPARE22_MSB   0x1AAD  /* Reg to program speed */
+#define TXGBE_CS4227_HOST_SPARE24_LSB   0x1AB0  /* Reg to program EDC */
+#define TXGBE_CS4227_EDC_MODE_CX1       0x0002
+#define TXGBE_CS4227_EDC_MODE_SR        0x0004
+#define TXGBE_CS4227_RESET_HOLD         500     /* microseconds */
+#define TXGBE_CS4227_RESET_DELAY        500     /* milliseconds */
+#define TXGBE_CS4227_CHECK_DELAY        30      /* milliseconds */
+#define TXGBE_PE                        0xE0    /* Port expander address */
+#define TXGBE_PE_OUTPUT                 1       /* Output register offset */
+#define TXGBE_PE_CONFIG                 3       /* Config register offset */
+#define TXGBE_PE_BIT1                   (1 << 1)
+
+/* Flow control defines */
+#define TXGBE_TAF_SYM_PAUSE (0x1)
+#define TXGBE_TAF_ASM_PAUSE (0x2)
+
+/* Bit-shift macros */
+#define TXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT        24
+#define TXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT        16
+#define TXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT        8
+
+/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */
+#define TXGBE_SFF_VENDOR_OUI_TYCO       0x00407600
+#define TXGBE_SFF_VENDOR_OUI_FTL        0x00906500
+#define TXGBE_SFF_VENDOR_OUI_AVAGO      0x00176A00
+#define TXGBE_SFF_VENDOR_OUI_INTEL      0x001B2100
+
+/* I2C SDA and SCL timing parameters for standard mode */
+#define TXGBE_I2C_T_HD_STA      4
+#define TXGBE_I2C_T_LOW         5
+#define TXGBE_I2C_T_HIGH        4
+#define TXGBE_I2C_T_SU_STA      5
+#define TXGBE_I2C_T_HD_DATA     5
+#define TXGBE_I2C_T_SU_DATA     1
+#define TXGBE_I2C_T_RISE        1
+#define TXGBE_I2C_T_FALL        1
+#define TXGBE_I2C_T_SU_STO      4
+#define TXGBE_I2C_T_BUF         5
+
+#ifndef TXGBE_SFP_DETECT_RETRIES
+#define TXGBE_SFP_DETECT_RETRIES        10
+#endif /* TXGBE_SFP_DETECT_RETRIES */
+
+/* SFP+ SFF-8472 Compliance */
+#define TXGBE_SFF_SFF_8472_UNSUP        0x00
+
+
+enum txgbe_phy_type txgbe_get_phy_type_from_id(struct txgbe_hw *hw);
+s32 txgbe_get_phy_id(struct txgbe_hw *hw);
+s32 txgbe_reset_phy(struct txgbe_hw *hw);
+s32 txgbe_read_phy_reg_mdi(struct txgbe_hw *hw, u32 reg_addr, u32 device_type,
+			   u16 *phy_data);
+s32 txgbe_write_phy_reg_mdi(struct txgbe_hw *hw, u32 reg_addr, u32 device_type,
+			    u16 phy_data);
+s32 txgbe_read_phy_reg(struct txgbe_hw *hw, u32 reg_addr,
+			       u32 device_type, u16 *phy_data);
+s32 txgbe_write_phy_reg(struct txgbe_hw *hw, u32 reg_addr,
+				u32 device_type, u16 phy_data);
+u32 txgbe_setup_phy_link(struct txgbe_hw *hw, u32 speed_set, bool autoneg_wait_to_complete);
+u32 txgbe_setup_phy_link_speed(struct txgbe_hw *hw,
+				       u32 speed,
+				       bool autoneg_wait_to_complete);
+s32 txgbe_get_copper_link_capabilities(struct txgbe_hw *hw,
+					       u32 *speed,
+					       bool *autoneg);
+s32 txgbe_check_reset_blocked(struct txgbe_hw *hw);
+
+s32 txgbe_get_phy_firmware_version(struct txgbe_hw *hw,
+					   u16 *firmware_version);
+
+s32 txgbe_identify_module(struct txgbe_hw *hw);
+s32 txgbe_identify_sfp_module(struct txgbe_hw *hw);
+s32 txgbe_tn_check_overtemp(struct txgbe_hw *hw);
+s32 txgbe_init_i2c(struct txgbe_hw *hw);
+s32 txgbe_clear_i2c(struct txgbe_hw *hw);
+s32 txgbe_switch_i2c_slave_addr(struct txgbe_hw *hw, u8 dev_addr);
+s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+				u8 dev_addr, u8 *data);
+s32 txgbe_read_i2c_2bytes(struct txgbe_hw *hw, u16 byte_offset,
+				u8 dev_addr, u16 *data);
+
+
+s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset,
+				 u8 dev_addr, u8 data);
+s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
+				  u8 *eeprom_data);
+s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset,
+				   u8 eeprom_data);
+s32 txgbe_read_i2c_sff8472(struct txgbe_hw *hw, u8 byte_offset,
+							u8 *sff8472_data);
+s32 txgbe_read_i2c_sfp_phy(struct txgbe_hw *hw, u16 byte_offset,
+					  u16 *avago_data);
+
+s32 txgbe_init_external_phy(struct txgbe_hw *hw);
+s32 txgbe_uninit_external_phy(struct txgbe_hw *hw);
+s32 txgbe_set_phy_pause_advertisement(struct txgbe_hw *hw, u32 pause_bit);
+s32 txgbe_get_phy_advertised_pause(struct txgbe_hw *hw, u8 *pause_bit);
+s32 txgbe_get_lp_advertised_pause(struct txgbe_hw *hw, u8 *pause_bit);
+
+MTD_STATUS txgbe_read_mdio(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 *value);
+
+MTD_STATUS txgbe_write_mdio(
+						MTD_DEV * dev,
+						MTD_U16 port,
+						MTD_U16 mmd,
+						MTD_U16 reg,
+						MTD_U16 value);
+
+
+#endif /* _TXGBE_PHY_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_procfs.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_procfs.c
new file mode 100644
index 000000000000..c569cfc340f0
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_procfs.c
@@ -0,0 +1,929 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_procfs.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+#include "txgbe_hw.h"
+#include "txgbe_type.h"
+
+#ifdef TXGBE_PROCFS
+#ifndef TXGBE_SYSFS
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+
+static struct proc_dir_entry *txgbe_top_dir;
+
+static struct net_device_stats *procfs_get_stats(struct net_device *netdev)
+{
+#ifndef HAVE_NETDEV_STATS_IN_NETDEV
+	struct txgbe_adapter *adapter;
+#endif
+	if (netdev == NULL)
+		return NULL;
+
+#ifdef HAVE_NETDEV_STATS_IN_NETDEV
+	/* only return the current stats */
+	return &netdev->stats;
+#else
+	adapter = netdev_priv(netdev);
+
+	/* only return the current stats */
+	return &adapter->net_stats;
+#endif /* HAVE_NETDEV_STATS_IN_NETDEV */
+}
+
+static int txgbe_fwbanner(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%s\n", adapter->eeprom_id);
+}
+
+static int txgbe_porttype(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	return snprintf(page, count, "%d\n",
+			test_bit(__TXGBE_DOWN, &adapter->state));
+}
+
+static int txgbe_portspeed(char *page, char __always_unused **start,
+			   off_t __always_unused off, int count,
+			   int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	int speed = 0;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	switch (adapter->link_speed) {
+	case TXGBE_LINK_SPEED_100_FULL:
+		speed = 1;
+		break;
+	case TXGBE_LINK_SPEED_1GB_FULL:
+		speed = 10;
+		break;
+	case TXGBE_LINK_SPEED_10GB_FULL:
+		speed = 100;
+		break;
+	default:
+		break;
+	}
+	return snprintf(page, count, "%d\n", speed);
+}
+
+static int txgbe_wqlflag(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%d\n", adapter->wol);
+}
+
+static int txgbe_xflowctl(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct txgbe_hw *hw;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n", hw->fc.current_mode);
+}
+
+static int txgbe_rxdrops(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->rx_dropped);
+}
+
+static int txgbe_rxerrors(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n", net_stats->rx_errors);
+}
+
+static int txgbe_rxupacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n", rd32(hw, TXGBE_TPR));
+}
+
+static int txgbe_rxmpacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	int i, mprc = 0;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+	for (i = 0; i < 128; i++)
+		mprc += rd32(hw, TXGBE_PX_MPRC(i));
+	return snprintf(page, count, "%d\n", mprc);
+}
+
+static int txgbe_rxbpacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n",
+			rd32(hw, TXGBE_RX_BC_FRAMES_GOOD_LOW));
+}
+
+static int txgbe_txupacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n",
+			rd32(hw, TXGBE_TX_FRAME_CNT_GOOD_BAD_LOW));
+}
+
+static int txgbe_txmpacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n",
+			rd32(hw, TXGBE_TX_MC_FRAMES_GOOD_LOW));
+}
+
+static int txgbe_txbpacks(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "%d\n",
+			rd32(hw, TXGBE_TX_BC_FRAMES_GOOD_LOW));
+}
+
+static int txgbe_txerrors(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->tx_errors);
+}
+
+static int txgbe_txdrops(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->tx_dropped);
+}
+
+static int txgbe_rxframes(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->rx_packets);
+}
+
+static int txgbe_rxbytes(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->rx_bytes);
+}
+
+static int txgbe_txframes(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->tx_packets);
+}
+
+static int txgbe_txbytes(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device_stats *net_stats;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	net_stats  = procfs_get_stats(adapter->netdev);
+	if (net_stats == NULL)
+		return snprintf(page, count, "error: no net stats\n");
+
+	return snprintf(page, count, "%lu\n",
+			net_stats->tx_bytes);
+}
+
+static int txgbe_linkstat(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	int bitmask = 0;
+	u32 link_speed;
+	bool link_up = false;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	if (!test_bit(__TXGBE_DOWN, &adapter->state))
+		bitmask |= 1;
+
+	if (TCALL(hw, mac.ops.check_link, &link_speed, &link_up, false)
+		/* always assume link is up, if no check link function */
+		link_up = true;
+	if (link_up)
+		bitmask |= 2;
+
+	if (adapter->old_lsc != adapter->lsc_int) {
+		bitmask |= 4;
+		adapter->old_lsc = adapter->lsc_int;
+	}
+
+	return snprintf(page, count, "0x%X\n", bitmask);
+}
+
+static int txgbe_funcid(char *page, char __always_unused **start,
+			off_t __always_unused off, int count,
+			int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct txgbe_hw *hw;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "0x%X\n", hw->bus.func);
+}
+
+static int txgbe_funcvers(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void __always_unused *data)
+{
+	return snprintf(page, count, "%s\n", txgbe_driver_version);
+}
+
+static int txgbe_macburn(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "0x%02X%02X%02X%02X%02X%02X\n",
+		       (unsigned int)hw->mac.perm_addr[0],
+		       (unsigned int)hw->mac.perm_addr[1],
+		       (unsigned int)hw->mac.perm_addr[2],
+		       (unsigned int)hw->mac.perm_addr[3],
+		       (unsigned int)hw->mac.perm_addr[4],
+		       (unsigned int)hw->mac.perm_addr[5]);
+}
+
+static int txgbe_macadmn(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_hw *hw;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	return snprintf(page, count, "0x%02X%02X%02X%02X%02X%02X\n",
+		       (unsigned int)hw->mac.addr[0],
+		       (unsigned int)hw->mac.addr[1],
+		       (unsigned int)hw->mac.addr[2],
+		       (unsigned int)hw->mac.addr[3],
+		       (unsigned int)hw->mac.addr[4],
+		       (unsigned int)hw->mac.addr[5]);
+}
+
+static int txgbe_maclla1(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct txgbe_hw *hw;
+	int rc;
+	u16 eeprom_buff[6];
+	u16 first_word = 0x37;
+	const u16 word_count = ARRAY_SIZE(eeprom_buff);
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(page, count, "error: no hw data\n");
+
+	rc = TCALL(hw, eeprom.ops.read_buffer, first_word, 1, &first_word);
+	if (rc != 0)
+		return snprintf(page, count,
+				"error: reading pointer to the EEPROM\n");
+
+	if (first_word != 0x0000 && first_word != 0xFFFF) {
+		rc = TCALL(hw, eeprom.ops.read_buffer, first_word, word_count,
+					eeprom_buff);
+		if (rc != 0)
+			return snprintf(page, count, "error: reading buffer\n");
+	} else {
+		memset(eeprom_buff, 0, sizeof(eeprom_buff));
+	}
+
+	switch (hw->bus.func) {
+	case 0:
+		return snprintf(page, count, "0x%04X%04X%04X\n",
+				eeprom_buff[0],
+				eeprom_buff[1],
+				eeprom_buff[2]);
+	case 1:
+		return snprintf(page, count, "0x%04X%04X%04X\n",
+				eeprom_buff[3],
+				eeprom_buff[4],
+				eeprom_buff[5]);
+	}
+	return snprintf(page, count, "unexpected port %d\n", hw->bus.func);
+}
+
+static int txgbe_mtusize(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device *netdev;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	netdev = adapter->netdev;
+	if (netdev == NULL)
+		return snprintf(page, count, "error: no net device\n");
+
+	return snprintf(page, count, "%d\n", netdev->mtu);
+}
+
+static int txgbe_featflag(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	int bitmask = 0;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device *netdev;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	netdev = adapter->netdev;
+	if (netdev == NULL)
+		return snprintf(page, count, "error: no net device\n");
+	if (adapter->netdev->features & NETIF_F_RXCSUM)
+		bitmask |= 1;
+	return snprintf(page, count, "%d\n", bitmask);
+}
+
+static int txgbe_lsominct(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void __always_unused *data)
+{
+	return snprintf(page, count, "%d\n", 1);
+}
+
+static int txgbe_prommode(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	struct net_device *netdev;
+
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+	netdev = adapter->netdev;
+	if (netdev == NULL)
+		return snprintf(page, count, "error: no net device\n");
+
+	return snprintf(page, count, "%d\n",
+			netdev->flags & IFF_PROMISC);
+}
+
+static int txgbe_txdscqsz(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%d\n", adapter->tx_ring[0]->count);
+}
+
+static int txgbe_rxdscqsz(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%d\n", adapter->rx_ring[0]->count);
+}
+
+static int txgbe_rxqavg(char *page, char __always_unused **start,
+			off_t __always_unused off, int count,
+			int __always_unused *eof, void *data)
+{
+	int index;
+	int diff = 0;
+	u16 ntc;
+	u16 ntu;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	for (index = 0; index < adapter->num_rx_queues; index++) {
+		ntc = adapter->rx_ring[index]->next_to_clean;
+		ntu = adapter->rx_ring[index]->next_to_use;
+
+		if (ntc >= ntu)
+			diff += (ntc - ntu);
+		else
+			diff += (adapter->rx_ring[index]->count - ntu + ntc);
+	}
+	if (adapter->num_rx_queues <= 0)
+		return snprintf(page, count,
+				"can't calculate, number of queues %d\n",
+				adapter->num_rx_queues);
+	return snprintf(page, count, "%d\n", diff/adapter->num_rx_queues);
+}
+
+static int txgbe_txqavg(char *page, char __always_unused **start,
+			off_t __always_unused off, int count,
+			int __always_unused *eof, void *data)
+{
+	int index;
+	int diff = 0;
+	u16 ntc;
+	u16 ntu;
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	for (index = 0; index < adapter->num_tx_queues; index++) {
+		ntc = adapter->tx_ring[index]->next_to_clean;
+		ntu = adapter->tx_ring[index]->next_to_use;
+
+		if (ntc >= ntu)
+			diff += (ntc - ntu);
+		else
+			diff += (adapter->tx_ring[index]->count - ntu + ntc);
+	}
+	if (adapter->num_tx_queues <= 0)
+		return snprintf(page, count,
+				"can't calculate, number of queues %d\n",
+				adapter->num_tx_queues);
+	return snprintf(page, count, "%d\n",
+			diff/adapter->num_tx_queues);
+}
+
+static int txgbe_iovotype(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void __always_unused *data)
+{
+	return snprintf(page, count, "2\n");
+}
+
+static int txgbe_funcnbr(char *page, char __always_unused **start,
+			 off_t __always_unused off, int count,
+			 int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%d\n", adapter->num_vfs);
+}
+
+static int txgbe_pciebnbr(char *page, char __always_unused **start,
+			  off_t __always_unused off, int count,
+			  int __always_unused *eof, void *data)
+{
+	struct txgbe_adapter *adapter = (struct txgbe_adapter *)data;
+	if (adapter == NULL)
+		return snprintf(page, count, "error: no adapter\n");
+
+	return snprintf(page, count, "%d\n", adapter->pdev->bus->number);
+}
+
+static int txgbe_therm_dealarmthresh(char *page, char __always_unused **start,
+				   off_t __always_unused off, int count,
+				   int __always_unused *eof, void *data)
+{
+	struct txgbe_therm_proc_data *therm_data =
+		(struct txgbe_therm_proc_data *)data;
+
+	if (therm_data == NULL)
+		return snprintf(page, count, "error: no therm_data\n");
+
+	return snprintf(page, count, "%d\n",
+			therm_data->sensor_data->dalarm_thresh);
+}
+
+
+static int txgbe_therm_alarmthresh(char *page, char __always_unused **start,
+				     off_t __always_unused off, int count,
+				     int __always_unused *eof, void *data)
+{
+	struct txgbe_therm_proc_data *therm_data =
+		(struct txgbe_therm_proc_data *)data;
+
+	if (therm_data == NULL)
+		return snprintf(page, count, "error: no therm_data\n");
+
+	return snprintf(page, count, "%d\n",
+			therm_data->sensor_data->alarm_thresh);
+}
+
+static int txgbe_therm_temp(char *page, char __always_unused **start,
+			    off_t __always_unused off, int count,
+			    int __always_unused *eof, void *data)
+{
+	s32 status;
+	struct txgbe_therm_proc_data *therm_data =
+		(struct txgbe_therm_proc_data *)data;
+
+	if (therm_data == NULL)
+		return snprintf(page, count, "error: no therm_data\n");
+
+	status = txgbe_get_thermal_sensor_data(therm_data->hw);
+	if (status != 0)
+		snprintf(page, count, "error: status %d returned\n", status);
+
+	return snprintf(page, count, "%d\n", therm_data->sensor_data->temp);
+}
+
+
+struct txgbe_proc_type {
+	char name[32];
+	int (*read)(char*, char**, off_t, int, int*, void*);
+};
+
+struct txgbe_proc_type txgbe_proc_entries[] = {
+	{"fwbanner", &txgbe_fwbanner},
+	{"porttype", &txgbe_porttype},
+	{"portspeed", &txgbe_portspeed},
+	{"wqlflag", &txgbe_wqlflag},
+	{"xflowctl", &txgbe_xflowctl},
+	{"rxdrops", &txgbe_rxdrops},
+	{"rxerrors", &txgbe_rxerrors},
+	{"rxupacks", &txgbe_rxupacks},
+	{"rxmpacks", &txgbe_rxmpacks},
+	{"rxbpacks", &txgbe_rxbpacks},
+	{"txdrops", &txgbe_txdrops},
+	{"txerrors", &txgbe_txerrors},
+	{"txupacks", &txgbe_txupacks},
+	{"txmpacks", &txgbe_txmpacks},
+	{"txbpacks", &txgbe_txbpacks},
+	{"rxframes", &txgbe_rxframes},
+	{"rxbytes", &txgbe_rxbytes},
+	{"txframes", &txgbe_txframes},
+	{"txbytes", &txgbe_txbytes},
+	{"linkstat", &txgbe_linkstat},
+	{"funcid", &txgbe_funcid},
+	{"funcvers", &txgbe_funcvers},
+	{"macburn", &txgbe_macburn},
+	{"macadmn", &txgbe_macadmn},
+	{"maclla1", &txgbe_maclla1},
+	{"mtusize", &txgbe_mtusize},
+	{"featflag", &txgbe_featflag},
+	{"lsominct", &txgbe_lsominct},
+	{"prommode", &txgbe_prommode},
+	{"txdscqsz", &txgbe_txdscqsz},
+	{"rxdscqsz", &txgbe_rxdscqsz},
+	{"txqavg", &txgbe_txqavg},
+	{"rxqavg", &txgbe_rxqavg},
+	{"iovotype", &txgbe_iovotype},
+	{"funcnbr", &txgbe_funcnbr},
+	{"pciebnbr", &txgbe_pciebnbr},
+	{"", NULL}
+};
+
+struct txgbe_proc_type txgbe_internal_entries[] = {
+	{"temp", &txgbe_therm_temp},
+	{"alarmthresh", &txgbe_therm_alarmthresh},
+	{"dealarmthresh", &txgbe_therm_dealarmthresh},
+	{"", NULL}
+};
+
+void txgbe_del_proc_entries(struct txgbe_adapter *adapter)
+{
+	int index;
+	int i;
+	char buf[16];   /* much larger than the sensor number will ever be */
+
+	if (txgbe_top_dir == NULL)
+		return;
+
+	for (i = 0; i < TXGBE_MAX_SENSORS; i++) {
+		if (adapter->therm_dir[i] == NULL)
+			continue;
+
+		for (index = 0; ; index++) {
+			if (txgbe_internal_entries[index].read == NULL)
+				break;
+
+			 remove_proc_entry(txgbe_internal_entries[index].name,
+					   adapter->therm_dir[i]);
+		}
+		snprintf(buf, sizeof(buf), "sensor_%d", i);
+		remove_proc_entry(buf, adapter->info_dir);
+	}
+
+	if (adapter->info_dir != NULL) {
+		for (index = 0; ; index++) {
+			if (txgbe_proc_entries[index].read == NULL)
+				break;
+			remove_proc_entry(txgbe_proc_entries[index].name,
+					  adapter->info_dir);
+		}
+		remove_proc_entry("info", adapter->eth_dir);
+	}
+
+	if (adapter->eth_dir != NULL)
+		remove_proc_entry(pci_name(adapter->pdev), txgbe_top_dir);
+}
+
+/* called from txgbe_main.c */
+void txgbe_procfs_exit(struct txgbe_adapter *adapter)
+{
+	txgbe_del_proc_entries(adapter);
+}
+
+int txgbe_procfs_topdir_init(void)
+{
+	txgbe_top_dir = proc_mkdir("driver/txgbe", NULL);
+	if (txgbe_top_dir == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void txgbe_procfs_topdir_exit(void)
+{
+	remove_proc_entry("driver/txgbe", NULL);
+}
+
+/* called from txgbe_main.c */
+int txgbe_procfs_init(struct txgbe_adapter *adapter)
+{
+	int rc = 0;
+	int index;
+	int i;
+	char buf[16];   /* much larger than the sensor number will ever be */
+
+	adapter->eth_dir = NULL;
+	adapter->info_dir = NULL;
+	adapter->therm_dir = NULL;
+
+	if (txgbe_top_dir == NULL) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	adapter->eth_dir = proc_mkdir(pci_name(adapter->pdev), txgbe_top_dir);
+	if (adapter->eth_dir == NULL) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	adapter->info_dir = proc_mkdir("info", adapter->eth_dir);
+	if (adapter->info_dir == NULL) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+	for (index = 0; ; index++) {
+		if (txgbe_proc_entries[index].read == NULL)
+			break;
+		if (!(create_proc_read_entry(txgbe_proc_entries[index].name,
+					   0444,
+					   adapter->info_dir,
+					   txgbe_proc_entries[index].read,
+					   adapter))) {
+
+			rc = -ENOMEM;
+			goto fail;
+		}
+	}
+	if (!TCALL(&(adapter->hw), ops.init_thermal_sensor_thresh))
+		goto exit;
+
+
+	snprintf(buf, sizeof(buf), "sensor");
+	adapter->therm_dir = proc_mkdir(buf, adapter->info_dir);
+	if (adapter->therm_dir == NULL) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+	for (index = 0; ; index++) {
+		if (txgbe_internal_entries[index].read == NULL)
+			break;
+		/*
+		 * therm_data struct contains pointer the read func
+		 * will be needing
+		 */
+		adapter->therm_data.hw = &adapter->hw;
+		adapter->therm_data.sensor_data =
+			&adapter->hw.mac.thermal_sensor_data.sensor;
+
+		if (!(create_proc_read_entry(
+				   txgbe_internal_entries[index].name,
+				   0444,
+				   adapter->therm_dir,
+				   txgbe_internal_entries[index].read,
+				   &adapter->therm_data))) {
+			rc = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	goto exit;
+
+fail:
+	txgbe_del_proc_entries(adapter);
+exit:
+	return rc;
+}
+
+#endif /* !TXGBE_SYSFS */
+#endif /* TXGBE_PROCFS */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ptp.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ptp.c
new file mode 100644
index 000000000000..d75a31758921
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ptp.c
@@ -0,0 +1,914 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_ptp.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+#include <linux/ptp_classify.h>
+
+/*
+ * SYSTIME is defined by a fixed point system which allows the user to
+ * define the scale counter increment value at every level change of
+ * the oscillator driving SYSTIME value. The time unit is determined by
+ * the clock frequency of the oscillator and TIMINCA register.
+ * The cyclecounter and timecounter structures are used to to convert
+ * the scale counter into nanoseconds. SYSTIME registers need to be converted
+ * to ns values by use of only a right shift.
+ * The following math determines the largest incvalue that will fit into
+ * the available bits in the TIMINCA register:
+ *   Period * [ 2 ^ ( MaxWidth - PeriodWidth ) ]
+ * PeriodWidth: Number of bits to store the clock period
+ * MaxWidth: The maximum width value of the TIMINCA register
+ * Period: The clock period for the oscillator, which changes based on the link
+ * speed:
+ *   At 10Gb link or no link, the period is 6.4 ns.
+ *   At 1Gb link, the period is multiplied by 10. (64ns)
+ *   At 100Mb link, the period is multiplied by 100. (640ns)
+ * round(): discard the fractional portion of the calculation
+ *
+ * The calculated value allows us to right shift the SYSTIME register
+ * value in order to quickly convert it into a nanosecond clock,
+ * while allowing for the maximum possible adjustment value.
+ *
+ * LinkSpeed    ClockFreq   ClockPeriod  TIMINCA:IV
+ * 10000Mbps    156.25MHz   6.4*10^-9    0xCCCCCC(0xFFFFF/ns)
+ * 1000 Mbps    62.5  MHz   16 *10^-9    0x800000(0x7FFFF/ns)
+ * 100  Mbps    6.25  MHz   160*10^-9    0xA00000(0xFFFF/ns)
+ * 10   Mbps    0.625 MHz   1600*10^-9   0xC7F380(0xFFF/ns)
+ * FPGA         31.25 MHz   32 *10^-9    0x800000(0x3FFFF/ns)
+ *
+ * These diagrams are only for the 10Gb link period
+ *
+ *       +--------------+  +--------------+
+ *       |      32      |  | 8 | 3 |  20  |
+ *       *--------------+  +--------------+
+ *        \________ 43 bits ______/  fract
+ *
+ * The 43 bit SYSTIME overflows every
+ *   2^43 * 10^-9 / 3600 = 2.4 hours
+ */
+#define TXGBE_INCVAL_10GB 0xCCCCCC
+#define TXGBE_INCVAL_1GB  0x800000
+#define TXGBE_INCVAL_100  0xA00000
+#define TXGBE_INCVAL_10   0xC7F380
+#define TXGBE_INCVAL_FPGA 0x800000
+
+#define TXGBE_INCVAL_SHIFT_10GB  20
+#define TXGBE_INCVAL_SHIFT_1GB   18
+#define TXGBE_INCVAL_SHIFT_100   15
+#define TXGBE_INCVAL_SHIFT_10    12
+#define TXGBE_INCVAL_SHIFT_FPGA  17
+
+#define TXGBE_OVERFLOW_PERIOD    (HZ * 30)
+#define TXGBE_PTP_TX_TIMEOUT     (HZ)
+
+/**
+ * txgbe_ptp_read - read raw cycle counter (to be used by time counter)
+ * @hw_cc: the cyclecounter structure
+ *
+ * this function reads the cyclecounter registers and is called by the
+ * cyclecounter structure used to construct a ns counter from the
+ * arbitrary fixed point registers
+ */
+static u64 txgbe_ptp_read(const struct cyclecounter *hw_cc)
+{
+	struct txgbe_adapter *adapter =
+		container_of(hw_cc, struct txgbe_adapter, hw_cc);
+	struct txgbe_hw *hw = &adapter->hw;
+	u64 stamp = 0;
+
+	stamp |= (u64)rd32(hw, TXGBE_TSC_1588_SYSTIML);
+	stamp |= (u64)rd32(hw, TXGBE_TSC_1588_SYSTIMH) << 32;
+
+	return stamp;
+}
+
+/**
+ * txgbe_ptp_convert_to_hwtstamp - convert register value to hw timestamp
+ * @adapter: private adapter structure
+ * @hwtstamp: stack timestamp structure
+ * @systim: unsigned 64bit system time value
+ *
+ * We need to convert the adapter's RX/TXSTMP registers into a hwtstamp value
+ * which can be used by the stack's ptp functions.
+ *
+ * The lock is used to protect consistency of the cyclecounter and the SYSTIME
+ * registers. However, it does not need to protect against the Rx or Tx
+ * timestamp registers, as there can't be a new timestamp until the old one is
+ * unlatched by reading.
+ *
+ * In addition to the timestamp in hardware, some controllers need a software
+ * overflow cyclecounter, and this function takes this into account as well.
+ **/
+static void txgbe_ptp_convert_to_hwtstamp(struct txgbe_adapter *adapter,
+					  struct skb_shared_hwtstamps *hwtstamp,
+					  u64 timestamp)
+{
+	unsigned long flags;
+	u64 ns;
+
+	memset(hwtstamp, 0, sizeof(*hwtstamp));
+
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	ns = timecounter_cyc2time(&adapter->hw_tc, timestamp);
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	hwtstamp->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * txgbe_ptp_adjfreq
+ * @ptp: the ptp clock structure
+ * @ppb: parts per billion adjustment from base
+ *
+ * adjust the frequency of the ptp cycle counter by the
+ * indicated ppb from the base frequency.
+ */
+static int txgbe_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+	struct txgbe_adapter *adapter =
+		container_of(ptp, struct txgbe_adapter, ptp_caps);
+	struct txgbe_hw *hw = &adapter->hw;
+	u64 freq, incval;
+	u32 diff;
+	int neg_adj = 0;
+
+	if (ppb < 0) {
+		neg_adj = 1;
+		ppb = -ppb;
+	}
+
+	smp_mb();
+	incval = READ_ONCE(adapter->base_incval);
+
+	freq = incval;
+	freq *= ppb;
+	diff = div_u64(freq, 1000000000ULL);
+
+	incval = neg_adj ? (incval - diff) : (incval + diff);
+
+	if (incval > TXGBE_TSC_1588_INC_IV(~0))
+		e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
+	wr32(hw, TXGBE_TSC_1588_INC,
+			TXGBE_TSC_1588_INC_IVP(incval, 2));
+
+	return 0;
+}
+
+
+/**
+ * txgbe_ptp_adjtime
+ * @ptp: the ptp clock structure
+ * @delta: offset to adjust the cycle counter by ns
+ *
+ * adjust the timer by resetting the timecounter structure.
+ */
+static int txgbe_ptp_adjtime(struct ptp_clock_info *ptp,
+					 s64 delta)
+{
+	struct txgbe_adapter *adapter =
+		container_of(ptp, struct txgbe_adapter, ptp_caps);
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	timecounter_adjtime(&adapter->hw_tc, delta);
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	return 0;
+}
+
+/**
+ * txgbe_ptp_gettime64
+ * @ptp: the ptp clock structure
+ * @ts: timespec64 structure to hold the current time value
+ *
+ * read the timecounter and return the correct value on ns,
+ * after converting it into a struct timespec64.
+ */
+static int txgbe_ptp_gettime64(struct ptp_clock_info *ptp,
+			       struct timespec64 *ts)
+{
+	struct txgbe_adapter *adapter =
+		container_of(ptp, struct txgbe_adapter, ptp_caps);
+	unsigned long flags;
+	u64 ns;
+
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	ns = timecounter_read(&adapter->hw_tc);
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	*ts = ns_to_timespec64(ns);
+
+	return 0;
+}
+
+/**
+ * txgbe_ptp_settime64
+ * @ptp: the ptp clock structure
+ * @ts: the timespec64 containing the new time for the cycle counter
+ *
+ * reset the timecounter to use a new base value instead of the kernel
+ * wall timer value.
+ */
+static int txgbe_ptp_settime64(struct ptp_clock_info *ptp,
+					   const struct timespec64 *ts)
+{
+	struct txgbe_adapter *adapter =
+		container_of(ptp, struct txgbe_adapter, ptp_caps);
+	u64 ns;
+	unsigned long flags;
+
+	ns = timespec64_to_ns(ts);
+
+	/* reset the timecounter */
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	timecounter_init(&adapter->hw_tc, &adapter->hw_cc, ns);
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	return 0;
+}
+
+#ifndef HAVE_PTP_CLOCK_INFO_GETTIME64
+static int txgbe_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	struct timespec64 ts64;
+	int err;
+
+	err = txgbe_ptp_gettime64(ptp, &ts64);
+	if (err)
+		return err;
+
+	*ts = timespec64_to_timespec(ts64);
+
+	return 0;
+}
+
+static int txgbe_ptp_settime(struct ptp_clock_info *ptp,
+					 const struct timespec *ts)
+{
+	struct timespec64 ts64;
+
+	ts64 = timespec_to_timespec64(*ts);
+	return txgbe_ptp_settime64(ptp, &ts64);
+}
+#endif
+
+/**
+ * txgbe_ptp_feature_enable
+ * @ptp: the ptp clock structure
+ * @rq: the requested feature to change
+ * @on: whether to enable or disable the feature
+ *
+ * enable (or disable) ancillary features of the phc subsystem.
+ * our driver only supports the PPS feature on the X540
+ */
+static int txgbe_ptp_feature_enable(struct ptp_clock_info *ptp,
+				    struct ptp_clock_request *rq, int on)
+{
+	return -ENOTSUPP;
+}
+
+/**
+ * txgbe_ptp_check_pps_event
+ * @adapter: the private adapter structure
+ * @eicr: the interrupt cause register value
+ *
+ * This function is called by the interrupt routine when checking for
+ * interrupts. It will check and handle a pps event.
+ */
+void txgbe_ptp_check_pps_event(struct txgbe_adapter *adapter)
+{
+	struct ptp_clock_event event;
+
+	event.type = PTP_CLOCK_PPS;
+
+	/* this check is necessary in case the interrupt was enabled via some
+	 * alternative means (ex. debug_fs). Better to check here than
+	 * everywhere that calls this function.
+	 */
+	if (!adapter->ptp_clock)
+		return;
+
+	/* we don't config PPS on SDP yet, so just return.
+	 * ptp_clock_event(adapter->ptp_clock, &event);
+	 */
+}
+
+/**
+ * txgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
+ * @adapter: private adapter struct
+ *
+ * this watchdog task periodically reads the timecounter
+ * in order to prevent missing when the system time registers wrap
+ * around. This needs to be run approximately twice a minute for the fastest
+ * overflowing hardware. We run it for all hardware since it shouldn't have a
+ * large impact.
+ */
+void txgbe_ptp_overflow_check(struct txgbe_adapter *adapter)
+{
+	bool timeout = time_is_before_jiffies(adapter->last_overflow_check +
+					      TXGBE_OVERFLOW_PERIOD);
+	struct timespec64 ts;
+
+	if (timeout) {
+		txgbe_ptp_gettime64(&adapter->ptp_caps, &ts);
+		adapter->last_overflow_check = jiffies;
+	}
+}
+
+/**
+ * txgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
+ *
+ * this watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
+ */
+void txgbe_ptp_rx_hang(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_ring *rx_ring;
+	u32 tsyncrxctl = rd32(hw, TXGBE_PSR_1588_CTL);
+	unsigned long rx_event;
+	int n;
+
+	/* if we don't have a valid timestamp in the registers, just update the
+	 * timeout counter and exit
+	 */
+	if (!(tsyncrxctl & TXGBE_PSR_1588_CTL_VALID)) {
+		adapter->last_rx_ptp_check = jiffies;
+		return;
+	}
+
+	/* determine the most recent watchdog or rx_timestamp event */
+	rx_event = adapter->last_rx_ptp_check;
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		if (time_after(rx_ring->last_rx_timestamp, rx_event))
+			rx_event = rx_ring->last_rx_timestamp;
+	}
+
+	/* only need to read the high RXSTMP register to clear the lock */
+	if (time_is_before_jiffies(rx_event + 5*HZ)) {
+		rd32(hw, TXGBE_PSR_1588_STMPH);
+		adapter->last_rx_ptp_check = jiffies;
+
+		adapter->rx_hwtstamp_cleared++;
+		e_warn(drv, "clearing RX Timestamp hang");
+	}
+}
+
+/**
+ * txgbe_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state
+ * @adapter: the private adapter structure
+ *
+ * This function should be called whenever the state related to a Tx timestamp
+ * needs to be cleared. This helps ensure that all related bits are reset for
+ * the next Tx timestamp event.
+ */
+static void txgbe_ptp_clear_tx_timestamp(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	rd32(hw, TXGBE_TSC_1588_STMPH);
+	if (adapter->ptp_tx_skb) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+	}
+	clear_bit_unlock(__TXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
+}
+
+/**
+ * txgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
+ * @adapter: the private adapter struct
+ *
+ * if the timestamp is valid, we convert it into the timecounter ns
+ * value, then store that result into the shhwtstamps structure which
+ * is passed up the network stack
+ */
+static void txgbe_ptp_tx_hwtstamp(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct skb_shared_hwtstamps shhwtstamps;
+	u64 regval = 0;
+
+	regval |= (u64)rd32(hw, TXGBE_TSC_1588_STMPL);
+	regval |= (u64)rd32(hw, TXGBE_TSC_1588_STMPH) << 32;
+
+	txgbe_ptp_convert_to_hwtstamp(adapter, &shhwtstamps, regval);
+	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
+
+	txgbe_ptp_clear_tx_timestamp(adapter);
+}
+
+/**
+ * txgbe_ptp_tx_hwtstamp_work
+ * @work: pointer to the work struct
+ *
+ * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
+ * timestamp has been taken for the current skb. It is necesary, because the
+ * descriptor's "done" bit does not correlate with the timestamp event.
+ */
+static void txgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
+{
+	struct txgbe_adapter *adapter = container_of(work, struct txgbe_adapter,
+						     ptp_tx_work);
+	struct txgbe_hw *hw = &adapter->hw;
+	bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+					      TXGBE_PTP_TX_TIMEOUT);
+	u32 tsynctxctl;
+
+	/* we have to have a valid skb to poll for a timestamp */
+	if (!adapter->ptp_tx_skb) {
+		txgbe_ptp_clear_tx_timestamp(adapter);
+		return;
+	}
+
+	/* stop polling once we have a valid timestamp */
+	tsynctxctl = rd32(hw, TXGBE_TSC_1588_CTL);
+	if (tsynctxctl & TXGBE_TSC_1588_CTL_VALID) {
+		txgbe_ptp_tx_hwtstamp(adapter);
+		return;
+	}
+
+	/* check timeout last in case timestamp event just occurred */
+	if (timeout) {
+		txgbe_ptp_clear_tx_timestamp(adapter);
+		adapter->tx_hwtstamp_timeouts++;
+		e_warn(drv, "clearing Tx Timestamp hang");
+	} else {
+		/* reschedule to keep checking until we timeout */
+		schedule_work(&adapter->ptp_tx_work);
+	}
+}
+
+/**
+ * txgbe_ptp_rx_rgtstamp - utility function which checks for RX time stamp
+ * @q_vector: structure containing interrupt and ring information
+ * @skb: particular skb to send timestamp with
+ *
+ * if the timestamp is valid, we convert it into the timecounter ns
+ * value, then store that result into the shhwtstamps structure which
+ * is passed up the network stack
+ */
+void txgbe_ptp_rx_hwtstamp(struct txgbe_adapter *adapter, struct sk_buff *skb)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u64 regval = 0;
+	u32 tsyncrxctl;
+
+	/*
+	 * Read the tsyncrxctl register afterwards in order to prevent taking an
+	 * I/O hit on every packet.
+	 */
+	tsyncrxctl = rd32(hw, TXGBE_PSR_1588_CTL);
+	if (!(tsyncrxctl & TXGBE_PSR_1588_CTL_VALID))
+		return;
+
+	regval |= (u64)rd32(hw, TXGBE_PSR_1588_STMPL);
+	regval |= (u64)rd32(hw, TXGBE_PSR_1588_STMPH) << 32;
+
+	txgbe_ptp_convert_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
+}
+
+/**
+ * txgbe_ptp_get_ts_config - get current hardware timestamping configuration
+ * @adapter: pointer to adapter structure
+ * @ifreq: ioctl data
+ *
+ * This function returns the current timestamping settings. Rather than
+ * attempt to deconstruct registers to fill in the values, simply keep a copy
+ * of the old settings around, and return a copy when requested.
+ */
+int txgbe_ptp_get_ts_config(struct txgbe_adapter *adapter, struct ifreq *ifr)
+{
+	struct hwtstamp_config *config = &adapter->tstamp_config;
+
+	return copy_to_user(ifr->ifr_data, config,
+			    sizeof(*config)) ? -EFAULT : 0;
+}
+
+/**
+ * txgbe_ptp_set_timestamp_mode - setup the hardware for the requested mode
+ * @adapter: the private txgbe adapter structure
+ * @config: the hwtstamp configuration requested
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware
+ * filters. Not all combinations are supported, in particular event
+ * type has to be specified. Matching the kind of event packet is
+ * not supported, with the exception of "all V2 events regardless of
+ * level 2 or 4".
+ *
+ * Since hardware always timestamps Path delay packets when timestamping V2
+ * packets, regardless of the type specified in the register, only use V2
+ * Event mode. This more accurately tells the user what the hardware is going
+ * to do anyways.
+ *
+ * Note: this may modify the hwtstamp configuration towards a more general
+ * mode, if required to support the specifically requested mode.
+ */
+static int txgbe_ptp_set_timestamp_mode(struct txgbe_adapter *adapter,
+					struct hwtstamp_config *config)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 tsync_tx_ctl = TXGBE_TSC_1588_CTL_ENABLED;
+	u32 tsync_rx_ctl = TXGBE_PSR_1588_CTL_ENABLED;
+	u32 tsync_rx_mtrl = PTP_EV_PORT << 16;
+	bool is_l2 = false;
+	u32 regval;
+
+	/* reserved for future extensions */
+	if (config->flags)
+		return -EINVAL;
+
+	switch (config->tx_type) {
+	case HWTSTAMP_TX_OFF:
+		tsync_tx_ctl = 0;
+	case HWTSTAMP_TX_ON:
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	switch (config->rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		tsync_rx_ctl = 0;
+		tsync_rx_mtrl = 0;
+		adapter->flags &= ~(TXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+		tsync_rx_ctl |= TXGBE_PSR_1588_CTL_TYPE_L4_V1;
+		tsync_rx_mtrl |= TXGBE_PSR_1588_MSGTYPE_V1_SYNC_MSG;
+		adapter->flags |= (TXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				   TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		tsync_rx_ctl |= TXGBE_PSR_1588_CTL_TYPE_L4_V1;
+		tsync_rx_mtrl |= TXGBE_PSR_1588_MSGTYPE_V1_DELAY_REQ_MSG;
+		adapter->flags |= (TXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				   TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+		tsync_rx_ctl |= TXGBE_PSR_1588_CTL_TYPE_EVENT_V2;
+		is_l2 = true;
+		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+		adapter->flags |= (TXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				   TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+	case HWTSTAMP_FILTER_ALL:
+	default:
+		/* register RXMTRL must be set in order to do V1 packets,
+		 * therefore it is not possible to time stamp both V1 Sync and
+		 * Delay_Req messages unless hardware supports timestamping all
+		 * packets => return error
+		 */
+		adapter->flags &= ~(TXGBE_FLAG_RX_HWTSTAMP_ENABLED |
+				    TXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER);
+		config->rx_filter = HWTSTAMP_FILTER_NONE;
+		return -ERANGE;
+	}
+
+	/* define ethertype filter for timestamping L2 packets */
+	if (is_l2)
+		wr32(hw,
+			TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_1588),
+			(TXGBE_PSR_ETYPE_SWC_FILTER_EN | /* enable filter */
+			 TXGBE_PSR_ETYPE_SWC_1588 | /* enable timestamping */
+			 ETH_P_1588));     /* 1588 eth protocol type */
+	else
+		wr32(hw,
+			TXGBE_PSR_ETYPE_SWC(TXGBE_PSR_ETYPE_SWC_FILTER_1588),
+			0);
+
+	/* enable/disable TX */
+	regval = rd32(hw, TXGBE_TSC_1588_CTL);
+	regval &= ~TXGBE_TSC_1588_CTL_ENABLED;
+	regval |= tsync_tx_ctl;
+	wr32(hw, TXGBE_TSC_1588_CTL, regval);
+
+	/* enable/disable RX */
+	regval = rd32(hw, TXGBE_PSR_1588_CTL);
+	regval &= ~(TXGBE_PSR_1588_CTL_ENABLED | TXGBE_PSR_1588_CTL_TYPE_MASK);
+	regval |= tsync_rx_ctl;
+	wr32(hw, TXGBE_PSR_1588_CTL, regval);
+
+	/* define which PTP packets are time stamped */
+	wr32(hw, TXGBE_PSR_1588_MSGTYPE, tsync_rx_mtrl);
+
+	TXGBE_WRITE_FLUSH(hw);
+
+	/* clear TX/RX timestamp state, just to be sure */
+	txgbe_ptp_clear_tx_timestamp(adapter);
+	rd32(hw, TXGBE_PSR_1588_STMPH);
+
+	return 0;
+}
+
+/**
+ * txgbe_ptp_set_ts_config - user entry point for timestamp mode
+ * @adapter: pointer to adapter struct
+ * @ifreq: ioctl data
+ *
+ * Set hardware to requested mode. If unsupported, return an error with no
+ * changes. Otherwise, store the mode for future reference.
+ */
+int txgbe_ptp_set_ts_config(struct txgbe_adapter *adapter, struct ifreq *ifr)
+{
+	struct hwtstamp_config config;
+	int err;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	err = txgbe_ptp_set_timestamp_mode(adapter, &config);
+	if (err)
+		return err;
+
+	/* save these settings for future reference */
+	memcpy(&adapter->tstamp_config, &config,
+	       sizeof(adapter->tstamp_config));
+
+	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+		-EFAULT : 0;
+}
+
+static void txgbe_ptp_link_speed_adjust(struct txgbe_adapter *adapter,
+					u32 *shift, u32 *incval)
+{
+	/**
+	 * Scale the NIC cycle counter by a large factor so that
+	 * relatively small corrections to the frequency can be added
+	 * or subtracted. The drawbacks of a large factor include
+	 * (a) the clock register overflows more quickly, (b) the cycle
+	 * counter structure must be able to convert the systime value
+	 * to nanoseconds using only a multiplier and a right-shift,
+	 * and (c) the value must fit within the timinca register space
+	 * => math based on internal DMA clock rate and available bits
+	 *
+	 * Note that when there is no link, internal DMA clock is same as when
+	 * link speed is 10Gb. Set the registers correctly even when link is
+	 * down to preserve the clock setting
+	 */
+	switch (adapter->link_speed) {
+	case TXGBE_LINK_SPEED_10_FULL:
+		*shift = TXGBE_INCVAL_SHIFT_10;
+		*incval = TXGBE_INCVAL_10;
+		break;
+	case TXGBE_LINK_SPEED_100_FULL:
+		*shift = TXGBE_INCVAL_SHIFT_100;
+		*incval = TXGBE_INCVAL_100;
+		break;
+	case TXGBE_LINK_SPEED_1GB_FULL:
+		*shift = TXGBE_INCVAL_SHIFT_1GB;
+		*incval = TXGBE_INCVAL_1GB;
+		break;
+	case TXGBE_LINK_SPEED_10GB_FULL:
+	default: /* TXGBE_LINK_SPEED_10GB_FULL */
+		*shift = TXGBE_INCVAL_SHIFT_10GB;
+		*incval = TXGBE_INCVAL_10GB;
+		break;
+	}
+
+	return;
+}
+
+/**
+ * txgbe_ptp_start_cyclecounter - create the cycle counter from hw
+ * @adapter: pointer to the adapter structure
+ *
+ * This function should be called to set the proper values for the TIMINCA
+ * register and tell the cyclecounter structure what the tick rate of SYSTIME
+ * is. It does not directly modify SYSTIME registers or the timecounter
+ * structure. It should be called whenever a new TIMINCA value is necessary,
+ * such as during initialization or when the link speed changes.
+ */
+void txgbe_ptp_start_cyclecounter(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	unsigned long flags;
+	struct cyclecounter cc;
+	u32 incval = 0;
+
+	/* For some of the boards below this mask is technically incorrect.
+	 * The timestamp mask overflows at approximately 61bits. However the
+	 * particular hardware does not overflow on an even bitmask value.
+	 * Instead, it overflows due to conversion of upper 32bits billions of
+	 * cycles. Timecounters are not really intended for this purpose so
+	 * they do not properly function if the overflow point isn't 2^N-1.
+	 * However, the actual SYSTIME values in question take ~138 years to
+	 * overflow. In practice this means they won't actually overflow. A
+	 * proper fix to this problem would require modification of the
+	 * timecounter delta calculations.
+	 */
+	cc.mask = CLOCKSOURCE_MASK(64);
+	cc.mult = 1;
+	cc.shift = 0;
+
+	cc.read = txgbe_ptp_read;
+	txgbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval);
+	wr32(hw, TXGBE_TSC_1588_INC,
+		TXGBE_TSC_1588_INC_IVP(incval, 2));
+
+	/* update the base incval used to calculate frequency adjustment */
+	WRITE_ONCE(adapter->base_incval, incval);
+	smp_mb();
+
+	/* need lock to prevent incorrect read while modifying cyclecounter */
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	memcpy(&adapter->hw_cc, &cc, sizeof(adapter->hw_cc));
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+}
+
+/**
+ * txgbe_ptp_reset
+ * @adapter: the txgbe private board structure
+ *
+ * When the MAC resets, all of the hardware configuration for timesync is
+ * reset. This function should be called to re-enable the device for PTP,
+ * using the last known settings. However, we do lose the current clock time,
+ * so we fallback to resetting it based on the kernel's realtime clock.
+ *
+ * This function will maintain the hwtstamp_config settings, and it retriggers
+ * the SDP output if it's enabled.
+ */
+void txgbe_ptp_reset(struct txgbe_adapter *adapter)
+{
+	unsigned long flags;
+
+	/* reset the hardware timestamping mode */
+	txgbe_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
+	txgbe_ptp_start_cyclecounter(adapter);
+
+	spin_lock_irqsave(&adapter->tmreg_lock, flags);
+	timecounter_init(&adapter->hw_tc, &adapter->hw_cc,
+			 ktime_to_ns(ktime_get_real()));
+	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+
+	adapter->last_overflow_check = jiffies;
+}
+
+/**
+ * txgbe_ptp_create_clock
+ * @adapter: the txgbe private adapter structure
+ *
+ * This functino performs setup of the user entry point function table and
+ * initalizes the PTP clock device used by userspace to access the clock-like
+ * features of the PTP core. It will be called by txgbe_ptp_init, and may
+ * re-use a previously initialized clock (such as during a suspend/resume
+ * cycle).
+ */
+
+static long txgbe_ptp_create_clock(struct txgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	long err;
+
+	/* do nothing if we already have a clock device */
+	if (!IS_ERR_OR_NULL(adapter->ptp_clock))
+		return 0;
+
+	snprintf(adapter->ptp_caps.name, sizeof(adapter->ptp_caps.name),
+		 "%s", netdev->name);
+	adapter->ptp_caps.owner = THIS_MODULE;
+	adapter->ptp_caps.max_adj = 250000000; /* 10^-9s */
+	adapter->ptp_caps.n_alarm = 0;
+	adapter->ptp_caps.n_ext_ts = 0;
+	adapter->ptp_caps.n_per_out = 0;
+	adapter->ptp_caps.pps = 0;
+	adapter->ptp_caps.adjfreq = txgbe_ptp_adjfreq;
+	adapter->ptp_caps.adjtime = txgbe_ptp_adjtime;
+#ifdef HAVE_PTP_CLOCK_INFO_GETTIME64
+	adapter->ptp_caps.gettime64 = txgbe_ptp_gettime64;
+	adapter->ptp_caps.settime64 = txgbe_ptp_settime64;
+#else
+	adapter->ptp_caps.gettime = txgbe_ptp_gettime;
+	adapter->ptp_caps.settime = txgbe_ptp_settime;
+#endif
+	adapter->ptp_caps.enable = txgbe_ptp_feature_enable;
+
+	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
+						pci_dev_to_dev(adapter->pdev));
+	if (IS_ERR(adapter->ptp_clock)) {
+		err = PTR_ERR(adapter->ptp_clock);
+		adapter->ptp_clock = NULL;
+		e_dev_err("ptp_clock_register failed\n");
+		return err;
+	} else
+		e_dev_info("registered PHC device on %s\n", netdev->name);
+
+	/* Set the default timestamp mode to disabled here. We do this in
+	 * create_clock instead of initialization, because we don't want to
+	 * override the previous settings during a suspend/resume cycle.
+	 */
+	adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+	adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+
+	return 0;
+}
+
+/**
+ * txgbe_ptp_init
+ * @adapter: the txgbe private adapter structure
+ *
+ * This function performs the required steps for enabling ptp
+ * support. If ptp support has already been loaded it simply calls the
+ * cyclecounter init routine and exits.
+ */
+void txgbe_ptp_init(struct txgbe_adapter *adapter)
+{
+	/* initialize the spin lock first, since the user might call the clock
+	 * functions any time after we've initialized the ptp clock device.
+	 */
+	spin_lock_init(&adapter->tmreg_lock);
+
+	/* obtain a ptp clock device, or re-use an existing device */
+	if (txgbe_ptp_create_clock(adapter))
+		return;
+
+	/* we have a clock, so we can intialize work for timestamps now */
+	INIT_WORK(&adapter->ptp_tx_work, txgbe_ptp_tx_hwtstamp_work);
+
+	/* reset the ptp related hardware bits */
+	txgbe_ptp_reset(adapter);
+
+	/* enter the TXGBE_PTP_RUNNING state */
+	set_bit(__TXGBE_PTP_RUNNING, &adapter->state);
+
+	return;
+}
+
+/**
+ * txgbe_ptp_suspend - stop ptp work items
+ * @adapter: pointer to adapter struct
+ *
+ * This function suspends ptp activity, and prevents more work from being
+ * generated, but does not destroy the clock device.
+ */
+void txgbe_ptp_suspend(struct txgbe_adapter *adapter)
+{
+	/* leave the TXGBE_PTP_RUNNING STATE */
+	if (!test_and_clear_bit(__TXGBE_PTP_RUNNING, &adapter->state))
+		return;
+
+	adapter->flags2 &= ~TXGBE_FLAG2_PTP_PPS_ENABLED;
+
+	cancel_work_sync(&adapter->ptp_tx_work);
+	txgbe_ptp_clear_tx_timestamp(adapter);
+}
+
+/**
+ * txgbe_ptp_stop - destroy the ptp_clock device
+ * @adapter: pointer to adapter struct
+ *
+ * Completely destroy the ptp_clock device, and disable all PTP related
+ * features. Intended to be run when the device is being closed.
+ */
+void txgbe_ptp_stop(struct txgbe_adapter *adapter)
+{
+	/* first, suspend ptp activity */
+	txgbe_ptp_suspend(adapter);
+
+	/* now destroy the ptp clock device */
+	if (adapter->ptp_clock) {
+		ptp_clock_unregister(adapter->ptp_clock);
+		adapter->ptp_clock = NULL;
+		e_dev_info("removed PHC on %s\n",
+			   adapter->netdev->name);
+	}
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.c
new file mode 100644
index 000000000000..c14141f5fd29
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.c
@@ -0,0 +1,1818 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_sriov.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+
+#include "txgbe.h"
+#include "txgbe_type.h"
+#include "txgbe_sriov.h"
+
+static void txgbe_set_vf_rx_tx(struct txgbe_adapter *adapter, int vf);
+
+
+#ifdef CONFIG_PCI_IOV
+static int __txgbe_enable_sriov(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int num_vf_macvlans, i;
+	struct vf_macvlans *mv_list;
+	u32 value = 0;
+
+	adapter->flags |= TXGBE_FLAG_SRIOV_ENABLED;
+	e_dev_info("SR-IOV enabled with %d VFs\n", adapter->num_vfs);
+
+	if (adapter->num_vfs != 1) {
+		if (adapter->ring_feature[RING_F_RSS].indices == 4)
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_32;
+		else /* adapter->ring_feature[RING_F_RSS].indices <= 2 */
+			value = TXGBE_CFG_PORT_CTL_NUM_VT_64;
+	}
+	wr32m(hw, TXGBE_CFG_PORT_CTL,
+	      TXGBE_CFG_PORT_CTL_NUM_VT_MASK,
+	      value);
+
+	/* Enable VMDq flag so device will be set in VM mode */
+	adapter->flags |= TXGBE_FLAG_VMDQ_ENABLED;
+	if (!adapter->ring_feature[RING_F_VMDQ].limit)
+		adapter->ring_feature[RING_F_VMDQ].limit = 1;
+	adapter->ring_feature[RING_F_VMDQ].offset = adapter->num_vfs;
+
+	num_vf_macvlans = hw->mac.num_rar_entries -
+		(TXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
+
+	adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
+					     sizeof(struct vf_macvlans),
+					     GFP_KERNEL);
+	if (mv_list) {
+		/* Initialize list of VF macvlans */
+		INIT_LIST_HEAD(&adapter->vf_mvs.l);
+		for (i = 0; i < num_vf_macvlans; i++) {
+			mv_list->vf = -1;
+			mv_list->free = true;
+			list_add(&mv_list->l, &adapter->vf_mvs.l);
+			mv_list++;
+		}
+	}
+
+	/* Initialize default switching mode VEB */
+	wr32m(hw, TXGBE_PSR_CTL,
+		TXGBE_PSR_CTL_SW_EN, TXGBE_PSR_CTL_SW_EN);
+
+	/* If call to enable VFs succeeded then allocate memory
+	 * for per VF control structures.
+	 */
+	adapter->vfinfo = kcalloc(adapter->num_vfs,
+			sizeof(struct vf_data_storage), GFP_KERNEL);
+	if (!adapter->vfinfo)
+		return -ENOMEM;
+
+	/* enable L2 switch and replication */
+	adapter->flags |= TXGBE_FLAG_SRIOV_L2SWITCH_ENABLE |
+			  TXGBE_FLAG_SRIOV_REPLICATION_ENABLE;
+
+	/* limit traffic classes based on VFs enabled */
+	if (adapter->num_vfs < 16) {
+		adapter->dcb_cfg.num_tcs.pg_tcs =
+			TXGBE_DCB_MAX_TRAFFIC_CLASS;
+		adapter->dcb_cfg.num_tcs.pfc_tcs =
+			TXGBE_DCB_MAX_TRAFFIC_CLASS;
+	} else if (adapter->num_vfs < 32) {
+		adapter->dcb_cfg.num_tcs.pg_tcs = 4;
+		adapter->dcb_cfg.num_tcs.pfc_tcs = 4;
+	} else {
+		adapter->dcb_cfg.num_tcs.pg_tcs = 1;
+		adapter->dcb_cfg.num_tcs.pfc_tcs = 1;
+	}
+	adapter->dcb_cfg.vt_mode = true;
+
+#ifdef TXGBE_DISABLE_VF_MQ
+	/* We do not support RSS w/ SR-IOV */
+	adapter->ring_feature[RING_F_RSS].limit = 1;
+#endif
+
+	/* Disable RSC when in SR-IOV mode */
+	adapter->flags2 &= ~(TXGBE_FLAG2_RSC_CAPABLE |
+				TXGBE_FLAG2_RSC_ENABLED);
+
+	/* enable spoof checking for all VFs */
+	for (i = 0; i < adapter->num_vfs; i++) {
+		/* enable spoof checking for all VFs */
+		adapter->vfinfo[i].spoofchk_enabled = true;
+		adapter->vfinfo[i].link_enable = true;
+
+#ifdef HAVE_NDO_SET_VF_RSS_QUERY_EN
+		/* We support VF RSS querying only for 82599 and x540
+		 * devices at the moment. These devices share RSS
+		 * indirection table and RSS hash key with PF therefore
+		 * we want to disable the querying by default.
+		 */
+		adapter->vfinfo[i].rss_query_enabled = 0;
+
+#endif
+
+		/* Untrust all VFs */
+		adapter->vfinfo[i].trusted = false;
+
+		/* set the default xcast mode */
+		adapter->vfinfo[i].xcast_mode = TXGBEVF_XCAST_MODE_NONE;
+	}
+
+	return 0;
+}
+
+#define TXGBE_BA4_ADDR(vfinfo, reg) \
+	((u8 __iomem *)((u8 *)(vfinfo)->b4_addr + (reg)))
+static int txgbe_vf_backup(struct txgbe_adapter *adapter, u16 vf)
+{
+	struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+	if (!vfinfo->b4_addr)
+		return -1;
+#if 0
+	for (i = 0; i < 16; i++) {
+		vfinfo->b4_buf[i] = 
+			txgbe_rd32(TXGBE_BA4_ADDR(vfinfo, i * 4));
+	}
+#endif
+	return 0;
+}
+
+static int txgbe_vf_restore(struct txgbe_adapter *adapter, u16 vf)
+{
+	struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+	if (!vfinfo->b4_addr)
+		return -1;
+#if 0
+	for (i = 0; i < 16; i++) {
+		txgbe_wr32(TXGBE_BA4_ADDR(vfinfo, i * 4),
+			   vfinfo->b4_buf[i]);
+	}
+#endif
+	return 0;
+}
+
+/**
+ * txgbe_get_vfs - Find and take references to all vf devices
+ * @adapter: Pointer to adapter struct
+ */
+static void txgbe_get_vfs(struct txgbe_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	u16 vendor = pdev->vendor;
+	struct pci_dev *vfdev;
+	int vf = 0;
+	u16 vf_id;
+	int pos;
+
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos)
+		return;
+	pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id);
+
+	vfdev = pci_get_device(vendor, vf_id, NULL);
+	for (; vfdev; vfdev = pci_get_device(vendor, vf_id, vfdev)) {
+		struct vf_data_storage *vfinfo;
+		if (!vfdev->is_virtfn)
+			continue;
+		if (vfdev->physfn != pdev)
+			continue;
+		if (vf >= adapter->num_vfs)
+			continue;
+
+		/*pci_dev_get(vfdev);*/
+		vfinfo = &adapter->vfinfo[vf];
+		vfinfo->vfdev = vfdev;
+		vfinfo->b4_addr = ioremap(pci_resource_start(vfdev, 4), 64);
+#ifdef CONFIG_PCI_IOV
+		txgbe_vf_backup(adapter, vf);
+#endif
+		++vf;
+	}
+}
+
+/**
+ * txgbe_pet_vfs - Release references to all vf devices
+ * @adapter: Pointer to adapter struct
+ */
+static void txgbe_put_vfs(struct txgbe_adapter *adapter)
+{
+	unsigned int num_vfs = adapter->num_vfs, vf;
+
+	/* put the reference to all of the vf devices */
+	for (vf = 0; vf < num_vfs; ++vf) {
+		struct vf_data_storage *vfinfo;
+		struct pci_dev *vfdev = adapter->vfinfo[vf].vfdev;
+
+		if (!vfdev)
+			continue;
+
+#ifdef CONFIG_PCI_IOV
+		txgbe_vf_restore(adapter, vf);
+#endif
+
+		vfinfo = &adapter->vfinfo[vf];
+		iounmap(vfinfo->b4_addr);
+		vfinfo->b4_addr = NULL;
+		vfinfo->vfdev = NULL;
+		/*pci_dev_put(vfdev);*/
+	}
+}
+
+/* Note this function is called when the user wants to enable SR-IOV
+ * VFs using the now deprecated module parameter
+ */
+void txgbe_enable_sriov(struct txgbe_adapter *adapter)
+{
+	int pre_existing_vfs = 0;
+
+	pre_existing_vfs = pci_num_vf(adapter->pdev);
+	if (!pre_existing_vfs && !adapter->num_vfs)
+		return;
+
+	/* If there are pre-existing VFs then we have to force
+	 * use of that many - over ride any module parameter value.
+	 * This may result from the user unloading the PF driver
+	 * while VFs were assigned to guest VMs or because the VFs
+	 * have been created via the new PCI SR-IOV sysfs interface.
+	 */
+	if (pre_existing_vfs) {
+		adapter->num_vfs = pre_existing_vfs;
+		dev_warn(&adapter->pdev->dev,
+			 "Virtual Functions already enabled for this device -"
+			 "Please reload all VF drivers to avoid spoofed packet "
+			 "errors\n");
+	} else {
+		int err;
+		int match;
+		/*
+		 * The sapphire supports up to 64 VFs per physical function
+		 * but this implementation limits allocation to 63 so that
+		 * basic networking resources are still available to the
+		 * physical function.  If the user requests greater thn
+		 * 63 VFs then it is an error - reset to default of zero.
+		 */
+		match = min_t(unsigned int, adapter->vf_mode, TXGBE_MAX_VFS_DRV_LIMIT);
+		adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, match);
+
+		err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+		if (err) {
+			e_err(probe, "Failed to enable PCI sriov: %d\n", err);
+			adapter->num_vfs = 0;
+			return;
+		}
+	}
+
+	if (!__txgbe_enable_sriov(adapter)) {
+		txgbe_get_vfs(adapter);
+		return;
+	}
+
+	/* If we have gotten to this point then there is no memory available
+	 * to manage the VF devices - print message and bail.
+	 */
+	e_err(probe, "Unable to allocate memory for VF Data Storage - "
+	      "SRIOV disabled\n");
+	txgbe_disable_sriov(adapter);
+}
+#endif /* CONFIG_PCI_IOV */
+
+int txgbe_disable_sriov(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+#ifdef CONFIG_PCI_IOV
+	/*
+	 * If our VFs are assigned we cannot shut down SR-IOV
+	 * without causing issues, so just leave the hardware
+	 * available but disabled
+	 */
+	if (pci_vfs_assigned(adapter->pdev)) {
+		e_dev_warn("Unloading driver while VFs are assigned -"
+			   "VFs will not be deallocated\n");
+		return -EPERM;
+	}
+	/* disable iov and allow time for transactions to clear */
+	pci_disable_sriov(adapter->pdev);
+#endif
+
+	/* set num VFs to 0 to prevent access to vfinfo */
+	adapter->num_vfs = 0;
+
+	/* put the reference to all of the vf devices */
+#ifdef CONFIG_PCI_IOV
+	txgbe_put_vfs(adapter);
+#endif
+
+	/* free VF control structures */
+	kfree(adapter->vfinfo);
+	adapter->vfinfo = NULL;
+
+	/* free macvlan list */
+	kfree(adapter->mv_list);
+	adapter->mv_list = NULL;
+
+	/* if SR-IOV is already disabled then there is nothing to do */
+	if (!(adapter->flags & TXGBE_FLAG_SRIOV_ENABLED))
+		return 0;
+
+#if 0
+#ifdef CONFIG_PCI_IOV
+	/*
+	 * If our VFs are assigned we cannot shut down SR-IOV
+	 * without causing issues, so just leave the hardware
+	 * available but disabled
+	 */
+	if (pci_vfs_assigned(adapter->pdev)) {
+		e_dev_warn("Unloading driver while VFs are assigned -"
+			   "VFs will not be deallocated\n");
+		return -EPERM;
+	}
+	/* disable iov and allow time for transactions to clear */
+	pci_disable_sriov(adapter->pdev);
+#endif
+#endif
+	/* set default pool back to 0 */
+	wr32m(hw, TXGBE_PSR_VM_CTL,
+		TXGBE_PSR_VM_CTL_POOL_MASK, 0);
+	TXGBE_WRITE_FLUSH(hw);
+
+	adapter->ring_feature[RING_F_VMDQ].offset = 0;
+
+	/* take a breather then clean up driver data */
+	msleep(100);
+
+	adapter->flags &= ~(TXGBE_FLAG_SRIOV_ENABLED |
+						TXGBE_FLAG_SRIOV_L2SWITCH_ENABLE |
+			  			TXGBE_FLAG_SRIOV_REPLICATION_ENABLE);
+
+	/* Disable VMDq flag so device will be set in VM mode */
+	if (adapter->ring_feature[RING_F_VMDQ].limit == 1) {
+		adapter->flags &= ~TXGBE_FLAG_VMDQ_ENABLED;
+
+	}
+
+	return 0;
+}
+
+static int txgbe_set_vf_multicasts(struct txgbe_adapter *adapter,
+				   u32 *msgbuf, u32 vf)
+{
+	u16 entries = (msgbuf[0] & TXGBE_VT_MSGINFO_MASK)
+		       >> TXGBE_VT_MSGINFO_SHIFT;
+	u16 *hash_list = (u16 *)&msgbuf[1];
+	struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+	struct txgbe_hw *hw = &adapter->hw;
+	int i;
+	u32 vector_bit;
+	u32 vector_reg;
+	u32 mta_reg;
+	u32 vmolr = rd32(hw, TXGBE_PSR_VM_L2CTL(vf));
+
+	/* only so many hash values supported */
+	entries = min(entries, (u16)TXGBE_MAX_VF_MC_ENTRIES);
+
+	/* salt away the number of multi cast addresses assigned
+	 * to this VF for later use to restore when the PF multi cast
+	 * list changes
+	 */
+	vfinfo->num_vf_mc_hashes = entries;
+
+	/* VFs are limited to using the MTA hash table for their multicast
+	 * addresses */
+	for (i = 0; i < entries; i++)
+		vfinfo->vf_mc_hashes[i] = hash_list[i];
+
+	for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) {
+		vector_reg = (vfinfo->vf_mc_hashes[i] >> 5) & 0x7F;
+		vector_bit = vfinfo->vf_mc_hashes[i] & 0x1F;
+		/* errata 5: maintain a copy of the register table conf */
+		mta_reg = hw->mac.mta_shadow[vector_reg];
+		mta_reg |= (1 << vector_bit);
+		hw->mac.mta_shadow[vector_reg] = mta_reg;
+		wr32(hw, TXGBE_PSR_MC_TBL(vector_reg), mta_reg);
+	}
+	vmolr |= TXGBE_PSR_VM_L2CTL_ROMPE;
+	wr32(hw, TXGBE_PSR_VM_L2CTL(vf), vmolr);
+
+	return 0;
+}
+
+void txgbe_restore_vf_multicasts(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct vf_data_storage *vfinfo;
+	u32 i, j;
+	u32 vector_bit;
+	u32 vector_reg;
+
+	for (i = 0; i < adapter->num_vfs; i++) {
+		u32 vmolr = rd32(hw, TXGBE_PSR_VM_L2CTL(i));
+		vfinfo = &adapter->vfinfo[i];
+		for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) {
+			hw->addr_ctrl.mta_in_use++;
+			vector_reg = (vfinfo->vf_mc_hashes[j] >> 5) & 0x7F;
+			vector_bit = vfinfo->vf_mc_hashes[j] & 0x1F;
+			wr32m(hw, TXGBE_PSR_MC_TBL(vector_reg),
+				1 << vector_bit, 1 << vector_bit);
+			/* errata 5: maintain a copy of the reg table conf */
+			hw->mac.mta_shadow[vector_reg] |= (1 << vector_bit);
+		}
+		if (vfinfo->num_vf_mc_hashes)
+			vmolr |= TXGBE_PSR_VM_L2CTL_ROMPE;
+		else
+			vmolr &= ~TXGBE_PSR_VM_L2CTL_ROMPE;
+		wr32(hw, TXGBE_PSR_VM_L2CTL(i), vmolr);
+	}
+
+	/* Restore any VF macvlans */
+	txgbe_full_sync_mac_table(adapter);
+}
+
+int txgbe_set_vf_vlan(struct txgbe_adapter *adapter, int add, int vid, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	/* VLAN 0 is a special case, don't allow it to be removed */
+	if (!vid && !add)
+		return 0;
+
+	return TCALL(hw, mac.ops.set_vfta, vid, vf, (bool)add);
+}
+
+static int txgbe_set_vf_lpe(struct txgbe_adapter *adapter, u32 max_frame,
+			    u32 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 max_frs, reg_val;
+
+	/*
+	 * For sapphire we have to keep all PFs and VFs operating with
+	 * the same max_frame value in order to avoid sending an oversize
+	 * frame to a VF.  In order to guarantee this is handled correctly
+	 * for all cases we have several special exceptions to take into
+	 * account before we can enable the VF for receive
+	 */
+	struct net_device *dev = adapter->netdev;
+	int pf_max_frame = dev->mtu + ETH_HLEN;
+	u32 reg_offset, vf_shift, vfre;
+	s32 err = 0;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (dev->features & NETIF_F_FCOE_MTU)
+		pf_max_frame = max_t(int, pf_max_frame,
+				     TXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif /* CONFIG_FCOE */
+
+	switch (adapter->vfinfo[vf].vf_api) {
+	case txgbe_mbox_api_11:
+	case txgbe_mbox_api_12:
+	case txgbe_mbox_api_13:
+		/*
+		 * Version 1.1 supports jumbo frames on VFs if PF has
+		 * jumbo frames enabled which means legacy VFs are
+		 * disabled
+		 */
+		if (pf_max_frame > ETH_FRAME_LEN)
+			break;
+		fallthrough;
+	default:
+		/*
+		 * If the PF or VF are running w/ jumbo frames enabled
+		 * we need to shut down the VF Rx path as we cannot
+		 * support jumbo frames on legacy VFs
+		 */
+		if ((pf_max_frame > ETH_FRAME_LEN) ||
+		    (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)))
+			err = -EINVAL;
+		break;
+	}
+
+	/* determine VF receive enable location */
+	vf_shift = vf % 32;
+	reg_offset = vf / 32;
+
+	/* enable or disable receive depending on error */
+	vfre = rd32(hw, TXGBE_RDM_VF_RE(reg_offset));
+	if (err)
+		vfre &= ~(1 << vf_shift);
+	else
+		vfre |= 1 << vf_shift;
+	wr32(hw, TXGBE_RDM_VF_RE(reg_offset), vfre);
+
+	if (err) {
+		e_err(drv, "VF max_frame %d out of range\n", max_frame);
+		return err;
+	}
+
+	/* pull current max frame size from hardware */
+	max_frs = DIV_ROUND_UP(max_frame, 1024);
+	reg_val = rd32(hw, TXGBE_MAC_WDG_TIMEOUT) &
+		TXGBE_MAC_WDG_TIMEOUT_WTO_MASK;
+	if (max_frs > (reg_val + TXGBE_MAC_WDG_TIMEOUT_WTO_DELTA)) {
+		wr32(hw, TXGBE_MAC_WDG_TIMEOUT,
+			max_frs - TXGBE_MAC_WDG_TIMEOUT_WTO_DELTA);
+	}
+
+	e_info(hw, "VF requests change max MTU to %d\n", max_frame);
+
+	return 0;
+}
+
+void txgbe_set_vmolr(struct txgbe_hw *hw, u16 vf, bool aupe)
+{
+	u32 vmolr = rd32(hw, TXGBE_PSR_VM_L2CTL(vf));
+	vmolr |=  TXGBE_PSR_VM_L2CTL_BAM;
+	if (aupe)
+		vmolr |= TXGBE_PSR_VM_L2CTL_AUPE;
+	else
+		vmolr &= ~TXGBE_PSR_VM_L2CTL_AUPE;
+	wr32(hw, TXGBE_PSR_VM_L2CTL(vf), vmolr);
+}
+
+static void txgbe_set_vmvir(struct txgbe_adapter *adapter,
+			    u16 vid, u16 qos, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) |
+		TXGBE_TDM_VLAN_INS_VLANA_DEFAULT;
+
+	wr32(hw, TXGBE_TDM_VLAN_INS(vf), vmvir);
+}
+
+static void txgbe_clear_vmvir(struct txgbe_adapter *adapter, u32 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	wr32(hw, TXGBE_TDM_VLAN_INS(vf), 0);
+}
+
+static inline void txgbe_vf_reset_event(struct txgbe_adapter *adapter, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+	u8 num_tcs = netdev_get_num_tc(adapter->netdev);
+
+	/* add PF assigned VLAN or VLAN 0 */
+	txgbe_set_vf_vlan(adapter, true, vfinfo->pf_vlan, vf);
+
+	/* reset offloads to defaults */
+	txgbe_set_vmolr(hw, vf, !vfinfo->pf_vlan);
+
+	/* set outgoing tags for VFs */
+	if (!vfinfo->pf_vlan && !vfinfo->pf_qos && !num_tcs) {
+		txgbe_clear_vmvir(adapter, vf);
+	} else {
+		if (vfinfo->pf_qos || !num_tcs)
+			txgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+					vfinfo->pf_qos, vf);
+		else
+			txgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+					adapter->default_up, vf);
+
+		if (vfinfo->spoofchk_enabled)
+			TCALL(hw, mac.ops.set_vlan_anti_spoofing, true, vf);
+	}
+
+	/* reset multicast table array for vf */
+	adapter->vfinfo[vf].num_vf_mc_hashes = 0;
+
+	/* Flush and reset the mta with the new values */
+	txgbe_set_rx_mode(adapter->netdev);
+
+	txgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
+
+	/* reset VF api back to unknown */
+	adapter->vfinfo[vf].vf_api = txgbe_mbox_api_10;
+}
+
+int txgbe_set_vf_mac(struct txgbe_adapter *adapter,
+		     u16 vf, unsigned char *mac_addr)
+{
+	s32 retval = 0;
+	txgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf);
+	retval = txgbe_add_mac_filter(adapter, mac_addr, vf);
+	if (retval >= 0)
+		memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr,
+		       ETH_ALEN);
+	else
+		memset(adapter->vfinfo[vf].vf_mac_addresses, 0, ETH_ALEN);
+
+	return retval;
+}
+
+static int txgbe_negotiate_vf_api(struct txgbe_adapter *adapter,
+				  u32 *msgbuf, u32 vf)
+{
+	int api = msgbuf[1];
+
+	switch (api) {
+	case txgbe_mbox_api_10:
+	case txgbe_mbox_api_11:
+	case txgbe_mbox_api_12:
+	case txgbe_mbox_api_13:
+		adapter->vfinfo[vf].vf_api = api;
+		return 0;
+	default:
+		break;
+	}
+
+	e_info(drv, "VF %d requested invalid api version %u\n", vf, api);
+
+	return -1;
+}
+
+static int txgbe_get_vf_queues(struct txgbe_adapter *adapter,
+			       u32 *msgbuf, u32 vf)
+{
+	struct net_device *dev = adapter->netdev;
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	unsigned int default_tc = 0;
+	u8 num_tcs = netdev_get_num_tc(dev);
+
+	/* verify the PF is supporting the correct APIs */
+	switch (adapter->vfinfo[vf].vf_api) {
+	case txgbe_mbox_api_20:
+	case txgbe_mbox_api_13:
+	case txgbe_mbox_api_12:
+	case txgbe_mbox_api_11:
+		break;
+	default:
+		return -1;
+	}
+
+	/* only allow 1 Tx queue for bandwidth limiting */
+	msgbuf[TXGBE_VF_TX_QUEUES] = __ALIGN_MASK(1, ~vmdq->mask);
+	msgbuf[TXGBE_VF_RX_QUEUES] = __ALIGN_MASK(1, ~vmdq->mask);
+
+	/* if TCs > 1 determine which TC belongs to default user priority */
+	if (num_tcs > 1)
+		default_tc = netdev_get_prio_tc_map(dev, adapter->default_up);
+
+	/* notify VF of need for VLAN tag stripping, and correct queue */
+	if (num_tcs)
+		msgbuf[TXGBE_VF_TRANS_VLAN] = num_tcs;
+	else if (adapter->vfinfo[vf].pf_vlan || adapter->vfinfo[vf].pf_qos)
+		msgbuf[TXGBE_VF_TRANS_VLAN] = 1;
+	else
+		msgbuf[TXGBE_VF_TRANS_VLAN] = 0;
+
+	/* notify VF of default queue */
+	if(adapter->vf_mode == 63)
+		msgbuf[TXGBE_VF_DEF_QUEUE] = default_tc;
+	else if( adapter->vf_mode == 31)
+		msgbuf[TXGBE_VF_DEF_QUEUE] = 4;
+	else
+		msgbuf[TXGBE_VF_DEF_QUEUE] = default_tc;
+
+
+	return 0;
+}
+
+static int txgbe_set_vf_macvlan(struct txgbe_adapter *adapter,
+				u16 vf, int index, unsigned char *mac_addr)
+{
+	struct list_head *pos;
+	struct vf_macvlans *entry;
+	s32 retval = 0;
+
+	if (index <= 1) {
+		list_for_each(pos, &adapter->vf_mvs.l) {
+			entry = list_entry(pos, struct vf_macvlans, l);
+			if (entry->vf == vf) {
+				entry->vf = -1;
+				entry->free = true;
+				entry->is_macvlan = false;
+				txgbe_del_mac_filter(adapter,
+						     entry->vf_macvlan, vf);
+			}
+		}
+	}
+
+	/*
+	 * If index was zero then we were asked to clear the uc list
+	 * for the VF.  We're done.
+	 */
+	if (!index)
+		return 0;
+
+	entry = NULL;
+
+	list_for_each(pos, &adapter->vf_mvs.l) {
+		entry = list_entry(pos, struct vf_macvlans, l);
+		if (entry->free)
+			break;
+	}
+
+	/*
+	 * If we traversed the entire list and didn't find a free entry
+	 * then we're out of space on the RAR table.  Also entry may
+	 * be NULL because the original memory allocation for the list
+	 * failed, which is not fatal but does mean we can't support
+	 * VF requests for MACVLAN because we couldn't allocate
+	 * memory for the list management required.
+	 */
+	if (!entry || !entry->free)
+		return -ENOSPC;
+
+	retval = txgbe_add_mac_filter(adapter, mac_addr, vf);
+	if (retval >= 0) {
+		entry->free = false;
+		entry->is_macvlan = true;
+		entry->vf = vf;
+		memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
+	}
+
+	return retval;
+}
+
+#ifdef CONFIG_PCI_IOV
+int txgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
+{
+	unsigned char vf_mac_addr[6];
+	struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+	unsigned int vfn = (event_mask & 0x3f);
+	bool enable = ((event_mask & 0x10000000U) != 0);
+
+	if (enable) {
+		memset(vf_mac_addr, 0, ETH_ALEN);
+		memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
+static inline void txgbe_write_qde(struct txgbe_adapter *adapter, u32 vf,
+				   u32 qde)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+	u32 reg = 0;
+	u32 i = vf * q_per_pool;
+	u32 n = i / 32;
+	reg = rd32(hw, TXGBE_RDM_PF_QDE(n));
+	for (i = (vf * q_per_pool - n * 32);
+	     i < ((vf + 1) * q_per_pool - n * 32);
+	     i++) {
+		if (qde == 1)
+			reg |= qde << i;
+		else
+			reg &= qde << i;
+	}
+
+	wr32(hw, TXGBE_RDM_PF_QDE(n), reg);
+
+}
+
+static inline void txgbe_write_hide_vlan(struct txgbe_adapter *adapter, u32 vf,
+				   u32 hide_vlan)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+	u32 reg = 0;
+	u32 i = vf * q_per_pool;
+	u32 n = i / 32;
+	reg = rd32(hw, TXGBE_RDM_PF_HIDE(n));
+	for (i = (vf * q_per_pool - n * 32);
+	     i < ((vf + 1) * q_per_pool - n * 32);
+	     i++) {
+		if (hide_vlan == 1)
+			reg |= hide_vlan << i;
+		else
+			reg &= hide_vlan << i;
+	}
+
+	wr32(hw, TXGBE_RDM_PF_HIDE(n), reg);
+}
+
+static int txgbe_vf_reset_msg(struct txgbe_adapter *adapter, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
+	u32 reg = 0;
+	u32 reg_offset, vf_shift;
+	u32 msgbuf[4] = {0, 0, 0, 0};
+	u8 *addr = (u8 *)(&msgbuf[1]);
+	struct net_device *dev = adapter->netdev;
+	int pf_max_frame;
+
+	e_info(probe, "VF Reset msg received from vf %d\n", vf);
+
+#ifdef CONFIG_PCI_IOV
+	txgbe_vf_restore(adapter, vf);
+#endif
+
+	/* reset the filters for the device */
+	txgbe_vf_reset_event(adapter, vf);
+
+	/* set vf mac address */
+	if (!is_zero_ether_addr(vf_mac))
+		txgbe_set_vf_mac(adapter, vf, vf_mac);
+
+	vf_shift = vf % 32;
+	reg_offset = vf / 32;
+
+	/* force drop enable for all VF Rx queues */
+	txgbe_write_qde(adapter, vf, 1);
+
+	/* set transmit and receive for vf */
+	txgbe_set_vf_rx_tx(adapter, vf);
+
+	pf_max_frame = dev->mtu + ETH_HLEN;
+
+#if IS_ENABLED(CONFIG_FCOE)
+	if (dev->features & NETIF_F_FCOE_MTU)
+		pf_max_frame = max_t(int, pf_max_frame,
+				     TXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif /* CONFIG_FCOE */
+
+	if (pf_max_frame > ETH_FRAME_LEN)
+		reg = (1 << vf_shift);
+	wr32(hw, TXGBE_RDM_VFRE_CLR(reg_offset), reg);
+
+	/* enable VF mailbox for further messages */
+	adapter->vfinfo[vf].clear_to_send = true;
+
+	/* reply to reset with ack and vf mac address */
+	msgbuf[0] = TXGBE_VF_RESET;
+	if (!is_zero_ether_addr(vf_mac)) {
+		msgbuf[0] |= TXGBE_VT_MSGTYPE_ACK;
+		memcpy(addr, vf_mac, ETH_ALEN);
+	} else {
+		msgbuf[0] |= TXGBE_VT_MSGTYPE_NACK;
+		dev_warn(pci_dev_to_dev(adapter->pdev),
+			 "VF %d has no MAC address assigned, you may have to "
+			 "assign one manually\n", vf);
+	}
+
+	/*
+	 * Piggyback the multicast filter type so VF can compute the
+	 * correct vectors
+	 */
+	msgbuf[3] = hw->mac.mc_filter_type;
+	txgbe_write_mbx(hw, msgbuf, TXGBE_VF_PERMADDR_MSG_LEN, vf);
+
+	return 0;
+}
+
+static int txgbe_set_vf_mac_addr(struct txgbe_adapter *adapter,
+				 u32 *msgbuf, u16 vf)
+{
+	u8 *new_mac = ((u8 *)(&msgbuf[1]));
+
+	if (!is_valid_ether_addr(new_mac)) {
+		e_warn(drv, "VF %d attempted to set invalid mac\n", vf);
+		return -1;
+	}
+
+	if (adapter->vfinfo[vf].pf_set_mac &&
+	    memcmp(adapter->vfinfo[vf].vf_mac_addresses, new_mac,
+		   ETH_ALEN)) {
+		u8 *pm = adapter->vfinfo[vf].vf_mac_addresses;
+		e_warn(drv,
+		       "VF %d attempted to set a new MAC address but it already "
+		       "has an administratively set MAC address "
+		       "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+		       vf, pm[0], pm[1], pm[2], pm[3], pm[4], pm[5]);
+		e_warn(drv, "Check the VF driver and if it is not using the "
+		       "correct MAC address you may need to reload the VF "
+		       "driver\n");
+		return -1;
+	}
+	return txgbe_set_vf_mac(adapter, vf, new_mac) < 0;
+}
+
+#ifdef CONFIG_PCI_IOV
+static int txgbe_find_vlvf_entry(struct txgbe_hw *hw, u32 vlan)
+{
+	u32 vlvf;
+	s32 regindex;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
+
+	/* Search for the vlan id in the VLVF entries */
+	for (regindex = 1; regindex < TXGBE_PSR_VLAN_SWC_ENTRIES; regindex++) {
+		wr32(hw, TXGBE_PSR_VLAN_SWC_IDX, regindex);
+		vlvf = rd32(hw, TXGBE_PSR_VLAN_SWC);
+		if ((vlvf & VLAN_VID_MASK) == vlan)
+			break;
+	}
+
+	/* Return a negative value if not found */
+	if (regindex >= TXGBE_PSR_VLAN_SWC_ENTRIES)
+		regindex = -1;
+
+	return regindex;
+}
+#endif /* CONFIG_PCI_IOV */
+
+static int txgbe_set_vf_vlan_msg(struct txgbe_adapter *adapter,
+				 u32 *msgbuf, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int add = (msgbuf[0] & TXGBE_VT_MSGINFO_MASK) >> TXGBE_VT_MSGINFO_SHIFT;
+	int vid = (msgbuf[1] & TXGBE_PSR_VLAN_SWC_VLANID_MASK);
+	int err;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	if (adapter->vfinfo[vf].pf_vlan || tcs) {
+		e_warn(drv,
+		       "VF %d attempted to override administratively set VLAN "
+		       "configuration\n"
+		       "Reload the VF driver to resume operations\n",
+		       vf);
+		return 0;
+	}
+
+	if (add)
+		adapter->vfinfo[vf].vlan_count++;
+	else if (adapter->vfinfo[vf].vlan_count)
+		adapter->vfinfo[vf].vlan_count--;
+
+	/* in case of promiscuous mode any VLAN filter set for a VF must
+	 * also have the PF pool added to it.
+	 */
+	if (add && adapter->netdev->flags & IFF_PROMISC)
+		err = txgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
+
+	err = txgbe_set_vf_vlan(adapter, add, vid, vf);
+	if (!err && adapter->vfinfo[vf].spoofchk_enabled)
+		TCALL(hw, mac.ops.set_vlan_anti_spoofing, true, vf);
+
+#ifdef CONFIG_PCI_IOV
+	/* Go through all the checks to see if the VLAN filter should
+	 * be wiped completely.
+	 */
+	if (!add && adapter->netdev->flags & IFF_PROMISC) {
+		u32 bits, vlvf;
+		s32 reg_ndx;
+
+		reg_ndx = txgbe_find_vlvf_entry(hw, vid);
+		if (reg_ndx < 0)
+			goto out;
+		wr32(hw, TXGBE_PSR_VLAN_SWC_IDX, reg_ndx);
+		vlvf = rd32(hw, TXGBE_PSR_VLAN_SWC);
+		/* See if any other pools are set for this VLAN filter
+		 * entry other than the PF.
+		 */
+		if (VMDQ_P(0) < 32) {
+			bits = rd32(hw, TXGBE_PSR_VLAN_SWC_VM_L);
+			bits &= ~(1 << VMDQ_P(0));
+			bits |= rd32(hw,
+					       TXGBE_PSR_VLAN_SWC_VM_H);
+		} else {
+			bits = rd32(hw,
+					      TXGBE_PSR_VLAN_SWC_VM_H);
+			bits &= ~(1 << (VMDQ_P(0) - 32));
+			bits |= rd32(hw, TXGBE_PSR_VLAN_SWC_VM_L);
+		}
+
+		/* If the filter was removed then ensure PF pool bit
+		 * is cleared if the PF only added itself to the pool
+		 * because the PF is in promiscuous mode.
+		 */
+		if ((vlvf & VLAN_VID_MASK) == vid &&
+#ifndef HAVE_VLAN_RX_REGISTER
+		    !test_bit(vid, adapter->active_vlans) &&
+#endif
+		    !bits)
+			txgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
+	}
+
+out:
+#endif
+	return err;
+}
+
+static int txgbe_set_vf_macvlan_msg(struct txgbe_adapter *adapter,
+				    u32 *msgbuf, u16 vf)
+{
+	u8 *new_mac = ((u8 *)(&msgbuf[1]));
+	int index = (msgbuf[0] & TXGBE_VT_MSGINFO_MASK) >>
+		    TXGBE_VT_MSGINFO_SHIFT;
+	int err;
+
+	if (adapter->vfinfo[vf].pf_set_mac && index > 0) {
+		e_warn(drv,
+			"VF %d requested MACVLAN filter but is administratively denied\n",
+			vf);
+		return 0;
+	}
+
+	/* An non-zero index indicates the VF is setting a filter */
+	if (index) {
+		if (!is_valid_ether_addr(new_mac)) {
+			e_warn(drv, "VF %d attempted to set invalid mac\n", vf);
+			return -1;
+		}
+#if defined(IFLA_VF_MAX) && defined(HAVE_VF_SPOOFCHK_CONFIGURE)
+		/*
+		 * If the VF is allowed to set MAC filters then turn off
+		 * anti-spoofing to avoid false positives.
+		 */
+		if (adapter->vfinfo[vf].spoofchk_enabled)
+			txgbe_ndo_set_vf_spoofchk(adapter->netdev, vf, false);
+#endif /* defined(IFLA_VF_MAX) && defined(HAVE_VF_SPOOFCHK_CONFIGURE) */
+	}
+
+	err = txgbe_set_vf_macvlan(adapter, vf, index, new_mac);
+	if (err == -ENOSPC)
+		e_warn(drv,
+		       "VF %d has requested a MACVLAN filter but there is no "
+		       "space for it\n",
+		       vf);
+
+	return err < 0;
+}
+
+static int txgbe_update_vf_xcast_mode(struct txgbe_adapter *adapter,
+				      u32 *msgbuf, u32 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int xcast_mode = msgbuf[1];
+	u32 vmolr, disable, enable;
+
+	/* verify the PF is supporting the correct APIs */
+	switch (adapter->vfinfo[vf].vf_api) {
+	case txgbe_mbox_api_12:
+		/* promisc introduced in 1.3 version */
+		if (xcast_mode == TXGBEVF_XCAST_MODE_PROMISC)
+			return -EOPNOTSUPP;
+		/* Fall threw */
+	case txgbe_mbox_api_13:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	if (adapter->vfinfo[vf].xcast_mode == xcast_mode)
+		goto out;
+
+	switch (xcast_mode) {
+	case TXGBEVF_XCAST_MODE_NONE:
+		disable = TXGBE_PSR_VM_L2CTL_BAM | TXGBE_PSR_VM_L2CTL_ROMPE |
+			  TXGBE_PSR_VM_L2CTL_MPE | TXGBE_PSR_VM_L2CTL_UPE | TXGBE_PSR_VM_L2CTL_VPE;
+		enable = 0;
+		break;
+	case TXGBEVF_XCAST_MODE_MULTI:
+		disable = TXGBE_PSR_VM_L2CTL_MPE | TXGBE_PSR_VM_L2CTL_UPE | TXGBE_PSR_VM_L2CTL_VPE;
+		enable = TXGBE_PSR_VM_L2CTL_BAM | TXGBE_PSR_VM_L2CTL_ROMPE;
+		break;
+	case TXGBEVF_XCAST_MODE_ALLMULTI:
+		disable = TXGBE_PSR_VM_L2CTL_UPE | TXGBE_PSR_VM_L2CTL_VPE;
+		enable = TXGBE_PSR_VM_L2CTL_BAM | TXGBE_PSR_VM_L2CTL_ROMPE | TXGBE_PSR_VM_L2CTL_MPE;
+		break;
+	case TXGBEVF_XCAST_MODE_PROMISC:
+		disable = 0;
+		enable = TXGBE_PSR_VM_L2CTL_BAM | TXGBE_PSR_VM_L2CTL_ROMPE |
+			 TXGBE_PSR_VM_L2CTL_MPE | TXGBE_PSR_VM_L2CTL_UPE | TXGBE_PSR_VM_L2CTL_VPE;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	vmolr = rd32(hw, TXGBE_PSR_VM_L2CTL(vf));
+	vmolr &= ~disable;
+	vmolr |= enable;
+	wr32(hw, TXGBE_PSR_VM_L2CTL(vf), vmolr);
+
+	adapter->vfinfo[vf].xcast_mode = xcast_mode;
+
+out:
+	msgbuf[1] = xcast_mode;
+
+	return 0;
+}
+
+static int txgbe_get_vf_link_state(struct txgbe_adapter *adapter,
+				   u32 *msgbuf, u32 vf)
+{
+	u32 *link_state = &msgbuf[1];
+
+	/* verify the PF is supporting the correct API */
+	switch (adapter->vfinfo[vf].vf_api) {
+	case txgbe_mbox_api_12:
+	case txgbe_mbox_api_13:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	*link_state = adapter->vfinfo[vf].link_enable;
+
+	return 0;
+}
+
+static int txgbe_rcv_msg_from_vf(struct txgbe_adapter *adapter, u16 vf)
+{
+	u16 mbx_size = TXGBE_VXMAILBOX_SIZE;
+	u32 msgbuf[TXGBE_VXMAILBOX_SIZE];
+	struct txgbe_hw *hw = &adapter->hw;
+	s32 retval;
+
+	retval = txgbe_read_mbx(hw, msgbuf, mbx_size, vf);
+
+	if (retval) {
+		pr_err("Error receiving message from VF\n");
+		return retval;
+	}
+
+	/* this is a message we already processed, do nothing */
+	if (msgbuf[0] & (TXGBE_VT_MSGTYPE_ACK | TXGBE_VT_MSGTYPE_NACK))
+		return retval;
+
+	/* flush the ack before we write any messages back */
+	TXGBE_WRITE_FLUSH(hw);
+
+	if (msgbuf[0] == TXGBE_VF_RESET)
+		return txgbe_vf_reset_msg(adapter, vf);
+
+	/*
+	 * until the vf completes a virtual function reset it should not be
+	 * allowed to start any configuration.
+	 */
+
+	if (!adapter->vfinfo[vf].clear_to_send) {
+		msgbuf[0] |= TXGBE_VT_MSGTYPE_NACK;
+		txgbe_write_mbx(hw, msgbuf, 1, vf);
+		return retval;
+	}
+
+	switch ((msgbuf[0] & 0xFFFF)) {
+	case TXGBE_VF_SET_MAC_ADDR:
+		retval = txgbe_set_vf_mac_addr(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_SET_MULTICAST:
+		retval = txgbe_set_vf_multicasts(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_SET_VLAN:
+		retval = txgbe_set_vf_vlan_msg(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_SET_LPE:
+		if (msgbuf[1] > TXGBE_MAX_JUMBO_FRAME_SIZE) {
+			e_err(drv, "VF max_frame %d out of range\n", msgbuf[1]);
+			return -EINVAL;
+		}
+		retval = txgbe_set_vf_lpe(adapter, msgbuf[1], vf);
+		break;
+	case TXGBE_VF_SET_MACVLAN:
+		retval = txgbe_set_vf_macvlan_msg(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_API_NEGOTIATE:
+		retval = txgbe_negotiate_vf_api(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_GET_QUEUES:
+		retval = txgbe_get_vf_queues(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_UPDATE_XCAST_MODE:
+		retval = txgbe_update_vf_xcast_mode(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_GET_LINK_STATE:
+		retval = txgbe_get_vf_link_state(adapter, msgbuf, vf);
+		break;
+	case TXGBE_VF_BACKUP:
+#ifdef CONFIG_PCI_IOV
+		retval = txgbe_vf_backup(adapter, vf);
+#endif
+		break;
+	default:
+		e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
+		retval = TXGBE_ERR_MBX;
+		break;
+	}
+
+	/* notify the VF of the results of what it sent us */
+	if (retval)
+		msgbuf[0] |= TXGBE_VT_MSGTYPE_NACK;
+	else
+		msgbuf[0] |= TXGBE_VT_MSGTYPE_ACK;
+
+	msgbuf[0] |= TXGBE_VT_MSGTYPE_CTS;
+
+	txgbe_write_mbx(hw, msgbuf, mbx_size, vf);
+
+	return retval;
+}
+
+static void txgbe_rcv_ack_from_vf(struct txgbe_adapter *adapter, u16 vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 msg = TXGBE_VT_MSGTYPE_NACK;
+
+	/* if device isn't clear to send it shouldn't be reading either */
+	if (!adapter->vfinfo[vf].clear_to_send)
+		txgbe_write_mbx(hw, &msg, 1, vf);
+}
+
+void txgbe_msg_task(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u16 vf;
+
+	for (vf = 0; vf < adapter->num_vfs; vf++) {
+		/* process any reset requests */
+		if (!txgbe_check_for_rst(hw, vf))
+			txgbe_vf_reset_event(adapter, vf);
+
+		/* process any messages pending */
+		if (!txgbe_check_for_msg(hw, vf))
+			txgbe_rcv_msg_from_vf(adapter, vf);
+
+		/* process any acks */
+		if (!txgbe_check_for_ack(hw, vf))
+			txgbe_rcv_ack_from_vf(adapter, vf);
+	}
+}
+
+void txgbe_disable_tx_rx(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+
+	/* disable transmit and receive for all vfs */
+	wr32(hw, TXGBE_TDM_VF_TE(0), 0);
+	wr32(hw, TXGBE_TDM_VF_TE(1), 0);
+
+	wr32(hw, TXGBE_RDM_VF_RE(0), 0);
+	wr32(hw, TXGBE_RDM_VF_RE(1), 0);
+}
+
+static inline void txgbe_ping_vf(struct txgbe_adapter *adapter, int vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 ping;
+
+	ping = TXGBE_PF_CONTROL_MSG;
+	if (adapter->vfinfo[vf].clear_to_send)
+		ping |= TXGBE_VT_MSGTYPE_CTS;
+	txgbe_write_mbx(hw, &ping, 1, vf);
+}
+
+void txgbe_ping_all_vfs(struct txgbe_adapter *adapter)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 ping;
+	u16 i;
+
+	for (i = 0 ; i < adapter->num_vfs; i++) {
+		ping = TXGBE_PF_CONTROL_MSG;
+		if (adapter->vfinfo[i].clear_to_send)
+			ping |= TXGBE_VT_MSGTYPE_CTS;
+		txgbe_write_mbx(hw, &ping, 1, i);
+	}
+}
+
+/**
+ * ixgbe_set_all_vfs - update vfs queues
+ * @adapter: Pointer to adapter struct
+ *
+ * Update setting transmit and receive queues for all vfs
+ **/
+void txgbe_set_all_vfs(struct txgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0 ; i < adapter->num_vfs; i++) {
+		txgbe_set_vf_link_state(adapter, i,
+					adapter->vfinfo[i].link_state);
+	}
+}
+
+#ifdef HAVE_NDO_SET_VF_TRUST
+int txgbe_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (vf >= adapter->num_vfs)
+		return -EINVAL;
+
+	/* nothing to do */
+	if (adapter->vfinfo[vf].trusted == setting)
+		return 0;
+
+	adapter->vfinfo[vf].trusted = setting;
+
+	/* reset VF to reconfigure features */
+	adapter->vfinfo[vf].clear_to_send = false;
+	txgbe_ping_vf(adapter, vf);
+
+	e_info(drv, "VF %u is %strusted\n", vf, setting ? "" : "not ");
+
+	return 0;
+}
+#endif
+
+static int txgbe_pci_sriov_enable(struct pci_dev __maybe_unused *dev,
+	int __maybe_unused num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+	struct txgbe_adapter *adapter = pci_get_drvdata(dev);
+	int err = 0;
+	int i;
+	int pre_existing_vfs = pci_num_vf(dev);
+
+	if (!(adapter->flags & TXGBE_FLAG_SRIOV_CAPABLE)) {
+		e_dev_warn("SRIOV not supported on this device\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+		err = txgbe_disable_sriov(adapter);
+	else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+		goto out;
+
+	if (err)
+		goto err_out;
+
+	/* While the SR-IOV capability structure reports total VFs to be
+	 * 64 we limit the actual number that can be allocated to 63 so
+	 * that some transmit/receive resources can be reserved to the
+	 * PF.  The PCI bus driver already checks for other values out of
+	 * range.
+	 */
+	if ((num_vfs + adapter->num_vmdqs) > TXGBE_MAX_VF_FUNCTIONS) {
+		err = -EPERM;
+		goto err_out;
+	}
+
+	adapter->num_vfs = num_vfs;
+
+	err = __txgbe_enable_sriov(adapter);
+	if (err)
+		goto err_out;
+
+	for (i = 0; i < adapter->num_vfs; i++)
+		txgbe_vf_configuration(dev, (i | 0x10000000));
+
+	err = pci_enable_sriov(dev, num_vfs);
+	if (err) {
+		e_dev_warn("Failed to enable PCI sriov: %d\n", err);
+		goto err_out;
+	}
+	txgbe_get_vfs(adapter);
+	txgbe_sriov_reinit(adapter);
+
+out:
+	return num_vfs;
+
+err_out:
+	return err;
+#endif
+	return 0;
+}
+
+static int txgbe_pci_sriov_disable(struct pci_dev *dev)
+{
+	struct txgbe_adapter *adapter = pci_get_drvdata(dev);
+	int err;
+#ifdef CONFIG_PCI_IOV
+	u32 current_flags = adapter->flags;
+#endif
+
+	err = txgbe_disable_sriov(adapter);
+
+	/* Only reinit if no error and state changed */
+#ifdef CONFIG_PCI_IOV
+	if (!err && current_flags != adapter->flags)
+		txgbe_sriov_reinit(adapter);
+#endif
+
+	return err;
+}
+
+int txgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+	if (num_vfs == 0)
+		return txgbe_pci_sriov_disable(dev);
+	else
+		return txgbe_pci_sriov_enable(dev, num_vfs);
+}
+
+#ifdef IFLA_VF_MAX
+int txgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+	s32 retval = 0;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs))
+		return -EINVAL;
+
+	dev_info(pci_dev_to_dev(adapter->pdev),
+		"setting MAC %pM on VF %d\n", mac, vf);
+	dev_info(pci_dev_to_dev(adapter->pdev),
+		"Reload the VF driver to make this change effective.\n");
+	retval = txgbe_set_vf_mac(adapter, vf, mac);
+	if (retval >= 0) {
+		adapter->vfinfo[vf].pf_set_mac = true;
+		if (test_bit(__TXGBE_DOWN, &adapter->state)) {
+			dev_warn(pci_dev_to_dev(adapter->pdev),
+				"The VF MAC address has been set, but the PF "
+				"device is not up.\n");
+			dev_warn(pci_dev_to_dev(adapter->pdev),
+				"Bring the PF device up before attempting to "
+				"use the VF device.\n");
+		}
+	} else {
+		dev_warn(pci_dev_to_dev(adapter->pdev),
+			"The VF MAC address was NOT set due to invalid or "
+			"duplicate MAC address.\n");
+	}
+
+	return retval;
+}
+
+static int txgbe_enable_port_vlan(struct txgbe_adapter *adapter,
+				   int vf, u16 vlan, u8 qos)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int err;
+
+	err = txgbe_set_vf_vlan(adapter, true, vlan, vf);
+	if (err)
+		goto out;
+	txgbe_set_vmvir(adapter, vlan, qos, vf);
+	txgbe_set_vmolr(hw, vf, false);
+	if (adapter->vfinfo[vf].spoofchk_enabled)
+		TCALL(hw, mac.ops.set_vlan_anti_spoofing, true, vf);
+	adapter->vfinfo[vf].vlan_count++;
+	/* enable hide vlan */
+	txgbe_write_qde(adapter, vf, 1);
+	txgbe_write_hide_vlan(adapter, vf, 1);
+	adapter->vfinfo[vf].pf_vlan = vlan;
+	adapter->vfinfo[vf].pf_qos = qos;
+	dev_info(pci_dev_to_dev(adapter->pdev),
+		 "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+	if (test_bit(__TXGBE_DOWN, &adapter->state)) {
+		dev_warn(pci_dev_to_dev(adapter->pdev),
+			"The VF VLAN has been set, but the PF device is not "
+			"up.\n");
+		dev_warn(pci_dev_to_dev(adapter->pdev),
+			"Bring the PF device up before attempting to use the VF "
+			"device.\n");
+	}
+
+out:
+	return err;
+}
+
+static int txgbe_disable_port_vlan(struct txgbe_adapter *adapter, int vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	int err;
+
+	err = txgbe_set_vf_vlan(adapter, false,
+				adapter->vfinfo[vf].pf_vlan, vf);
+	txgbe_clear_vmvir(adapter, vf);
+	txgbe_set_vmolr(hw, vf, true);
+	TCALL(hw, mac.ops.set_vlan_anti_spoofing, false, vf);
+	if (adapter->vfinfo[vf].vlan_count)
+		adapter->vfinfo[vf].vlan_count--;
+	/* disable hide vlan */
+	txgbe_write_hide_vlan(adapter, vf, 0);
+	adapter->vfinfo[vf].pf_vlan = 0;
+	adapter->vfinfo[vf].pf_qos = 0;
+
+	return err;
+}
+#ifdef IFLA_VF_MAX
+#ifdef IFLA_VF_VLAN_INFO_MAX
+int txgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
+			  u8 qos, __be16 vlan_proto)
+#else
+int txgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
+#endif
+{
+	int err = 0;
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* VLAN IDs accepted range 0-4094 */
+	if ((vf >= adapter->num_vfs) || (vlan > VLAN_VID_MASK-1) || (qos > 7))
+		return -EINVAL;
+#ifdef IFLA_VF_VLAN_INFO_MAX
+	if (vlan_proto != htons(ETH_P_8021Q))
+		return -EPROTONOSUPPORT;
+#endif
+	if (vlan || qos) {
+		/*
+		 * Check if there is already a port VLAN set, if so
+		 * we have to delete the old one first before we
+		 * can set the new one.  The usage model had
+		 * previously assumed the user would delete the
+		 * old port VLAN before setting a new one but this
+		 * is not necessarily the case.
+		 */
+		if (adapter->vfinfo[vf].pf_vlan)
+			err = txgbe_disable_port_vlan(adapter, vf);
+		if (err)
+			goto out;
+		err = txgbe_enable_port_vlan(adapter, vf, vlan, qos);
+
+	} else {
+		err = txgbe_disable_port_vlan(adapter, vf);
+	}
+out:
+	return err;
+}
+#endif /* IFLA_VF_MAX */
+
+static void txgbe_set_vf_rate_limit(struct txgbe_adapter *adapter, int vf)
+{
+	struct txgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 bcnrc_val;
+	u16 queue, queues_per_pool;
+	u16 max_tx_rate = adapter->vfinfo[vf].max_tx_rate;
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+	u16 min_tx_rate = adapter->vfinfo[vf].min_tx_rate;
+#endif
+
+	/* determine how many queues per pool based on VMDq mask */
+	queues_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+
+	max_tx_rate /= queues_per_pool;
+	bcnrc_val = TXGBE_TDM_RP_RATE_MAX(max_tx_rate);
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+	min_tx_rate /= queues_per_pool;
+	bcnrc_val |= TXGBE_TDM_RP_RATE_MIN(min_tx_rate);
+#endif
+
+	/*
+	 * Set global transmit compensation time to the MMW_SIZE in RTTBCNRM
+	 * register. Typically MMW_SIZE=0x014 if 9728-byte jumbo is supported
+	 * and 0x004 otherwise.
+	 */
+	wr32(hw, TXGBE_TDM_MMW, 0x14);
+
+	/* write value for all Tx queues belonging to VF */
+	for (queue = 0; queue < queues_per_pool; queue++) {
+		unsigned int reg_idx = (vf * queues_per_pool) + queue;
+
+		wr32(hw, TXGBE_TDM_RP_IDX, reg_idx);
+		wr32(hw, TXGBE_TDM_RP_RATE, bcnrc_val);
+		if (max_tx_rate)
+			wr32m(hw, TXGBE_TDM_RP_CTL,
+				TXGBE_TDM_RP_CTL_RLEN, TXGBE_TDM_RP_CTL_RLEN);
+		else
+			wr32m(hw, TXGBE_TDM_RP_CTL,
+				TXGBE_TDM_RP_CTL_RLEN, 0);
+	}
+}
+
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+int txgbe_ndo_set_vf_bw(struct net_device *netdev,
+			int vf,
+			int min_tx_rate,
+			int max_tx_rate)
+#else
+int txgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int max_tx_rate)
+#endif /* HAVE_NDO_SET_VF_MIN_MAX_TX_RATE */
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* verify VF is active */
+	if (vf >= adapter->num_vfs)
+		return -EINVAL;
+
+	/* verify link is up */
+	if (!adapter->link_up)
+		return -EINVAL;
+
+	/* verify we are linked at 1 or 10 Gbps */
+	if (adapter->link_speed < TXGBE_LINK_SPEED_1GB_FULL)
+		return -EINVAL;
+
+	/* store values */
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+	adapter->vfinfo[vf].min_tx_rate = min_tx_rate;
+#endif
+	adapter->vfinfo[vf].max_tx_rate = max_tx_rate;
+
+	/* update hardware configuration */
+	txgbe_set_vf_rate_limit(adapter, vf);
+
+	return 0;
+}
+
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+int txgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 regval;
+
+	if (vf >= adapter->num_vfs)
+		return -EINVAL;
+
+	adapter->vfinfo[vf].spoofchk_enabled = setting;
+
+	if (vf < 32) {
+		regval = (setting << vf);
+		wr32m(hw, TXGBE_TDM_MAC_AS_L,
+			regval | (1 << vf), regval);
+
+		if (adapter->vfinfo[vf].vlan_count) {
+			wr32m(hw, TXGBE_TDM_VLAN_AS_L,
+				regval | (1 << vf), regval);
+		}
+	} else {
+		regval = (setting << (vf - 32));
+		wr32m(hw, TXGBE_TDM_MAC_AS_H,
+			regval | (1 << (vf - 32)), regval);
+
+		if (adapter->vfinfo[vf].vlan_count) {
+			wr32m(hw, TXGBE_TDM_VLAN_AS_H,
+				regval | (1 << (vf - 32)), regval);
+		}
+	}
+	return 0;
+}
+#endif /* HAVE_VF_SPOOFCHK_CONFIGURE */
+
+/**
+ * ixgbe_set_vf_rx_tx - Set VF rx tx
+ * @adapter: Pointer to adapter struct
+ * @vf: VF identifier
+ *
+ * Set or reset correct transmit and receive for vf
+ **/
+static void txgbe_set_vf_rx_tx(struct txgbe_adapter *adapter, int vf)
+{
+	struct txgbe_hw *hw = &adapter->hw;
+	u32 reg_cur_tx, reg_cur_rx, reg_req_tx, reg_req_rx;
+	u32 reg_offset, vf_shift;
+
+	vf_shift = vf % 32;
+	reg_offset = vf / 32;
+
+	reg_cur_tx = rd32(hw, TXGBE_TDM_VF_TE(reg_offset));
+	reg_cur_rx = rd32(hw, TXGBE_RDM_VF_RE(reg_offset));
+
+	if (adapter->vfinfo[vf].link_enable) {
+		reg_req_tx = reg_cur_tx | 1 << vf_shift;
+		reg_req_rx = reg_cur_rx | 1 << vf_shift;
+		/* Enable particular VF */
+		if (reg_cur_tx != reg_req_tx)
+			wr32(hw, TXGBE_TDM_VF_TE(reg_offset), reg_req_tx);
+		if (reg_cur_rx != reg_req_rx)
+			wr32(hw, TXGBE_RDM_VF_RE(reg_offset), reg_req_rx);
+	} else {
+		reg_req_tx = 1 << vf_shift;
+		reg_req_rx = 1 << vf_shift;
+		/* Disable particular VF */
+		if (reg_cur_tx & reg_req_tx)
+			wr32(hw, TXGBE_TDM_VFTE_CLR(reg_offset), reg_req_tx);
+		if (reg_cur_rx & reg_req_rx)
+			wr32(hw, TXGBE_RDM_VFRE_CLR(reg_offset), reg_req_rx);
+	}
+
+}
+
+/**
+ * txgbe_set_vf_link_state - Set link state
+ * @adapter: Pointer to adapter struct
+ * @vf: VF identifier
+ * @state: required link state
+ *
+ * Set a link force state on/off a single vf
+ **/
+void txgbe_set_vf_link_state(struct txgbe_adapter *adapter, int vf, int state)
+{
+	adapter->vfinfo[vf].link_state = state;
+
+	switch (state) {
+	case IFLA_VF_LINK_STATE_AUTO:
+		if (test_bit(__TXGBE_DOWN, &adapter->state))
+			adapter->vfinfo[vf].link_enable = false;
+		else
+			adapter->vfinfo[vf].link_enable = true;
+		break;
+	case IFLA_VF_LINK_STATE_ENABLE:
+		adapter->vfinfo[vf].link_enable = true;
+		break;
+	case IFLA_VF_LINK_STATE_DISABLE:
+		adapter->vfinfo[vf].link_enable = false;
+		break;
+	}
+
+	txgbe_set_vf_rx_tx(adapter, vf);
+
+	/* restart the VF */
+	adapter->vfinfo[vf].clear_to_send = false;
+	txgbe_ping_vf(adapter, vf);
+
+}
+
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
+
+/**
+ * txgbe_ndo_set_vf_link_state - Set link state
+ * @netdev: network interface device structure
+ * @vf: VF identifier
+ * @state: required link state
+ *
+ * Set the link state of a specified VF, regardless of physical link state
+ **/
+int txgbe_ndo_set_vf_link_state(struct net_device *netdev, int vf, int state)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	int ret = 0;
+
+	if (vf < 0 || vf >= adapter->num_vfs) {
+		dev_err(pci_dev_to_dev(adapter->pdev),
+			"NDO set VF link - invalid VF identifier %d\n", vf);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (state) {
+	case IFLA_VF_LINK_STATE_ENABLE:
+		dev_info(pci_dev_to_dev(adapter->pdev),
+			 "NDO set VF %d link state %d - not supported\n",
+			vf, state);
+		break;
+	case IFLA_VF_LINK_STATE_DISABLE:
+		dev_info(pci_dev_to_dev(adapter->pdev),
+			 "NDO set VF %d link state disable\n", vf);
+		txgbe_set_vf_link_state(adapter, vf, state);
+		break;
+	case IFLA_VF_LINK_STATE_AUTO:
+		dev_info(pci_dev_to_dev(adapter->pdev),
+			 "NDO set VF %d link state auto\n", vf);
+		txgbe_set_vf_link_state(adapter, vf, state);
+		break;
+	default:
+		dev_err(pci_dev_to_dev(adapter->pdev),
+			"NDO set VF %d - invalid link state %d\n", vf, state);
+		ret = -EINVAL;
+	}
+out:
+	return ret;
+}
+#endif /* HAVE_NDO_SET_VF_LINK_STATE */
+
+
+int txgbe_ndo_get_vf_config(struct net_device *netdev,
+			    int vf, struct ifla_vf_info *ivi)
+{
+	struct txgbe_adapter *adapter = netdev_priv(netdev);
+	if (vf >= adapter->num_vfs)
+		return -EINVAL;
+	ivi->vf = vf;
+	memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN);
+
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+	ivi->max_tx_rate = adapter->vfinfo[vf].max_tx_rate;
+	ivi->min_tx_rate = adapter->vfinfo[vf].min_tx_rate;
+#else
+	ivi->tx_rate = adapter->vfinfo[vf].max_tx_rate;
+#endif
+
+	ivi->vlan = adapter->vfinfo[vf].pf_vlan;
+	ivi->qos = adapter->vfinfo[vf].pf_qos;
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+	ivi->spoofchk = adapter->vfinfo[vf].spoofchk_enabled;
+#endif
+#ifdef HAVE_NDO_SET_VF_TRUST
+	ivi->trusted = adapter->vfinfo[vf].trusted;
+#endif
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
+	ivi->linkstate = adapter->vfinfo[vf].link_state;
+#endif
+
+	return 0;
+}
+#endif /* IFLA_VF_MAX */
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.h
new file mode 100644
index 000000000000..7c64f68605b5
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_sriov.h
@@ -0,0 +1,77 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+
+#ifndef _TXGBE_SRIOV_H_
+#define _TXGBE_SRIOV_H_
+
+/* txgbe driver limit the max number of VFs could be enabled to
+ * 63 (TXGBE_MAX_VF_FUNCTIONS - 1)
+ */
+#define TXGBE_MAX_VFS_DRV_LIMIT  (TXGBE_MAX_VF_FUNCTIONS - 1)
+
+void txgbe_restore_vf_multicasts(struct txgbe_adapter *adapter);
+int txgbe_set_vf_vlan(struct txgbe_adapter *adapter, int add, int vid, u16 vf);
+void txgbe_set_vmolr(struct txgbe_hw *hw, u16 vf, bool aupe);
+void txgbe_msg_task(struct txgbe_adapter *adapter);
+int txgbe_set_vf_mac(struct txgbe_adapter *adapter,
+		     u16 vf, unsigned char *mac_addr);
+void txgbe_disable_tx_rx(struct txgbe_adapter *adapter);
+void txgbe_ping_all_vfs(struct txgbe_adapter *adapter);
+void txgbe_set_all_vfs(struct txgbe_adapter *adapter);
+#ifdef IFLA_VF_MAX
+int txgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
+#ifdef IFLA_VF_VLAN_INFO_MAX
+int txgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
+			  u8 qos, __be16 vlan_proto);
+#else
+int txgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
+			  u8 qos);
+#endif
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+int txgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int min_tx_rate,
+			int max_tx_rate);
+#else
+int txgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+#endif /* HAVE_NDO_SET_VF_MIN_MAX_TX_RATE */
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+int txgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
+#endif
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
+int txgbe_ndo_set_vf_link_state(struct net_device *netdev, int vf, int state);
+#endif
+#ifdef HAVE_NDO_SET_VF_TRUST
+int txgbe_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting);
+#endif
+int txgbe_ndo_get_vf_config(struct net_device *netdev,
+			    int vf, struct ifla_vf_info *ivi);
+#endif /* IFLA_VF_MAX */
+int txgbe_disable_sriov(struct txgbe_adapter *adapter);
+#ifdef CONFIG_PCI_IOV
+int txgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
+void txgbe_enable_sriov(struct txgbe_adapter *adapter);
+#endif
+int txgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
+void txgbe_set_vf_link_state(struct txgbe_adapter *adapter, int vf, int state);
+
+/*
+ * These are defined in txgbe_type.h on behalf of the VF driver
+ * but we need them here unwrapped for the PF driver.
+ */
+#define TXGBE_DEV_ID_SP_VF                      0x1000
+#endif /* _TXGBE_SRIOV_H_ */
+
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_sysfs.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_sysfs.c
new file mode 100644
index 000000000000..bc9c94608046
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_sysfs.c
@@ -0,0 +1,229 @@
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_sysfs.c, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
+
+#include "txgbe.h"
+#include "txgbe_hw.h"
+#include "txgbe_type.h"
+
+#ifdef TXGBE_SYSFS
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/time.h>
+#ifdef TXGBE_HWMON
+#include <linux/hwmon.h>
+#endif
+
+#ifdef TXGBE_HWMON
+/* hwmon callback functions */
+static ssize_t txgbe_hwmon_show_temp(struct device __always_unused *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *txgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value;
+
+	/* reset the temp field */
+	TCALL(txgbe_attr->hw, mac.ops.get_thermal_sensor_data);
+
+	value = txgbe_attr->sensor->temp;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t txgbe_hwmon_show_alarmthresh(struct device __always_unused *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *txgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = txgbe_attr->sensor->alarm_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t txgbe_hwmon_show_dalarmthresh(struct device __always_unused *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *txgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = txgbe_attr->sensor->dalarm_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+/**
+ * txgbe_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
+ * @adapter: pointer to the adapter structure
+ * @type: type of sensor data to display
+ *
+ * For each file we want in hwmon's sysfs interface we need a device_attribute
+ * This is included in our hwmon_attr struct that contains the references to
+ * the data structures we need to get the data to display.
+ */
+static int txgbe_add_hwmon_attr(struct txgbe_adapter *adapter, int type)
+{
+	int rc;
+	unsigned int n_attr;
+	struct hwmon_attr *txgbe_attr;
+
+	n_attr = adapter->txgbe_hwmon_buff.n_hwmon;
+	txgbe_attr = &adapter->txgbe_hwmon_buff.hwmon_list[n_attr];
+
+	switch (type) {
+	case TXGBE_HWMON_TYPE_TEMP:
+		txgbe_attr->dev_attr.show = txgbe_hwmon_show_temp;
+		snprintf(txgbe_attr->name, sizeof(txgbe_attr->name),
+			 "temp%u_input", 0);
+		break;
+	case TXGBE_HWMON_TYPE_ALARMTHRESH:
+		txgbe_attr->dev_attr.show = txgbe_hwmon_show_alarmthresh;
+		snprintf(txgbe_attr->name, sizeof(txgbe_attr->name),
+			 "temp%u_alarmthresh", 0);
+		break;
+	case TXGBE_HWMON_TYPE_DALARMTHRESH:
+		txgbe_attr->dev_attr.show = txgbe_hwmon_show_dalarmthresh;
+		snprintf(txgbe_attr->name, sizeof(txgbe_attr->name),
+			 "temp%u_dalarmthresh", 0);
+		break;
+	default:
+		rc = -EPERM;
+		return rc;
+	}
+
+	/* These always the same regardless of type */
+	txgbe_attr->sensor =
+		&adapter->hw.mac.thermal_sensor_data.sensor;
+	txgbe_attr->hw = &adapter->hw;
+	txgbe_attr->dev_attr.store = NULL;
+	txgbe_attr->dev_attr.attr.mode = S_IRUGO;
+	txgbe_attr->dev_attr.attr.name = txgbe_attr->name;
+
+	rc = device_create_file(pci_dev_to_dev(adapter->pdev),
+				&txgbe_attr->dev_attr);
+
+	if (rc == 0)
+		++adapter->txgbe_hwmon_buff.n_hwmon;
+
+	return rc;
+}
+#endif /* TXGBE_HWMON */
+
+static void txgbe_sysfs_del_adapter(
+				struct txgbe_adapter __maybe_unused *adapter)
+{
+#ifdef TXGBE_HWMON
+	int i;
+
+	if (adapter == NULL)
+		return;
+
+	for (i = 0; i < adapter->txgbe_hwmon_buff.n_hwmon; i++) {
+		device_remove_file(pci_dev_to_dev(adapter->pdev),
+			   &adapter->txgbe_hwmon_buff.hwmon_list[i].dev_attr);
+	}
+
+	kfree(adapter->txgbe_hwmon_buff.hwmon_list);
+
+	if (adapter->txgbe_hwmon_buff.device)
+		hwmon_device_unregister(adapter->txgbe_hwmon_buff.device);
+#endif /* TXGBE_HWMON */
+}
+
+/* called from txgbe_main.c */
+void txgbe_sysfs_exit(struct txgbe_adapter *adapter)
+{
+	txgbe_sysfs_del_adapter(adapter);
+}
+
+/* called from txgbe_main.c */
+int txgbe_sysfs_init(struct txgbe_adapter *adapter)
+{
+	int rc = 0;
+#ifdef TXGBE_HWMON
+	struct hwmon_buff *txgbe_hwmon = &adapter->txgbe_hwmon_buff;
+	int n_attrs;
+
+#endif /* TXGBE_HWMON */
+	if (adapter == NULL)
+		goto err;
+
+#ifdef TXGBE_HWMON
+
+	/* Don't create thermal hwmon interface if no sensors present */
+	if (TCALL(&adapter->hw, mac.ops.init_thermal_sensor_thresh))
+		goto no_thermal;
+
+	/*
+	 * Allocation space for max attributs
+	 * max num sensors * values (temp, alamthresh, dalarmthresh)
+	 */
+	n_attrs = 3;
+	txgbe_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
+					  GFP_KERNEL);
+	if (!txgbe_hwmon->hwmon_list) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	txgbe_hwmon->device =
+			hwmon_device_register(pci_dev_to_dev(adapter->pdev));
+	if (IS_ERR(txgbe_hwmon->device)) {
+		rc = PTR_ERR(txgbe_hwmon->device);
+		goto err;
+	}
+
+
+	/* Bail if any hwmon attr struct fails to initialize */
+	rc = txgbe_add_hwmon_attr(adapter, TXGBE_HWMON_TYPE_TEMP);
+	rc |= txgbe_add_hwmon_attr(adapter, TXGBE_HWMON_TYPE_ALARMTHRESH);
+	rc |= txgbe_add_hwmon_attr(adapter, TXGBE_HWMON_TYPE_DALARMTHRESH);
+	if (rc)
+		goto err;
+
+no_thermal:
+#endif /* TXGBE_HWMON */
+	goto exit;
+
+err:
+	txgbe_sysfs_del_adapter(adapter);
+exit:
+	return rc;
+}
+#endif /* TXGBE_SYSFS */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index b2e329f50bae..6c84cc2564e3 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -1,16 +1,99 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+/*
+ * WangXun 10 Gigabit PCI Express Linux driver
+ * Copyright (c) 2015 - 2017 Beijing WangXun Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * based on ixgbe_type.h, Copyright(c) 1999 - 2017 Intel Corporation.
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
+
 
 #ifndef _TXGBE_TYPE_H_
 #define _TXGBE_TYPE_H_
 
-#include <linux/types.h>
-#include <linux/netdevice.h>
+/*
+ * The following is a brief description of the error categories used by the
+ * ERROR_REPORT* macros.
+ *
+ * - TXGBE_ERROR_INVALID_STATE
+ * This category is for errors which represent a serious failure state that is
+ * unexpected, and could be potentially harmful to device operation. It should
+ * not be used for errors relating to issues that can be worked around or
+ * ignored.
+ *
+ * - TXGBE_ERROR_POLLING
+ * This category is for errors related to polling/timeout issues and should be
+ * used in any case where the timeout occured, or a failure to obtain a lock, or
+ * failure to receive data within the time limit.
+ *
+ * - TXGBE_ERROR_CAUTION
+ * This category should be used for reporting issues that may be the cause of
+ * other errors, such as temperature warnings. It should indicate an event which
+ * could be serious, but hasn't necessarily caused problems yet.
+ *
+ * - TXGBE_ERROR_SOFTWARE
+ * This category is intended for errors due to software state preventing
+ * something. The category is not intended for errors due to bad arguments, or
+ * due to unsupported features. It should be used when a state occurs which
+ * prevents action but is not a serious issue.
+ *
+ * - TXGBE_ERROR_ARGUMENT
+ * This category is for when a bad or invalid argument is passed. It should be
+ * used whenever a function is called and error checking has detected the
+ * argument is wrong or incorrect.
+ *
+ * - TXGBE_ERROR_UNSUPPORTED
+ * This category is for errors which are due to unsupported circumstances or
+ * configuration issues. It should not be used when the issue is due to an
+ * invalid argument, but for when something has occurred that is unsupported
+ * (Ex: Flow control autonegotiation or an unsupported SFP+ module.)
+ */
+
+#include "txgbe_osdep.h"
+#include "txgbe_mtd.h"
+
+/* Override this by setting IOMEM in your txgbe_osdep.h header */
+#ifndef IOMEM
+#define IOMEM
+#endif
+
+/* Little Endian defines */
+#ifndef __le16
+#define __le16  u16
+#endif
+#ifndef __le32
+#define __le32  u32
+#endif
+#ifndef __le64
+#define __le64  u64
+
+#endif
+#ifndef __be16
+/* Big Endian defines */
+#define __be16  u16
+#define __be32  u32
+#define __be64  u64
+
+#endif
 
 /************ txgbe_register.h ************/
 /* Vendor ID */
-#ifndef PCI_VENDOR_ID_WANGXUN
-#define PCI_VENDOR_ID_WANGXUN                   0x8088
+#ifndef PCI_VENDOR_ID_TRUSTNETIC
+#define PCI_VENDOR_ID_TRUSTNETIC                0x8088
 #endif
 
 /* Device IDs */
@@ -48,10 +131,3116 @@
 #define TXGBE_WOL_MASK                          0x4000
 #define TXGBE_DEV_MASK                          0xf0
 
+
 /* Combined interface*/
-#define TXGBE_ID_SFI_XAUI			0x50
+#define TXGBE_ID_SFI_XAUI						0x50
 
 /* Revision ID */
 #define TXGBE_SP_MPW  1
 
+/* MDIO Manageable Devices (MMDs). */
+#define TXGBE_MDIO_PMA_PMD_DEV_TYPE            0x1 /* PMA and PMD */
+#define TXGBE_MDIO_PCS_DEV_TYPE                0x3 /* Physical Coding Sublayer*/
+#define TXGBE_MDIO_PHY_XS_DEV_TYPE             0x4 /* PHY Extender Sublayer */
+#define TXGBE_MDIO_AUTO_NEG_DEV_TYPE           0x7 /* Auto-Negotiation */
+#define TXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE  0x1E /* Vendor specific 1 */
+
+/* phy register definitions */
+/* VENDOR_SPECIFIC_1_DEV regs */
+#define TXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS             0x1 /* VS1 Status Reg */
+#define TXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS        0x0008 /* 1 = Link Up */
+#define TXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS       0x0010 /* 0-10G, 1-1G */
+
+/* AUTO_NEG_DEV regs */
+#define TXGBE_MDIO_AUTO_NEG_CONTROL              0x0  /* AUTO_NEG Control Reg */
+#define TXGBE_MDIO_AUTO_NEG_ADVT                 0x10 /* AUTO_NEG Advt Reg */
+#define TXGBE_MDIO_AUTO_NEG_LP                   0x13 /* AUTO_NEG LP Reg */
+#define TXGBE_MDIO_AUTO_NEG_LP_STATUS            0xE820 /* AUTO NEG RX LP Status
+														 * Reg */
+#define TXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG     0x20   /* 10G Control Reg */
+#define TXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG 0xC400 /* 1G Provisioning 1 */
+#define TXGBE_MII_AUTONEG_XNP_TX_REG             0x17   /* 1G XNP Transmit */
+#define TXGBE_MII_AUTONEG_ADVERTISE_REG          0x10   /* 100M Advertisement */
+
+
+#define TXGBE_MDIO_AUTO_NEG_10GBASE_EEE_ADVT    0x8
+#define TXGBE_MDIO_AUTO_NEG_1000BASE_EEE_ADVT   0x4
+#define TXGBE_MDIO_AUTO_NEG_100BASE_EEE_ADVT    0x2
+#define TXGBE_MDIO_AUTO_NEG_LP_1000BASE_CAP     0x8000
+#define TXGBE_MDIO_AUTO_NEG_LP_10GBASE_CAP      0x0800
+#define TXGBE_MDIO_AUTO_NEG_10GBASET_STAT       0x0021
+
+#define TXGBE_MII_10GBASE_T_ADVERTISE           0x1000 /* full duplex, bit:12*/
+#define TXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX     0x4000 /* full duplex, bit:14*/
+#define TXGBE_MII_1GBASE_T_ADVERTISE            0x8000 /* full duplex, bit:15*/
+#define TXGBE_MII_100BASE_T_ADVERTISE           0x0100 /* full duplex, bit:8 */
+#define TXGBE_MII_100BASE_T_ADVERTISE_HALF      0x0080 /* half duplex, bit:7 */
+#define TXGBE_MII_RESTART                       0x200
+#define TXGBE_MII_AUTONEG_COMPLETE              0x20
+#define TXGBE_MII_AUTONEG_LINK_UP               0x04
+#define TXGBE_MII_AUTONEG_REG                   0x0
+
+/* PHY_XS_DEV regs */
+#define TXGBE_MDIO_PHY_XS_CONTROL               0x0    /* PHY_XS Control Reg */
+#define TXGBE_MDIO_PHY_XS_RESET                 0x8000 /* PHY_XS Reset */
+
+/* Media-dependent registers. */
+#define TXGBE_MDIO_PHY_ID_HIGH                  0x2 /* PHY ID High Reg*/
+#define TXGBE_MDIO_PHY_ID_LOW                   0x3 /* PHY ID Low Reg*/
+#define TXGBE_MDIO_PHY_SPEED_ABILITY            0x4 /* Speed Ability Reg */
+#define TXGBE_MDIO_PHY_EXT_ABILITY              0xB /* Ext Ability Reg */
+
+#define TXGBE_MDIO_PHY_SPEED_10G                0x0001 /* 10G capable */
+#define TXGBE_MDIO_PHY_SPEED_1G                 0x0010 /* 1G capable */
+#define TXGBE_MDIO_PHY_SPEED_100M               0x0020 /* 100M capable */
+#define TXGBE_MDIO_PHY_SPEED_10M                0x0040 /* 10M capable */
+
+#define TXGBE_MDIO_PHY_10GBASET_ABILITY         0x0004 /* 10GBaseT capable */
+#define TXGBE_MDIO_PHY_1000BASET_ABILITY        0x0020 /* 1000BaseT capable */
+#define TXGBE_MDIO_PHY_100BASETX_ABILITY        0x0080 /* 100BaseTX capable */
+
+#define TXGBE_PHY_REVISION_MASK                 0xFFFFFFF0U
+#define TXGBE_MAX_PHY_ADDR                      32
+
+/* PHY IDs*/
+#define TN1010_PHY_ID                           0x00A19410U
+#define QT2022_PHY_ID                           0x0043A400U
+#define ATH_PHY_ID                              0x03429050U
+/* PHY FW revision */
+#define TNX_FW_REV                              0xB
+#define AQ_FW_REV                               0x20
+
+/* ETH PHY Registers */
+#define TXGBE_SR_XS_PCS_MMD_STATUS1             0x30001
+#define TXGBE_SR_PCS_CTL2                       0x30007
+#define TXGBE_SR_PMA_MMD_CTL1                   0x10000
+#define TXGBE_SR_MII_MMD_CTL                    0x1F0000
+#define TXGBE_SR_MII_MMD_DIGI_CTL               0x1F8000
+#define TXGBE_SR_MII_MMD_AN_CTL                 0x1F8001
+#define TXGBE_SR_MII_MMD_AN_ADV                 0x1F0004
+#define TXGBE_SR_MII_MMD_AN_ADV_PAUSE(_v)       ((0x3 & (_v)) << 7)
+#define TXGBE_SR_MII_MMD_AN_ADV_PAUSE_ASM       0x80
+#define TXGBE_SR_MII_MMD_AN_ADV_PAUSE_SYM       0x100
+#define TXGBE_SR_MII_MMD_LP_BABL                0x1F0005
+#define TXGBE_SR_AN_MMD_CTL                     0x70000
+#define TXGBE_SR_AN_MMD_ADV_REG1                0x70010
+#define TXGBE_SR_AN_MMD_ADV_REG1_PAUSE(_v)      ((0x3 & (_v)) << 10)
+#define TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_SYM      0x400
+#define TXGBE_SR_AN_MMD_ADV_REG1_PAUSE_ASM      0x800
+#define TXGBE_SR_AN_MMD_ADV_REG2                0x70011
+#define TXGBE_SR_AN_MMD_LP_ABL1                 0x70013
+#define TXGBE_VR_AN_KR_MODE_CL                  0x78003
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1        0x38000
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS      0x38010
+#define TXGBE_PHY_MPLLA_CTL0                    0x18071
+#define TXGBE_PHY_MPLLA_CTL3                    0x18077
+#define TXGBE_PHY_MISC_CTL0                     0x18090
+#define TXGBE_PHY_VCO_CAL_LD0                   0x18092
+#define TXGBE_PHY_VCO_CAL_LD1                   0x18093
+#define TXGBE_PHY_VCO_CAL_LD2                   0x18094
+#define TXGBE_PHY_VCO_CAL_LD3                   0x18095
+#define TXGBE_PHY_VCO_CAL_REF0                  0x18096
+#define TXGBE_PHY_VCO_CAL_REF1                  0x18097
+#define TXGBE_PHY_RX_AD_ACK                     0x18098
+#define TXGBE_PHY_AFE_DFE_ENABLE                0x1805D
+#define TXGBE_PHY_DFE_TAP_CTL0                  0x1805E
+#define TXGBE_PHY_RX_EQ_ATT_LVL0                0x18057
+#define TXGBE_PHY_RX_EQ_CTL0                    0x18058
+#define TXGBE_PHY_RX_EQ_CTL                     0x1805C
+#define TXGBE_PHY_TX_EQ_CTL0                    0x18036
+#define TXGBE_PHY_TX_EQ_CTL1                    0x18037
+#define TXGBE_PHY_TX_RATE_CTL                   0x18034
+#define TXGBE_PHY_RX_RATE_CTL                   0x18054
+#define TXGBE_PHY_TX_GEN_CTL2                   0x18032
+#define TXGBE_PHY_RX_GEN_CTL2                   0x18052
+#define TXGBE_PHY_RX_GEN_CTL3                   0x18053
+#define TXGBE_PHY_MPLLA_CTL2                    0x18073
+#define TXGBE_PHY_RX_POWER_ST_CTL               0x18055
+#define TXGBE_PHY_TX_POWER_ST_CTL               0x18035
+#define TXGBE_PHY_TX_GENCTRL1                   0x18031
+
+#define TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_R        0x0
+#define TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_X        0x1
+#define TXGBE_SR_PCS_CTL2_PCS_TYPE_SEL_MASK     0x3
+#define TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_1G      0x0
+#define TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_10G     0x2000
+#define TXGBE_SR_PMA_MMD_CTL1_SPEED_SEL_MASK    0x2000
+#define TXGBE_SR_PMA_MMD_CTL1_LB_EN             0x1
+#define TXGBE_SR_MII_MMD_CTL_AN_EN              0x1000
+#define TXGBE_SR_MII_MMD_CTL_RESTART_AN         0x0200
+#define TXGBE_SR_AN_MMD_CTL_RESTART_AN          0x0200
+#define TXGBE_SR_AN_MMD_CTL_ENABLE              0x1000
+#define TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KX4    0x40
+#define TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KX     0x20
+#define TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_KR     0x80
+#define TXGBE_SR_AN_MMD_ADV_REG2_BP_TYPE_MASK   0xFFFF
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_ENABLE 0x1000
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_CTL1_VR_RST 0x8000
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_MASK            0x1C
+#define TXGBE_VR_XS_OR_PCS_MMD_DIGI_STATUS_PSEQ_POWER_GOOD      0x10
+
+#define TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_1GBASEX_KX              32
+#define TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_10GBASER_KR             33
+#define TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_OTHER                   40
+#define TXGBE_PHY_MPLLA_CTL0_MULTIPLIER_MASK                    0xFF
+#define TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_1GBASEX_KX           0x56
+#define TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_10GBASER_KR          0x7B
+#define TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_OTHER                0x56
+#define TXGBE_PHY_MPLLA_CTL3_MULTIPLIER_BW_MASK                 0x7FF
+#define TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_0                       0x1
+#define TXGBE_PHY_MISC_CTL0_TX2RX_LB_EN_3_1                     0xE
+#define TXGBE_PHY_MISC_CTL0_RX_VREF_CTRL                        0x1F00
+#define TXGBE_PHY_VCO_CAL_LD0_1GBASEX_KX                        1344
+#define TXGBE_PHY_VCO_CAL_LD0_10GBASER_KR                       1353
+#define TXGBE_PHY_VCO_CAL_LD0_OTHER                             1360
+#define TXGBE_PHY_VCO_CAL_LD0_MASK                              0x1000
+#define TXGBE_PHY_VCO_CAL_REF0_LD0_1GBASEX_KX                   42
+#define TXGBE_PHY_VCO_CAL_REF0_LD0_10GBASER_KR                  41
+#define TXGBE_PHY_VCO_CAL_REF0_LD0_OTHER                        34
+#define TXGBE_PHY_VCO_CAL_REF0_LD0_MASK                         0x3F
+#define TXGBE_PHY_AFE_DFE_ENABLE_DFE_EN0                        0x10
+#define TXGBE_PHY_AFE_DFE_ENABLE_AFE_EN0                        0x1
+#define TXGBE_PHY_AFE_DFE_ENABLE_MASK                           0xFF
+#define TXGBE_PHY_RX_EQ_CTL_CONT_ADAPT0                         0x1
+#define TXGBE_PHY_RX_EQ_CTL_CONT_ADAPT_MASK                     0xF
+#define TXGBE_PHY_TX_RATE_CTL_TX0_RATE_10GBASER_KR              0x0
+#define TXGBE_PHY_TX_RATE_CTL_TX0_RATE_RXAUI                    0x1
+#define TXGBE_PHY_TX_RATE_CTL_TX0_RATE_1GBASEX_KX               0x3
+#define TXGBE_PHY_TX_RATE_CTL_TX0_RATE_OTHER                    0x2
+#define TXGBE_PHY_TX_RATE_CTL_TX1_RATE_OTHER                    0x20
+#define TXGBE_PHY_TX_RATE_CTL_TX2_RATE_OTHER                    0x200
+#define TXGBE_PHY_TX_RATE_CTL_TX3_RATE_OTHER                    0x2000
+#define TXGBE_PHY_TX_RATE_CTL_TX0_RATE_MASK                     0x7
+#define TXGBE_PHY_TX_RATE_CTL_TX1_RATE_MASK                     0x70
+#define TXGBE_PHY_TX_RATE_CTL_TX2_RATE_MASK                     0x700
+#define TXGBE_PHY_TX_RATE_CTL_TX3_RATE_MASK                     0x7000
+#define TXGBE_PHY_RX_RATE_CTL_RX0_RATE_10GBASER_KR              0x0
+#define TXGBE_PHY_RX_RATE_CTL_RX0_RATE_RXAUI                    0x1
+#define TXGBE_PHY_RX_RATE_CTL_RX0_RATE_1GBASEX_KX               0x3
+#define TXGBE_PHY_RX_RATE_CTL_RX0_RATE_OTHER                    0x2
+#define TXGBE_PHY_RX_RATE_CTL_RX1_RATE_OTHER                    0x20
+#define TXGBE_PHY_RX_RATE_CTL_RX2_RATE_OTHER                    0x200
+#define TXGBE_PHY_RX_RATE_CTL_RX3_RATE_OTHER                    0x2000
+#define TXGBE_PHY_RX_RATE_CTL_RX0_RATE_MASK                     0x7
+#define TXGBE_PHY_RX_RATE_CTL_RX1_RATE_MASK                     0x70
+#define TXGBE_PHY_RX_RATE_CTL_RX2_RATE_MASK                     0x700
+#define TXGBE_PHY_RX_RATE_CTL_RX3_RATE_MASK                     0x7000
+#define TXGBE_PHY_TX_GEN_CTL2_TX0_WIDTH_10GBASER_KR             0x200
+#define TXGBE_PHY_TX_GEN_CTL2_TX0_WIDTH_10GBASER_KR_RXAUI       0x300
+#define TXGBE_PHY_TX_GEN_CTL2_TX0_WIDTH_OTHER                   0x100
+#define TXGBE_PHY_TX_GEN_CTL2_TX0_WIDTH_MASK                    0x300
+#define TXGBE_PHY_TX_GEN_CTL2_TX1_WIDTH_OTHER                   0x400
+#define TXGBE_PHY_TX_GEN_CTL2_TX1_WIDTH_MASK                    0xC00
+#define TXGBE_PHY_TX_GEN_CTL2_TX2_WIDTH_OTHER                   0x1000
+#define TXGBE_PHY_TX_GEN_CTL2_TX2_WIDTH_MASK                    0x3000
+#define TXGBE_PHY_TX_GEN_CTL2_TX3_WIDTH_OTHER                   0x4000
+#define TXGBE_PHY_TX_GEN_CTL2_TX3_WIDTH_MASK                    0xC000
+#define TXGBE_PHY_RX_GEN_CTL2_RX0_WIDTH_10GBASER_KR             0x200
+#define TXGBE_PHY_RX_GEN_CTL2_RX0_WIDTH_10GBASER_KR_RXAUI       0x300
+#define TXGBE_PHY_RX_GEN_CTL2_RX0_WIDTH_OTHER                   0x100
+#define TXGBE_PHY_RX_GEN_CTL2_RX0_WIDTH_MASK                    0x300
+#define TXGBE_PHY_RX_GEN_CTL2_RX1_WIDTH_OTHER                   0x400
+#define TXGBE_PHY_RX_GEN_CTL2_RX1_WIDTH_MASK                    0xC00
+#define TXGBE_PHY_RX_GEN_CTL2_RX2_WIDTH_OTHER                   0x1000
+#define TXGBE_PHY_RX_GEN_CTL2_RX2_WIDTH_MASK                    0x3000
+#define TXGBE_PHY_RX_GEN_CTL2_RX3_WIDTH_OTHER                   0x4000
+#define TXGBE_PHY_RX_GEN_CTL2_RX3_WIDTH_MASK                    0xC000
+
+#define TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_8                       0x100
+#define TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_10                      0x200
+#define TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_16P5                    0x400
+#define TXGBE_PHY_MPLLA_CTL2_DIV_CLK_EN_MASK                    0x700
+
+#define TXGBE_XPCS_POWER_GOOD_MAX_POLLING_TIME  100
+#define TXGBE_PHY_INIT_DONE_POLLING_TIME        100
+
+/**************** Global Registers ****************************/
+/* chip control Registers */
+#define TXGBE_MIS_RST                   0x1000C
+#define TXGBE_MIS_PWR                   0x10000
+#define TXGBE_MIS_CTL                   0x10004
+#define TXGBE_MIS_PF_SM                 0x10008
+#define TXGBE_MIS_PRB_CTL               0x10010 /* for PCIE recovery only */
+#define TXGBE_MIS_ST                    0x10028
+#define TXGBE_MIS_SWSM                  0x1002C
+#define TXGBE_MIS_RST_ST                0x10030
+
+#define TXGBE_MIS_RST_SW_RST            0x00000001U
+#define TXGBE_MIS_RST_LAN0_RST          0x00000002U
+#define TXGBE_MIS_RST_LAN1_RST          0x00000004U
+#define TXGBE_MIS_RST_LAN0_CHG_ETH_MODE 0x20000000U
+#define TXGBE_MIS_RST_LAN1_CHG_ETH_MODE 0x40000000U
+#define TXGBE_MIS_RST_GLOBAL_RST        0x80000000U
+#define TXGBE_MIS_RST_MASK      (TXGBE_MIS_RST_SW_RST | \
+				 TXGBE_MIS_RST_LAN0_RST | \
+				 TXGBE_MIS_RST_LAN1_RST)
+#define TXGBE_MIS_PWR_LAN_ID(_r)        ((0xC0000000U & (_r)) >> 30)
+#define TXGBE_MIS_PWR_LAN_ID_0          (1)
+#define TXGBE_MIS_PWR_LAN_ID_1          (2)
+#define TXGBE_MIS_PWR_LAN_ID_A          (3)
+#define TXGBE_MIS_ST_MNG_INIT_DN        0x00000001U
+#define TXGBE_MIS_ST_MNG_VETO           0x00000100U
+#define TXGBE_MIS_ST_LAN0_ECC           0x00010000U
+#define TXGBE_MIS_ST_LAN1_ECC           0x00020000U
+#define TXGBE_MIS_ST_MNG_ECC            0x00040000U
+#define TXGBE_MIS_ST_PCORE_ECC          0x00080000U
+#define TXGBE_MIS_ST_PCIWRP_ECC         0x00100000U
+#define TXGBE_MIS_SWSM_SMBI             1
+#define TXGBE_MIS_RST_ST_DEV_RST_ST_DONE        0x00000000U
+#define TXGBE_MIS_RST_ST_DEV_RST_ST_REQ         0x00080000U
+#define TXGBE_MIS_RST_ST_DEV_RST_ST_INPROGRESS  0x00100000U
+#define TXGBE_MIS_RST_ST_DEV_RST_ST_MASK        0x00180000U
+#define TXGBE_MIS_RST_ST_DEV_RST_TYPE_MASK      0x00070000U
+#define TXGBE_MIS_RST_ST_DEV_RST_TYPE_SHIFT     16
+#define TXGBE_MIS_RST_ST_DEV_RST_TYPE_SW_RST    0x3
+#define TXGBE_MIS_RST_ST_DEV_RST_TYPE_GLOBAL_RST 0x5
+#define TXGBE_MIS_RST_ST_RST_INIT       0x0000FF00U
+#define TXGBE_MIS_RST_ST_RST_INI_SHIFT  8
+#define TXGBE_MIS_RST_ST_RST_TIM        0x000000FFU
+#define TXGBE_MIS_PF_SM_SM              1
+#define TXGBE_MIS_PRB_CTL_LAN0_UP               0x2
+#define TXGBE_MIS_PRB_CTL_LAN1_UP               0x1
+
+/* Sensors for PVT(Process Voltage Temperature) */
+#define TXGBE_TS_CTL                    0x10300
+#define TXGBE_TS_EN                     0x10304
+#define TXGBE_TS_ST                     0x10308
+#define TXGBE_TS_ALARM_THRE             0x1030C
+#define TXGBE_TS_DALARM_THRE            0x10310
+#define TXGBE_TS_INT_EN                 0x10314
+#define TXGBE_TS_ALARM_ST               0x10318
+#define TXGBE_TS_ALARM_ST_DALARM        0x00000002U
+#define TXGBE_TS_ALARM_ST_ALARM         0x00000001U
+
+#define TXGBE_TS_CTL_EVAL_MD            0x80000000U
+#define TXGBE_TS_EN_ENA                 0x00000001U
+#define TXGBE_TS_ST_DATA_OUT_MASK       0x000003FFU
+#define TXGBE_TS_ALARM_THRE_MASK        0x000003FFU
+#define TXGBE_TS_DALARM_THRE_MASK       0x000003FFU
+#define TXGBE_TS_INT_EN_DALARM_INT_EN   0x00000002U
+#define TXGBE_TS_INT_EN_ALARM_INT_EN    0x00000001U
+
+struct txgbe_thermal_diode_data {
+	s16 temp;
+	s16 alarm_thresh;
+	s16 dalarm_thresh;
+};
+
+struct txgbe_thermal_sensor_data {
+	struct txgbe_thermal_diode_data sensor;
+};
+
+
+/* FMGR Registers */
+#define TXGBE_SPI_ILDR_STATUS           0x10120
+#define TXGBE_SPI_ILDR_STATUS_PERST     0x00000001U /* PCIE_PERST is done */
+#define TXGBE_SPI_ILDR_STATUS_PWRRST    0x00000002U /* Power on reset is done */
+#define TXGBE_SPI_ILDR_STATUS_SW_RESET  0x00000080U /* software reset is done */
+#define TXGBE_SPI_ILDR_STATUS_LAN0_SW_RST 0x00000200U /* lan0 soft reset done */
+#define TXGBE_SPI_ILDR_STATUS_LAN1_SW_RST 0x00000400U /* lan1 soft reset done */
+
+#define TXGBE_MAX_FLASH_LOAD_POLL_TIME  10
+
+#define TXGBE_SPI_CMD                   0x10104
+#define TXGBE_SPI_CMD_CMD(_v)           (((_v) & 0x7) << 28)
+#define TXGBE_SPI_CMD_CLK(_v)           (((_v) & 0x7) << 25)
+#define TXGBE_SPI_CMD_ADDR(_v)          (((_v) & 0xFFFFFF))
+#define TXGBE_SPI_DATA                  0x10108
+#define TXGBE_SPI_DATA_BYPASS           ((0x1) << 31)
+#define TXGBE_SPI_DATA_STATUS(_v)       (((_v) & 0xFF) << 16)
+#define TXGBE_SPI_DATA_OP_DONE          ((0x1))
+
+#define TXGBE_SPI_STATUS                0x1010C
+#define TXGBE_SPI_STATUS_OPDONE         ((0x1))
+#define TXGBE_SPI_STATUS_FLASH_BYPASS   ((0x1) << 31)
+
+#define TXGBE_SPI_USR_CMD               0x10110
+#define TXGBE_SPI_CMDCFG0               0x10114
+#define TXGBE_SPI_CMDCFG1               0x10118
+#define TXGBE_SPI_ECC_CTL               0x10130
+#define TXGBE_SPI_ECC_INJ               0x10134
+#define TXGBE_SPI_ECC_ST                0x10138
+#define TXGBE_SPI_ILDR_SWPTR            0x10124
+
+/************************* Port Registers ************************************/
+/* I2C registers */
+#define TXGBE_I2C_CON                   0x14900 /* I2C Control */
+#define TXGBE_I2C_CON_SLAVE_DISABLE     ((1 << 6))
+#define TXGBE_I2C_CON_RESTART_EN        ((1 << 5))
+#define TXGBE_I2C_CON_10BITADDR_MASTER  ((1 << 4))
+#define TXGBE_I2C_CON_10BITADDR_SLAVE   ((1 << 3))
+#define TXGBE_I2C_CON_SPEED(_v)         (((_v) & 0x3) << 1)
+#define TXGBE_I2C_CON_MASTER_MODE       ((1 << 0))
+#define TXGBE_I2C_TAR                   0x14904 /* I2C Target Address */
+#define TXGBE_I2C_DATA_CMD              0x14910 /* I2C Rx/Tx Data Buf and Cmd */
+#define TXGBE_I2C_DATA_CMD_STOP         ((1 << 9))
+#define TXGBE_I2C_DATA_CMD_READ         ((1 << 8) | TXGBE_I2C_DATA_CMD_STOP)
+#define TXGBE_I2C_DATA_CMD_WRITE        ((0 << 8) | TXGBE_I2C_DATA_CMD_STOP)
+#define TXGBE_I2C_SS_SCL_HCNT           0x14914 /* Standard speed I2C Clock SCL
+												 * High Count */
+#define TXGBE_I2C_SS_SCL_LCNT           0x14918 /* Standard speed I2C Clock SCL
+												 * Low Count */
+#define TXGBE_I2C_FS_SCL_HCNT           0x1491C /* Fast Mode and Fast Mode Plus
+												 * I2C Clock SCL High Count */
+#define TXGBE_I2C_FS_SCL_LCNT           0x14920 /* Fast Mode and Fast Mode Plus
+												 * I2C Clock SCL Low Count */
+#define TXGBE_I2C_HS_SCL_HCNT           0x14924 /* High speed I2C Clock SCL
+												 * High Count */
+#define TXGBE_I2C_HS_SCL_LCNT           0x14928 /* High speed I2C Clock SCL Low
+												 * Count */
+#define TXGBE_I2C_INTR_STAT             0x1492C /* I2C Interrupt Status */
+#define TXGBE_I2C_RAW_INTR_STAT         0x14934 /* I2C Raw Interrupt Status */
+#define TXGBE_I2C_INTR_STAT_RX_FULL     ((0x1) << 2)
+#define TXGBE_I2C_INTR_STAT_TX_EMPTY    ((0x1) << 4)
+#define TXGBE_I2C_INTR_MASK             0x14930 /* I2C Interrupt Mask */
+#define TXGBE_I2C_RX_TL                 0x14938 /* I2C Receive FIFO Threshold */
+#define TXGBE_I2C_TX_TL                 0x1493C /* I2C TX FIFO Threshold */
+#define TXGBE_I2C_CLR_INTR              0x14940 /* Clear Combined and Individual
+												 * Int */
+#define TXGBE_I2C_CLR_RX_UNDER          0x14944 /* Clear RX_UNDER Interrupt */
+#define TXGBE_I2C_CLR_RX_OVER           0x14948 /* Clear RX_OVER Interrupt */
+#define TXGBE_I2C_CLR_TX_OVER           0x1494C /* Clear TX_OVER Interrupt */
+#define TXGBE_I2C_CLR_RD_REQ            0x14950 /* Clear RD_REQ Interrupt */
+#define TXGBE_I2C_CLR_TX_ABRT           0x14954 /* Clear TX_ABRT Interrupt */
+#define TXGBE_I2C_CLR_RX_DONE           0x14958 /* Clear RX_DONE Interrupt */
+#define TXGBE_I2C_CLR_ACTIVITY          0x1495C /* Clear ACTIVITY Interrupt */
+#define TXGBE_I2C_CLR_STOP_DET          0x14960 /* Clear STOP_DET Interrupt */
+#define TXGBE_I2C_CLR_START_DET         0x14964 /* Clear START_DET Interrupt */
+#define TXGBE_I2C_CLR_GEN_CALL          0x14968 /* Clear GEN_CALL Interrupt */
+#define TXGBE_I2C_ENABLE                0x1496C /* I2C Enable */
+#define TXGBE_I2C_STATUS                0x14970 /* I2C Status register */
+#define TXGBE_I2C_STATUS_MST_ACTIVITY   ((1U << 5))
+#define TXGBE_I2C_TXFLR                 0x14974 /* Transmit FIFO Level Reg */
+#define TXGBE_I2C_RXFLR                 0x14978 /* Receive FIFO Level Reg */
+#define TXGBE_I2C_SDA_HOLD              0x1497C /* SDA hold time length reg */
+#define TXGBE_I2C_TX_ABRT_SOURCE        0x14980 /* I2C TX Abort Status Reg */
+#define TXGBE_I2C_SDA_SETUP             0x14994 /* I2C SDA Setup Register */
+#define TXGBE_I2C_ENABLE_STATUS         0x1499C /* I2C Enable Status Register */
+#define TXGBE_I2C_FS_SPKLEN             0x149A0 /* ISS and FS spike suppression
+												 * limit */
+#define TXGBE_I2C_HS_SPKLEN             0x149A4 /* HS spike suppression limit */
+#define TXGBE_I2C_SCL_STUCK_TIMEOUT     0x149AC /* I2C SCL stuck at low timeout
+												 * register */
+#define TXGBE_I2C_SDA_STUCK_TIMEOUT     0x149B0 /*I2C SDA Stuck at Low Timeout*/
+#define TXGBE_I2C_CLR_SCL_STUCK_DET     0x149B4 /* Clear SCL Stuck at Low Detect
+												 * Interrupt */
+#define TXGBE_I2C_DEVICE_ID             0x149b8 /* I2C Device ID */
+#define TXGBE_I2C_COMP_PARAM_1          0x149f4 /* Component Parameter Reg */
+#define TXGBE_I2C_COMP_VERSION          0x149f8 /* Component Version ID */
+#define TXGBE_I2C_COMP_TYPE             0x149fc /* DesignWare Component Type
+												 * Reg */
+
+#define TXGBE_I2C_SLAVE_ADDR            (0xA0 >> 1)
+#define TXGBE_I2C_THERMAL_SENSOR_ADDR   0xF8
+
+
+/* port cfg Registers */
+#define TXGBE_CFG_PORT_CTL              0x14400
+#define TXGBE_CFG_PORT_ST               0x14404
+#define TXGBE_CFG_EX_VTYPE              0x14408
+#define TXGBE_CFG_LED_CTL               0x14424
+#define TXGBE_CFG_VXLAN                 0x14410
+#define TXGBE_CFG_VXLAN_GPE             0x14414
+#define TXGBE_CFG_GENEVE                0x14418
+#define TXGBE_CFG_TEREDO                0x1441C
+#define TXGBE_CFG_TCP_TIME              0x14420
+#define TXGBE_CFG_TAG_TPID(_i)          (0x14430 + ((_i) * 4))
+/* port cfg bit */
+#define TXGBE_CFG_PORT_CTL_PFRSTD       0x00004000U /* Phy Function Reset Done */
+#define TXGBE_CFG_PORT_CTL_D_VLAN       0x00000001U /* double vlan*/
+#define TXGBE_CFG_PORT_CTL_ETAG_ETYPE_VLD 0x00000002U
+#define TXGBE_CFG_PORT_CTL_QINQ         0x00000004U
+#define TXGBE_CFG_PORT_CTL_DRV_LOAD     0x00000008U
+#define TXGBE_CFG_PORT_CTL_FORCE_LKUP   0x00000010U /* force link up */
+#define TXGBE_CFG_PORT_CTL_DCB_EN       0x00000400U /* dcb enabled */
+#define TXGBE_CFG_PORT_CTL_NUM_TC_MASK  0x00000800U /* number of TCs */
+#define TXGBE_CFG_PORT_CTL_NUM_TC_4     0x00000000U
+#define TXGBE_CFG_PORT_CTL_NUM_TC_8     0x00000800U
+#define TXGBE_CFG_PORT_CTL_NUM_VT_MASK  0x00003000U /* number of TVs */
+#define TXGBE_CFG_PORT_CTL_NUM_VT_NONE  0x00000000U
+#define TXGBE_CFG_PORT_CTL_NUM_VT_16    0x00001000U
+#define TXGBE_CFG_PORT_CTL_NUM_VT_32    0x00002000U
+#define TXGBE_CFG_PORT_CTL_NUM_VT_64    0x00003000U
+/* Status Bit */
+#define TXGBE_CFG_PORT_ST_LINK_UP       0x00000001U
+#define TXGBE_CFG_PORT_ST_LINK_10G      0x00000002U
+#define TXGBE_CFG_PORT_ST_LINK_1G       0x00000004U
+#define TXGBE_CFG_PORT_ST_LINK_100M     0x00000008U
+#define TXGBE_CFG_PORT_ST_LAN_ID(_r)    ((0x00000100U & (_r)) >> 8)
+#define TXGBE_LINK_UP_TIME              90
+/* LED CTL Bit */
+#define TXGBE_CFG_LED_CTL_LINK_BSY_SEL  0x00000010U
+#define TXGBE_CFG_LED_CTL_LINK_100M_SEL 0x00000008U
+#define TXGBE_CFG_LED_CTL_LINK_1G_SEL   0x00000004U
+#define TXGBE_CFG_LED_CTL_LINK_10G_SEL  0x00000002U
+#define TXGBE_CFG_LED_CTL_LINK_UP_SEL   0x00000001U
+#define TXGBE_CFG_LED_CTL_LINK_OD_SHIFT 16
+/* LED modes */
+#define TXGBE_LED_LINK_UP               TXGBE_CFG_LED_CTL_LINK_UP_SEL
+#define TXGBE_LED_LINK_10G              TXGBE_CFG_LED_CTL_LINK_10G_SEL
+#define TXGBE_LED_LINK_ACTIVE           TXGBE_CFG_LED_CTL_LINK_BSY_SEL
+#define TXGBE_LED_LINK_1G               TXGBE_CFG_LED_CTL_LINK_1G_SEL
+#define TXGBE_LED_LINK_100M             TXGBE_CFG_LED_CTL_LINK_100M_SEL
+
+/* GPIO Registers */
+#define TXGBE_GPIO_DR                   0x14800
+#define TXGBE_GPIO_DDR                  0x14804
+#define TXGBE_GPIO_CTL                  0x14808
+#define TXGBE_GPIO_INTEN                0x14830
+#define TXGBE_GPIO_INTMASK              0x14834
+#define TXGBE_GPIO_INTTYPE_LEVEL        0x14838
+#define TXGBE_GPIO_INTSTATUS            0x14844
+#define TXGBE_GPIO_EOI                  0x1484C
+/*GPIO bit */
+#define TXGBE_GPIO_DR_0         0x00000001U /* SDP0 Data Value */
+#define TXGBE_GPIO_DR_1         0x00000002U /* SDP1 Data Value */
+#define TXGBE_GPIO_DR_2         0x00000004U /* SDP2 Data Value */
+#define TXGBE_GPIO_DR_3         0x00000008U /* SDP3 Data Value */
+#define TXGBE_GPIO_DR_4         0x00000010U /* SDP4 Data Value */
+#define TXGBE_GPIO_DR_5         0x00000020U /* SDP5 Data Value */
+#define TXGBE_GPIO_DR_6         0x00000040U /* SDP6 Data Value */
+#define TXGBE_GPIO_DR_7         0x00000080U /* SDP7 Data Value */
+#define TXGBE_GPIO_DDR_0        0x00000001U /* SDP0 IO direction */
+#define TXGBE_GPIO_DDR_1        0x00000002U /* SDP1 IO direction */
+#define TXGBE_GPIO_DDR_2        0x00000004U /* SDP1 IO direction */
+#define TXGBE_GPIO_DDR_3        0x00000008U /* SDP3 IO direction */
+#define TXGBE_GPIO_DDR_4        0x00000010U /* SDP4 IO direction */
+#define TXGBE_GPIO_DDR_5        0x00000020U /* SDP5 IO direction */
+#define TXGBE_GPIO_DDR_6        0x00000040U /* SDP6 IO direction */
+#define TXGBE_GPIO_DDR_7        0x00000080U /* SDP7 IO direction */
+#define TXGBE_GPIO_CTL_SW_MODE  0x00000000U /* SDP software mode */
+#define TXGBE_GPIO_INTEN_1      0x00000002U /* SDP1 interrupt enable */
+#define TXGBE_GPIO_INTEN_2      0x00000004U /* SDP2 interrupt enable */
+#define TXGBE_GPIO_INTEN_3      0x00000008U /* SDP3 interrupt enable */
+#define TXGBE_GPIO_INTEN_5      0x00000020U /* SDP5 interrupt enable */
+#define TXGBE_GPIO_INTEN_6      0x00000040U /* SDP6 interrupt enable */
+#define TXGBE_GPIO_INTTYPE_LEVEL_2 0x00000004U /* SDP2 interrupt type level */
+#define TXGBE_GPIO_INTTYPE_LEVEL_3 0x00000008U /* SDP3 interrupt type level */
+#define TXGBE_GPIO_INTTYPE_LEVEL_5 0x00000020U /* SDP5 interrupt type level */
+#define TXGBE_GPIO_INTTYPE_LEVEL_6 0x00000040U /* SDP6 interrupt type level */
+#define TXGBE_GPIO_INTSTATUS_1  0x00000002U /* SDP1 interrupt status */
+#define TXGBE_GPIO_INTSTATUS_2  0x00000004U /* SDP2 interrupt status */
+#define TXGBE_GPIO_INTSTATUS_3  0x00000008U /* SDP3 interrupt status */
+#define TXGBE_GPIO_INTSTATUS_5  0x00000020U /* SDP5 interrupt status */
+#define TXGBE_GPIO_INTSTATUS_6  0x00000040U /* SDP6 interrupt status */
+#define TXGBE_GPIO_EOI_2        0x00000004U /* SDP2 interrupt clear */
+#define TXGBE_GPIO_EOI_3        0x00000008U /* SDP3 interrupt clear */
+#define TXGBE_GPIO_EOI_5        0x00000020U /* SDP5 interrupt clear */
+#define TXGBE_GPIO_EOI_6        0x00000040U /* SDP6 interrupt clear */
+
+/* TPH registers */
+#define TXGBE_CFG_TPH_TDESC     0x14F00 /* TPH conf for Tx desc write back */
+#define TXGBE_CFG_TPH_RDESC     0x14F04 /* TPH conf for Rx desc write back */
+#define TXGBE_CFG_TPH_RHDR      0x14F08 /* TPH conf for writing Rx pkt header */
+#define TXGBE_CFG_TPH_RPL       0x14F0C /* TPH conf for payload write access */
+/* TPH bit */
+#define TXGBE_CFG_TPH_TDESC_EN  0x80000000U
+#define TXGBE_CFG_TPH_TDESC_PH_SHIFT 29
+#define TXGBE_CFG_TPH_TDESC_ST_SHIFT 16
+#define TXGBE_CFG_TPH_RDESC_EN  0x80000000U
+#define TXGBE_CFG_TPH_RDESC_PH_SHIFT 29
+#define TXGBE_CFG_TPH_RDESC_ST_SHIFT 16
+#define TXGBE_CFG_TPH_RHDR_EN   0x00008000U
+#define TXGBE_CFG_TPH_RHDR_PH_SHIFT 13
+#define TXGBE_CFG_TPH_RHDR_ST_SHIFT 0
+#define TXGBE_CFG_TPH_RPL_EN    0x80000000U
+#define TXGBE_CFG_TPH_RPL_PH_SHIFT 29
+#define TXGBE_CFG_TPH_RPL_ST_SHIFT 16
+
+/*********************** Transmit DMA registers **************************/
+/* transmit global control */
+#define TXGBE_TDM_CTL           0x18000
+#define TXGBE_TDM_VF_TE(_i)     (0x18004 + ((_i) * 4))
+#define TXGBE_TDM_VFTE_CLR(_i)  (0x180A0 + ((_i) * 4))
+#define TXGBE_TDM_PB_THRE(_i)   (0x18020 + ((_i) * 4)) /* 8 of these 0 - 7 */
+#define TXGBE_TDM_LLQ(_i)       (0x18040 + ((_i) * 4)) /* 4 of these (0-3) */
+#define TXGBE_TDM_ETYPE_LB_L    0x18050
+#define TXGBE_TDM_ETYPE_LB_H    0x18054
+#define TXGBE_TDM_ETYPE_AS_L    0x18058
+#define TXGBE_TDM_ETYPE_AS_H    0x1805C
+#define TXGBE_TDM_MAC_AS_L      0x18060
+#define TXGBE_TDM_MAC_AS_H      0x18064
+#define TXGBE_TDM_VLAN_AS_L     0x18070
+#define TXGBE_TDM_VLAN_AS_H     0x18074
+#define TXGBE_TDM_TCP_FLG_L     0x18078
+#define TXGBE_TDM_TCP_FLG_H     0x1807C
+#define TXGBE_TDM_VLAN_INS(_i)  (0x18100 + ((_i) * 4)) /* 64 of these 0 - 63 */
+/* TDM CTL BIT */
+#define TXGBE_TDM_CTL_TE        0x1 /* Transmit Enable */
+#define TXGBE_TDM_CTL_PADDING   0x2 /* Padding byte number for ipsec ESP */
+#define TXGBE_TDM_CTL_VT_SHIFT  16  /* VLAN EtherType */
+/* Per VF Port VLAN insertion rules */
+#define TXGBE_TDM_VLAN_INS_VLANA_DEFAULT 0x40000000U /*Always use default VLAN*/
+#define TXGBE_TDM_VLAN_INS_VLANA_NEVER   0x80000000U /* Never insert VLAN tag */
+
+#define TXGBE_TDM_RP_CTL        0x18400
+#define TXGBE_TDM_RP_CTL_RST    ((0x1) << 0)
+#define TXGBE_TDM_RP_CTL_RPEN   ((0x1) << 2)
+#define TXGBE_TDM_RP_CTL_RLEN   ((0x1) << 3)
+#define TXGBE_TDM_RP_IDX        0x1820C
+#define TXGBE_TDM_RP_RATE       0x18404
+#define TXGBE_TDM_RP_RATE_MIN(v) ((0x3FFF & (v)))
+#define TXGBE_TDM_RP_RATE_MAX(v) ((0x3FFF & (v)) << 16)
+
+/* qos */
+#define TXGBE_TDM_PBWARB_CTL    0x18200
+#define TXGBE_TDM_PBWARB_CFG(_i) (0x18220 + ((_i) * 4)) /* 8 of these (0-7) */
+#define TXGBE_TDM_MMW           0x18208
+#define TXGBE_TDM_VM_CREDIT(_i) (0x18500 + ((_i) * 4))
+#define TXGBE_TDM_VM_CREDIT_VAL(v) (0x3FF & (v))
+/* fcoe */
+#define TXGBE_TDM_FC_EOF        0x18384
+#define TXGBE_TDM_FC_SOF        0x18380
+/* etag */
+#define TXGBE_TDM_ETAG_INS(_i)  (0x18700 + ((_i) * 4)) /* 64 of these 0 - 63 */
+/* statistic */
+#define TXGBE_TDM_SEC_DRP       0x18304
+#define TXGBE_TDM_PKT_CNT       0x18308
+#define TXGBE_TDM_OS2BMC_CNT    0x18314
+
+/**************************** Receive DMA registers **************************/
+/* receive control */
+#define TXGBE_RDM_ARB_CTL       0x12000
+#define TXGBE_RDM_VF_RE(_i)     (0x12004 + ((_i) * 4))
+#define TXGBE_RDM_VFRE_CLR(_i)  (0x120A0 + ((_i) * 4))
+#define TXGBE_RDM_RSC_CTL       0x1200C
+#define TXGBE_RDM_ARB_CFG(_i)   (0x12040 + ((_i) * 4)) /* 8 of these (0-7) */
+#define TXGBE_RDM_PF_QDE(_i)    (0x12080 + ((_i) * 4))
+#define TXGBE_RDM_PF_HIDE(_i)   (0x12090 + ((_i) * 4))
+/* VFRE bitmask */
+#define TXGBE_RDM_VF_RE_ENABLE_ALL  0xFFFFFFFFU
+
+/* FCoE DMA Context Registers */
+#define TXGBE_RDM_FCPTRL            0x12410
+#define TXGBE_RDM_FCPTRH            0x12414
+#define TXGBE_RDM_FCBUF             0x12418
+#define TXGBE_RDM_FCBUF_VALID       ((0x1)) /* DMA Context Valid */
+#define TXGBE_RDM_FCBUF_SIZE(_v)    (((_v) & 0x3) << 3) /* User Buffer Size */
+#define TXGBE_RDM_FCBUF_COUNT(_v)   (((_v) & 0xFF) << 8) /* Num of User Buf */
+#define TXGBE_RDM_FCBUF_OFFSET(_v)  (((_v) & 0xFFFF) << 16) /* User Buf Offset*/
+#define TXGBE_RDM_FCRW              0x12420
+#define TXGBE_RDM_FCRW_FCSEL(_v)    (((_v) & 0x1FF))  /* FC X_ID: 11 bits */
+#define TXGBE_RDM_FCRW_WE           ((0x1) << 14)   /* Write enable */
+#define TXGBE_RDM_FCRW_RE           ((0x1) << 15)   /* Read enable */
+#define TXGBE_RDM_FCRW_LASTSIZE(_v) (((_v) & 0xFFFF) << 16)
+
+/* statistic */
+#define TXGBE_RDM_DRP_PKT           0x12500
+#define TXGBE_RDM_BMC2OS_CNT        0x12510
+
+/***************************** RDB registers *********************************/
+/* Flow Control Registers */
+#define TXGBE_RDB_RFCV(_i)          (0x19200 + ((_i) * 4)) /* 4 of these (0-3)*/
+#define TXGBE_RDB_RFCL(_i)          (0x19220 + ((_i) * 4)) /* 8 of these (0-7)*/
+#define TXGBE_RDB_RFCH(_i)          (0x19260 + ((_i) * 4)) /* 8 of these (0-7)*/
+#define TXGBE_RDB_RFCRT             0x192A0
+#define TXGBE_RDB_RFCC              0x192A4
+/* receive packet buffer */
+#define TXGBE_RDB_PB_WRAP           0x19004
+#define TXGBE_RDB_PB_SZ(_i)         (0x19020 + ((_i) * 4))
+#define TXGBE_RDB_PB_CTL            0x19000
+#define TXGBE_RDB_UP2TC             0x19008
+#define TXGBE_RDB_PB_SZ_SHIFT       10
+#define TXGBE_RDB_PB_SZ_MASK        0x000FFC00U
+/* lli interrupt */
+#define TXGBE_RDB_LLI_THRE          0x19080
+#define TXGBE_RDB_LLI_THRE_SZ(_v)   ((0xFFF & (_v)))
+#define TXGBE_RDB_LLI_THRE_UP(_v)   ((0x7 & (_v)) << 16)
+#define TXGBE_RDB_LLI_THRE_UP_SHIFT 16
+
+/* ring assignment */
+#define TXGBE_RDB_PL_CFG(_i)    (0x19300 + ((_i) * 4))
+#define TXGBE_RDB_RSSTBL(_i)    (0x19400 + ((_i) * 4))
+#define TXGBE_RDB_RSSRK(_i)     (0x19480 + ((_i) * 4))
+#define TXGBE_RDB_RSS_TC        0x194F0
+#define TXGBE_RDB_RA_CTL        0x194F4
+#define TXGBE_RDB_5T_SA(_i)     (0x19600 + ((_i) * 4)) /* Src Addr Q Filter */
+#define TXGBE_RDB_5T_DA(_i)     (0x19800 + ((_i) * 4)) /* Dst Addr Q Filter */
+#define TXGBE_RDB_5T_SDP(_i)    (0x19A00 + ((_i) * 4)) /*Src Dst Addr Q Filter*/
+#define TXGBE_RDB_5T_CTL0(_i)   (0x19C00 + ((_i) * 4)) /* Five Tuple Q Filter */
+#define TXGBE_RDB_ETYPE_CLS(_i) (0x19100 + ((_i) * 4)) /* EType Q Select */
+#define TXGBE_RDB_SYN_CLS       0x19130
+#define TXGBE_RDB_5T_CTL1(_i)   (0x19E00 + ((_i) * 4)) /*128 of these (0-127)*/
+/* Flow Director registers */
+#define TXGBE_RDB_FDIR_CTL          0x19500
+#define TXGBE_RDB_FDIR_HKEY         0x19568
+#define TXGBE_RDB_FDIR_SKEY         0x1956C
+#define TXGBE_RDB_FDIR_DA4_MSK      0x1953C
+#define TXGBE_RDB_FDIR_SA4_MSK      0x19540
+#define TXGBE_RDB_FDIR_TCP_MSK      0x19544
+#define TXGBE_RDB_FDIR_UDP_MSK      0x19548
+#define TXGBE_RDB_FDIR_SCTP_MSK     0x19560
+#define TXGBE_RDB_FDIR_IP6_MSK      0x19574
+#define TXGBE_RDB_FDIR_OTHER_MSK    0x19570
+#define TXGBE_RDB_FDIR_FLEX_CFG(_i) (0x19580 + ((_i) * 4))
+/* Flow Director Stats registers */
+#define TXGBE_RDB_FDIR_FREE         0x19538
+#define TXGBE_RDB_FDIR_LEN          0x1954C
+#define TXGBE_RDB_FDIR_USE_ST       0x19550
+#define TXGBE_RDB_FDIR_FAIL_ST      0x19554
+#define TXGBE_RDB_FDIR_MATCH        0x19558
+#define TXGBE_RDB_FDIR_MISS         0x1955C
+/* Flow Director Programming registers */
+#define TXGBE_RDB_FDIR_IP6(_i)      (0x1950C + ((_i) * 4)) /* 3 of these (0-2)*/
+#define TXGBE_RDB_FDIR_SA           0x19518
+#define TXGBE_RDB_FDIR_DA           0x1951C
+#define TXGBE_RDB_FDIR_PORT         0x19520
+#define TXGBE_RDB_FDIR_FLEX         0x19524
+#define TXGBE_RDB_FDIR_HASH         0x19528
+#define TXGBE_RDB_FDIR_CMD          0x1952C
+/* VM RSS */
+#define TXGBE_RDB_VMRSSRK(_i, _p)   (0x1A000 + ((_i) * 4) + ((_p) * 0x40))
+#define TXGBE_RDB_VMRSSTBL(_i, _p)  (0x1B000 + ((_i) * 4) + ((_p) * 0x40))
+/* FCoE Redirection */
+#define TXGBE_RDB_FCRE_TBL_SIZE     (8) /* Max entries in FCRETA */
+#define TXGBE_RDB_FCRE_CTL          0x19140
+#define TXGBE_RDB_FCRE_CTL_ENA      ((0x1)) /* FCoE Redir Table Enable */
+#define TXGBE_RDB_FCRE_TBL(_i)      (0x19160 + ((_i) * 4))
+#define TXGBE_RDB_FCRE_TBL_RING(_v) (((_v) & 0x7F)) /* output queue number */
+/* statistic */
+#define TXGBE_RDB_MPCNT(_i)         (0x19040 + ((_i) * 4)) /* 8 of 3FA0-3FBC*/
+#define TXGBE_RDB_LXONTXC           0x1921C
+#define TXGBE_RDB_LXOFFTXC          0x19218
+#define TXGBE_RDB_PXON2OFFCNT(_i)   (0x19280 + ((_i) * 4)) /* 8 of these */
+#define TXGBE_RDB_PXONTXC(_i)       (0x192E0 + ((_i) * 4)) /* 8 of 3F00-3F1C*/
+#define TXGBE_RDB_PXOFFTXC(_i)      (0x192C0 + ((_i) * 4)) /* 8 of 3F20-3F3C*/
+#define TXGBE_RDB_PFCMACDAL         0x19210
+#define TXGBE_RDB_PFCMACDAH         0x19214
+#define TXGBE_RDB_TXSWERR           0x1906C
+#define TXGBE_RDB_TXSWERR_TB_FREE   0x3FF
+/* rdb_pl_cfg reg mask */
+#define TXGBE_RDB_PL_CFG_L4HDR          0x2
+#define TXGBE_RDB_PL_CFG_L3HDR          0x4
+#define TXGBE_RDB_PL_CFG_L2HDR          0x8
+#define TXGBE_RDB_PL_CFG_TUN_OUTER_L2HDR 0x20
+#define TXGBE_RDB_PL_CFG_TUN_TUNHDR     0x10
+#define TXGBE_RDB_PL_CFG_RSS_PL_MASK    0x7
+#define TXGBE_RDB_PL_CFG_RSS_PL_SHIFT   29
+/* RQTC Bit Masks and Shifts */
+#define TXGBE_RDB_RSS_TC_SHIFT_TC(_i)   ((_i) * 4)
+#define TXGBE_RDB_RSS_TC_TC0_MASK       (0x7 << 0)
+#define TXGBE_RDB_RSS_TC_TC1_MASK       (0x7 << 4)
+#define TXGBE_RDB_RSS_TC_TC2_MASK       (0x7 << 8)
+#define TXGBE_RDB_RSS_TC_TC3_MASK       (0x7 << 12)
+#define TXGBE_RDB_RSS_TC_TC4_MASK       (0x7 << 16)
+#define TXGBE_RDB_RSS_TC_TC5_MASK       (0x7 << 20)
+#define TXGBE_RDB_RSS_TC_TC6_MASK       (0x7 << 24)
+#define TXGBE_RDB_RSS_TC_TC7_MASK       (0x7 << 28)
+/* Packet Buffer Initialization */
+#define TXGBE_MAX_PACKET_BUFFERS        8
+#define TXGBE_RDB_PB_SZ_48KB    0x00000030U /* 48KB Packet Buffer */
+#define TXGBE_RDB_PB_SZ_64KB    0x00000040U /* 64KB Packet Buffer */
+#define TXGBE_RDB_PB_SZ_80KB    0x00000050U /* 80KB Packet Buffer */
+#define TXGBE_RDB_PB_SZ_128KB   0x00000080U /* 128KB Packet Buffer */
+#define TXGBE_RDB_PB_SZ_MAX     0x00000200U /* 512KB Packet Buffer */
+
+
+/* Packet buffer allocation strategies */
+enum {
+	PBA_STRATEGY_EQUAL      = 0, /* Distribute PB space equally */
+#define PBA_STRATEGY_EQUAL      PBA_STRATEGY_EQUAL
+	PBA_STRATEGY_WEIGHTED   = 1, /* Weight front half of TCs */
+#define PBA_STRATEGY_WEIGHTED   PBA_STRATEGY_WEIGHTED
+};
+
+
+/* FCRTL Bit Masks */
+#define TXGBE_RDB_RFCL_XONE             0x80000000U /* XON enable */
+#define TXGBE_RDB_RFCH_XOFFE            0x80000000U /* Packet buffer fc enable */
+/* FCCFG Bit Masks */
+#define TXGBE_RDB_RFCC_RFCE_802_3X      0x00000008U /* Tx link FC enable */
+#define TXGBE_RDB_RFCC_RFCE_PRIORITY    0x00000010U /* Tx priority FC enable */
+
+/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
+#define TXGBE_RDB_5T_CTL1_SIZE_BP       0x00001000U /* Packet size bypass */
+#define TXGBE_RDB_5T_CTL1_LLI           0x00100000U /* Enables low latency Int */
+#define TXGBE_RDB_LLI_THRE_PRIORITY_MASK 0x00070000U /* VLAN priority mask */
+#define TXGBE_RDB_LLI_THRE_PRIORITY_EN  0x00080000U /* VLAN priority enable */
+#define TXGBE_RDB_LLI_THRE_CMN_EN       0x00100000U /* cmn packet receiveed */
+
+#define TXGBE_MAX_RDB_5T_CTL0_FILTERS           128
+#define TXGBE_RDB_5T_CTL0_PROTOCOL_MASK         0x00000003U
+#define TXGBE_RDB_5T_CTL0_PROTOCOL_TCP          0x00000000U
+#define TXGBE_RDB_5T_CTL0_PROTOCOL_UDP          0x00000001U
+#define TXGBE_RDB_5T_CTL0_PROTOCOL_SCTP         2
+#define TXGBE_RDB_5T_CTL0_PRIORITY_MASK         0x00000007U
+#define TXGBE_RDB_5T_CTL0_PRIORITY_SHIFT        2
+#define TXGBE_RDB_5T_CTL0_POOL_MASK             0x0000003FU
+#define TXGBE_RDB_5T_CTL0_POOL_SHIFT            8
+#define TXGBE_RDB_5T_CTL0_5TUPLE_MASK_MASK      0x0000001FU
+#define TXGBE_RDB_5T_CTL0_5TUPLE_MASK_SHIFT     25
+#define TXGBE_RDB_5T_CTL0_SOURCE_ADDR_MASK      0x1E
+#define TXGBE_RDB_5T_CTL0_DEST_ADDR_MASK        0x1D
+#define TXGBE_RDB_5T_CTL0_SOURCE_PORT_MASK      0x1B
+#define TXGBE_RDB_5T_CTL0_DEST_PORT_MASK        0x17
+#define TXGBE_RDB_5T_CTL0_PROTOCOL_COMP_MASK    0x0F
+#define TXGBE_RDB_5T_CTL0_POOL_MASK_EN          0x40000000U
+#define TXGBE_RDB_5T_CTL0_QUEUE_ENABLE          0x80000000U
+
+#define TXGBE_RDB_ETYPE_CLS_RX_QUEUE            0x007F0000U /* bits 22:16 */
+#define TXGBE_RDB_ETYPE_CLS_RX_QUEUE_SHIFT      16
+#define TXGBE_RDB_ETYPE_CLS_LLI                 0x20000000U /* bit 29 */
+#define TXGBE_RDB_ETYPE_CLS_QUEUE_EN            0x80000000U /* bit 31 */
+
+/* Receive Config masks */
+#define TXGBE_RDB_PB_CTL_RXEN           (0x80000000) /* Enable Receiver */
+#define TXGBE_RDB_PB_CTL_DISABLED       0x1
+
+#define TXGBE_RDB_RA_CTL_RSS_EN         0x00000004U /* RSS Enable */
+//#define TXGBE_RDB_RA_CTL_MULTI_RSS    0x00000001U /* VF RSS Hash Rule Enable */
+#define TXGBE_RDB_RA_CTL_RSS_MASK       0xFFFF0000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV4_TCP   0x00010000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV4       0x00020000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV6       0x00100000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV6_TCP   0x00200000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV4_UDP   0x00400000U
+#define TXGBE_RDB_RA_CTL_RSS_IPV6_UDP   0x00800000U
+
+enum txgbe_fdir_pballoc_type {
+	TXGBE_FDIR_PBALLOC_NONE = 0,
+	TXGBE_FDIR_PBALLOC_64K  = 1,
+	TXGBE_FDIR_PBALLOC_128K = 2,
+	TXGBE_FDIR_PBALLOC_256K = 3,
+};
+
+/* Flow Director register values */
+#define TXGBE_RDB_FDIR_CTL_PBALLOC_64K          0x00000001U
+#define TXGBE_RDB_FDIR_CTL_PBALLOC_128K         0x00000002U
+#define TXGBE_RDB_FDIR_CTL_PBALLOC_256K         0x00000003U
+#define TXGBE_RDB_FDIR_CTL_INIT_DONE            0x00000008U
+#define TXGBE_RDB_FDIR_CTL_PERFECT_MATCH        0x00000010U
+#define TXGBE_RDB_FDIR_CTL_REPORT_STATUS        0x00000020U
+#define TXGBE_RDB_FDIR_CTL_REPORT_STATUS_ALWAYS 0x00000080U
+#define TXGBE_RDB_FDIR_CTL_DROP_Q_SHIFT         8
+#define TXGBE_RDB_FDIR_CTL_FILTERMODE_SHIFT     21
+#define TXGBE_RDB_FDIR_CTL_MAX_LENGTH_SHIFT     24
+#define TXGBE_RDB_FDIR_CTL_HASH_BITS_SHIFT      20
+#define TXGBE_RDB_FDIR_CTL_FULL_THRESH_MASK     0xF0000000U
+#define TXGBE_RDB_FDIR_CTL_FULL_THRESH_SHIFT    28
+
+
+#define TXGBE_RDB_FDIR_TCP_MSK_DPORTM_SHIFT     16
+#define TXGBE_RDB_FDIR_UDP_MSK_DPORTM_SHIFT     16
+#define TXGBE_RDB_FDIR_IP6_MSK_DIPM_SHIFT       16
+#define TXGBE_RDB_FDIR_OTHER_MSK_POOL           0x00000004U
+#define TXGBE_RDB_FDIR_OTHER_MSK_L4P            0x00000008U
+#define TXGBE_RDB_FDIR_OTHER_MSK_L3P            0x00000010U
+#define TXGBE_RDB_FDIR_OTHER_MSK_TUN_TYPE       0x00000020U
+#define TXGBE_RDB_FDIR_OTHER_MSK_TUN_OUTIP      0x00000040U
+#define TXGBE_RDB_FDIR_OTHER_MSK_TUN            0x00000080U
+
+#define TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC        0x00000000U
+#define TXGBE_RDB_FDIR_FLEX_CFG_BASE_IP         0x00000001U
+#define TXGBE_RDB_FDIR_FLEX_CFG_BASE_L4_HDR     0x00000002U
+#define TXGBE_RDB_FDIR_FLEX_CFG_BASE_L4_PAYLOAD 0x00000003U
+#define TXGBE_RDB_FDIR_FLEX_CFG_BASE_MSK        0x00000003U
+#define TXGBE_RDB_FDIR_FLEX_CFG_MSK             0x00000004U
+#define TXGBE_RDB_FDIR_FLEX_CFG_OFST            0x000000F8U
+#define TXGBE_RDB_FDIR_FLEX_CFG_OFST_SHIFT      3
+#define TXGBE_RDB_FDIR_FLEX_CFG_VM_SHIFT        8
+
+#define TXGBE_RDB_FDIR_PORT_DESTINATION_SHIFT   16
+#define TXGBE_RDB_FDIR_FLEX_FLEX_SHIFT          16
+#define TXGBE_RDB_FDIR_HASH_BUCKET_VALID_SHIFT  15
+#define TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX_SHIFT  16
+
+#define TXGBE_RDB_FDIR_CMD_CMD_MASK             0x00000003U
+#define TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW         0x00000001U
+#define TXGBE_RDB_FDIR_CMD_CMD_REMOVE_FLOW      0x00000002U
+#define TXGBE_RDB_FDIR_CMD_CMD_QUERY_REM_FILT   0x00000003U
+#define TXGBE_RDB_FDIR_CMD_FILTER_VALID         0x00000004U
+#define TXGBE_RDB_FDIR_CMD_FILTER_UPDATE        0x00000008U
+#define TXGBE_RDB_FDIR_CMD_IPv6DMATCH           0x00000010U
+#define TXGBE_RDB_FDIR_CMD_L4TYPE_UDP           0x00000020U
+#define TXGBE_RDB_FDIR_CMD_L4TYPE_TCP           0x00000040U
+#define TXGBE_RDB_FDIR_CMD_L4TYPE_SCTP          0x00000060U
+#define TXGBE_RDB_FDIR_CMD_IPV6                 0x00000080U
+#define TXGBE_RDB_FDIR_CMD_CLEARHT              0x00000100U
+#define TXGBE_RDB_FDIR_CMD_DROP                 0x00000200U
+#define TXGBE_RDB_FDIR_CMD_INT                  0x00000400U
+#define TXGBE_RDB_FDIR_CMD_LAST                 0x00000800U
+#define TXGBE_RDB_FDIR_CMD_COLLISION            0x00001000U
+#define TXGBE_RDB_FDIR_CMD_QUEUE_EN             0x00008000U
+#define TXGBE_RDB_FDIR_CMD_FLOW_TYPE_SHIFT      5
+#define TXGBE_RDB_FDIR_CMD_RX_QUEUE_SHIFT       16
+#define TXGBE_RDB_FDIR_CMD_TUNNEL_FILTER_SHIFT  23
+#define TXGBE_RDB_FDIR_CMD_VT_POOL_SHIFT        24
+#define TXGBE_RDB_FDIR_INIT_DONE_POLL           10
+#define TXGBE_RDB_FDIR_CMD_CMD_POLL             10
+#define TXGBE_RDB_FDIR_CMD_TUNNEL_FILTER        0x00800000U
+#define TXGBE_RDB_FDIR_DROP_QUEUE               127
+#define TXGBE_FDIR_INIT_DONE_POLL               10
+
+/******************************* PSR Registers *******************************/
+/* psr control */
+#define TXGBE_PSR_CTL                   0x15000
+#define TXGBE_PSR_VLAN_CTL              0x15088
+#define TXGBE_PSR_VM_CTL                0x151B0
+/* Header split receive */
+#define TXGBE_PSR_CTL_SW_EN             0x00040000U
+#define TXGBE_PSR_CTL_RSC_DIS           0x00010000U
+#define TXGBE_PSR_CTL_RSC_ACK           0x00020000U
+#define TXGBE_PSR_CTL_PCSD              0x00002000U
+#define TXGBE_PSR_CTL_IPPCSE            0x00001000U
+#define TXGBE_PSR_CTL_BAM               0x00000400U
+#define TXGBE_PSR_CTL_UPE               0x00000200U
+#define TXGBE_PSR_CTL_MPE               0x00000100U
+#define TXGBE_PSR_CTL_MFE               0x00000080U
+#define TXGBE_PSR_CTL_MO                0x00000060U
+#define TXGBE_PSR_CTL_TPE               0x00000010U
+#define TXGBE_PSR_CTL_MO_SHIFT          5
+/* VT_CTL bitmasks */
+#define TXGBE_PSR_VM_CTL_DIS_DEFPL      0x20000000U /* disable default pool */
+#define TXGBE_PSR_VM_CTL_REPLEN         0x40000000U /* replication enabled */
+#define TXGBE_PSR_VM_CTL_POOL_SHIFT     7
+#define TXGBE_PSR_VM_CTL_POOL_MASK      (0x3F << TXGBE_PSR_VM_CTL_POOL_SHIFT)
+/* VLAN Control Bit Masks */
+#define TXGBE_PSR_VLAN_CTL_VET          0x0000FFFFU  /* bits 0-15 */
+#define TXGBE_PSR_VLAN_CTL_CFI          0x10000000U  /* bit 28 */
+#define TXGBE_PSR_VLAN_CTL_CFIEN        0x20000000U  /* bit 29 */
+#define TXGBE_PSR_VLAN_CTL_VFE          0x40000000U  /* bit 30 */
+
+/* vm L2 contorl */
+#define TXGBE_PSR_VM_L2CTL(_i)          (0x15600 + ((_i) * 4))
+/* VMOLR bitmasks */
+#define TXGBE_PSR_VM_L2CTL_LBDIS        0x00000002U /* disable loopback */
+#define TXGBE_PSR_VM_L2CTL_LLB          0x00000004U /* local pool loopback */
+#define TXGBE_PSR_VM_L2CTL_UPE          0x00000010U /* unicast promiscuous */
+#define TXGBE_PSR_VM_L2CTL_TPE          0x00000020U /* ETAG promiscuous */
+#define TXGBE_PSR_VM_L2CTL_VACC         0x00000040U /* accept nomatched vlan */
+#define TXGBE_PSR_VM_L2CTL_VPE          0x00000080U /* vlan promiscuous mode */
+#define TXGBE_PSR_VM_L2CTL_AUPE         0x00000100U /* accept untagged packets */
+#define TXGBE_PSR_VM_L2CTL_ROMPE        0x00000200U /*accept packets in MTA tbl*/
+#define TXGBE_PSR_VM_L2CTL_ROPE         0x00000400U /* accept packets in UC tbl*/
+#define TXGBE_PSR_VM_L2CTL_BAM          0x00000800U /* accept broadcast packets*/
+#define TXGBE_PSR_VM_L2CTL_MPE          0x00001000U /* multicast promiscuous */
+
+/* etype switcher 1st stage */
+#define TXGBE_PSR_ETYPE_SWC(_i) (0x15128 + ((_i) * 4)) /* EType Queue Filter */
+/* ETYPE Queue Filter/Select Bit Masks */
+#define TXGBE_MAX_PSR_ETYPE_SWC_FILTERS         8
+#define TXGBE_PSR_ETYPE_SWC_FCOE                0x08000000U /* bit 27 */
+#define TXGBE_PSR_ETYPE_SWC_TX_ANTISPOOF        0x20000000U /* bit 29 */
+#define TXGBE_PSR_ETYPE_SWC_1588                0x40000000U /* bit 30 */
+#define TXGBE_PSR_ETYPE_SWC_FILTER_EN           0x80000000U /* bit 31 */
+#define TXGBE_PSR_ETYPE_SWC_POOL_ENABLE         (1 << 26) /* bit 26 */
+#define TXGBE_PSR_ETYPE_SWC_POOL_SHIFT          20
+/*
+ * ETQF filter list: one static filter per filter consumer. This is
+ *                 to avoid filter collisions later. Add new filters
+ *                 here!!
+ *
+ * Current filters:
+ *      EAPOL 802.1x (0x888e): Filter 0
+ *      FCoE (0x8906):   Filter 2
+ *      1588 (0x88f7):   Filter 3
+ *      FIP  (0x8914):   Filter 4
+ *      LLDP (0x88CC):   Filter 5
+ *      LACP (0x8809):   Filter 6
+ *      FC   (0x8808):   Filter 7
+ */
+#define TXGBE_PSR_ETYPE_SWC_FILTER_EAPOL        0
+#define TXGBE_PSR_ETYPE_SWC_FILTER_FCOE         2
+#define TXGBE_PSR_ETYPE_SWC_FILTER_1588         3
+#define TXGBE_PSR_ETYPE_SWC_FILTER_FIP          4
+#define TXGBE_PSR_ETYPE_SWC_FILTER_LLDP         5
+#define TXGBE_PSR_ETYPE_SWC_FILTER_LACP         6
+#define TXGBE_PSR_ETYPE_SWC_FILTER_FC           7
+
+/* mcasst/ucast overflow tbl */
+#define TXGBE_PSR_MC_TBL(_i)    (0x15200  + ((_i) * 4))
+#define TXGBE_PSR_UC_TBL(_i)    (0x15400 + ((_i) * 4))
+
+/* vlan tbl */
+#define TXGBE_PSR_VLAN_TBL(_i)  (0x16000 + ((_i) * 4))
+
+/* mac switcher */
+#define TXGBE_PSR_MAC_SWC_AD_L  0x16200
+#define TXGBE_PSR_MAC_SWC_AD_H  0x16204
+#define TXGBE_PSR_MAC_SWC_VM_L  0x16208
+#define TXGBE_PSR_MAC_SWC_VM_H  0x1620C
+#define TXGBE_PSR_MAC_SWC_IDX   0x16210
+/* RAH */
+#define TXGBE_PSR_MAC_SWC_AD_H_AD(v)       (((v) & 0xFFFF))
+#define TXGBE_PSR_MAC_SWC_AD_H_ADTYPE(v)   (((v) & 0x1) << 30)
+#define TXGBE_PSR_MAC_SWC_AD_H_AV       0x80000000U
+#define TXGBE_CLEAR_VMDQ_ALL            0xFFFFFFFFU
+
+/* vlan switch */
+#define TXGBE_PSR_VLAN_SWC      0x16220
+#define TXGBE_PSR_VLAN_SWC_VM_L 0x16224
+#define TXGBE_PSR_VLAN_SWC_VM_H 0x16228
+#define TXGBE_PSR_VLAN_SWC_IDX  0x16230         /* 64 vlan entries */
+/* VLAN pool filtering masks */
+#define TXGBE_PSR_VLAN_SWC_VIEN         0x80000000U  /* filter is valid */
+#define TXGBE_PSR_VLAN_SWC_ENTRIES      64
+#define TXGBE_PSR_VLAN_SWC_VLANID_MASK  0x00000FFFU
+#define TXGBE_ETHERNET_IEEE_VLAN_TYPE   0x8100  /* 802.1q protocol */
+
+/* cloud switch */
+#define TXGBE_PSR_CL_SWC_DST0    0x16240
+#define TXGBE_PSR_CL_SWC_DST1    0x16244
+#define TXGBE_PSR_CL_SWC_DST2    0x16248
+#define TXGBE_PSR_CL_SWC_DST3    0x1624c
+#define TXGBE_PSR_CL_SWC_KEY     0x16250
+#define TXGBE_PSR_CL_SWC_CTL     0x16254
+#define TXGBE_PSR_CL_SWC_VM_L    0x16258
+#define TXGBE_PSR_CL_SWC_VM_H    0x1625c
+#define TXGBE_PSR_CL_SWC_IDX     0x16260
+
+#define TXGBE_PSR_CL_SWC_CTL_VLD        0x80000000U
+#define TXGBE_PSR_CL_SWC_CTL_DST_MSK    0x00000002U
+#define TXGBE_PSR_CL_SWC_CTL_KEY_MSK    0x00000001U
+
+
+/* FCoE SOF/EOF */
+#define TXGBE_PSR_FC_EOF        0x15158
+#define TXGBE_PSR_FC_SOF        0x151F8
+/* FCoE Filter Context Registers */
+#define TXGBE_PSR_FC_FLT_CTXT           0x15108
+#define TXGBE_PSR_FC_FLT_CTXT_VALID     ((0x1)) /* Filter Context Valid */
+#define TXGBE_PSR_FC_FLT_CTXT_FIRST     ((0x1) << 1) /* Filter First */
+#define TXGBE_PSR_FC_FLT_CTXT_WR        ((0x1) << 2) /* Write/Read Context */
+#define TXGBE_PSR_FC_FLT_CTXT_SEQID(_v) (((_v) & 0xFF) << 8) /* Sequence ID */
+#define TXGBE_PSR_FC_FLT_CTXT_SEQCNT(_v) (((_v) & 0xFFFF) << 16) /* Seq Count */
+
+#define TXGBE_PSR_FC_FLT_RW             0x15110
+#define TXGBE_PSR_FC_FLT_RW_FCSEL(_v)   (((_v) & 0x1FF)) /* FC OX_ID: 11 bits */
+#define TXGBE_PSR_FC_FLT_RW_RVALDT      ((0x1) << 13)  /* Fast Re-Validation */
+#define TXGBE_PSR_FC_FLT_RW_WE          ((0x1) << 14)  /* Write Enable */
+#define TXGBE_PSR_FC_FLT_RW_RE          ((0x1) << 15)  /* Read Enable */
+
+#define TXGBE_PSR_FC_PARAM              0x151D8
+
+/* FCoE Receive Control */
+#define TXGBE_PSR_FC_CTL                0x15100
+#define TXGBE_PSR_FC_CTL_FCOELLI        ((0x1))   /* Low latency interrupt */
+#define TXGBE_PSR_FC_CTL_SAVBAD         ((0x1) << 1) /* Save Bad Frames */
+#define TXGBE_PSR_FC_CTL_FRSTRDH        ((0x1) << 2) /* EN 1st Read Header */
+#define TXGBE_PSR_FC_CTL_LASTSEQH       ((0x1) << 3) /* EN Last Header in Seq */
+#define TXGBE_PSR_FC_CTL_ALLH           ((0x1) << 4) /* EN All Headers */
+#define TXGBE_PSR_FC_CTL_FRSTSEQH       ((0x1) << 5) /* EN 1st Seq. Header */
+#define TXGBE_PSR_FC_CTL_ICRC           ((0x1) << 6) /* Ignore Bad FC CRC */
+#define TXGBE_PSR_FC_CTL_FCCRCBO        ((0x1) << 7) /* FC CRC Byte Ordering */
+#define TXGBE_PSR_FC_CTL_FCOEVER(_v)    (((_v) & 0xF) << 8) /* FCoE Version */
+
+/* Management */
+#define TXGBE_PSR_MNG_FIT_CTL           0x15820
+/* Management Bit Fields and Masks */
+#define TXGBE_PSR_MNG_FIT_CTL_MPROXYE    0x40000000U /* Management Proxy Enable*/
+#define TXGBE_PSR_MNG_FIT_CTL_RCV_TCO_EN 0x00020000U /* Rcv TCO packet enable */
+#define TXGBE_PSR_MNG_FIT_CTL_EN_BMC2OS  0x10000000U /* Ena BMC2OS and OS2BMC
+													  *traffic */
+#define TXGBE_PSR_MNG_FIT_CTL_EN_BMC2OS_SHIFT   28
+
+#define TXGBE_PSR_MNG_FLEX_SEL  0x1582C
+#define TXGBE_PSR_MNG_FLEX_DW_L(_i) (0x15A00 + ((_i) * 16))
+#define TXGBE_PSR_MNG_FLEX_DW_H(_i) (0x15A04 + ((_i) * 16))
+#define TXGBE_PSR_MNG_FLEX_MSK(_i)  (0x15A08 + ((_i) * 16))
+
+/* mirror */
+#define TXGBE_PSR_MR_CTL(_i)    (0x15B00 + ((_i) * 4))
+#define TXGBE_PSR_MR_VLAN_L(_i) (0x15B10 + ((_i) * 8))
+#define TXGBE_PSR_MR_VLAN_H(_i) (0x15B14 + ((_i) * 8))
+#define TXGBE_PSR_MR_VM_L(_i)   (0x15B30 + ((_i) * 8))
+#define TXGBE_PSR_MR_VM_H(_i)   (0x15B34 + ((_i) * 8))
+
+/* 1588 */
+#define TXGBE_PSR_1588_CTL      0x15188 /* Rx Time Sync Control register - RW */
+#define TXGBE_PSR_1588_STMPL    0x151E8 /* Rx timestamp Low - RO */
+#define TXGBE_PSR_1588_STMPH    0x151A4 /* Rx timestamp High - RO */
+#define TXGBE_PSR_1588_ATTRL    0x151A0 /* Rx timestamp attribute low - RO */
+#define TXGBE_PSR_1588_ATTRH    0x151A8 /* Rx timestamp attribute high - RO */
+#define TXGBE_PSR_1588_MSGTYPE  0x15120 /* RX message type register low - RW */
+/* 1588 CTL Bit */
+#define TXGBE_PSR_1588_CTL_VALID            0x00000001U /* Rx timestamp valid */
+#define TXGBE_PSR_1588_CTL_TYPE_MASK        0x0000000EU /* Rx type mask */
+#define TXGBE_PSR_1588_CTL_TYPE_L2_V2       0x00
+#define TXGBE_PSR_1588_CTL_TYPE_L4_V1       0x02
+#define TXGBE_PSR_1588_CTL_TYPE_L2_L4_V2    0x04
+#define TXGBE_PSR_1588_CTL_TYPE_EVENT_V2    0x0A
+#define TXGBE_PSR_1588_CTL_ENABLED          0x00000010U /* Rx Timestamp enabled*/
+/* 1588 msg type bit */
+#define TXGBE_PSR_1588_MSGTYPE_V1_CTRLT_MASK            0x000000FFU
+#define TXGBE_PSR_1588_MSGTYPE_V1_SYNC_MSG              0x00
+#define TXGBE_PSR_1588_MSGTYPE_V1_DELAY_REQ_MSG         0x01
+#define TXGBE_PSR_1588_MSGTYPE_V1_FOLLOWUP_MSG          0x02
+#define TXGBE_PSR_1588_MSGTYPE_V1_DELAY_RESP_MSG        0x03
+#define TXGBE_PSR_1588_MSGTYPE_V1_MGMT_MSG              0x04
+#define TXGBE_PSR_1588_MSGTYPE_V2_MSGID_MASK            0x0000FF00U
+#define TXGBE_PSR_1588_MSGTYPE_V2_SYNC_MSG              0x0000
+#define TXGBE_PSR_1588_MSGTYPE_V2_DELAY_REQ_MSG         0x0100
+#define TXGBE_PSR_1588_MSGTYPE_V2_PDELAY_REQ_MSG        0x0200
+#define TXGBE_PSR_1588_MSGTYPE_V2_PDELAY_RESP_MSG       0x0300
+#define TXGBE_PSR_1588_MSGTYPE_V2_FOLLOWUP_MSG          0x0800
+#define TXGBE_PSR_1588_MSGTYPE_V2_DELAY_RESP_MSG        0x0900
+#define TXGBE_PSR_1588_MSGTYPE_V2_PDELAY_FOLLOWUP_MSG   0x0A00
+#define TXGBE_PSR_1588_MSGTYPE_V2_ANNOUNCE_MSG          0x0B00
+#define TXGBE_PSR_1588_MSGTYPE_V2_SIGNALLING_MSG        0x0C00
+#define TXGBE_PSR_1588_MSGTYPE_V2_MGMT_MSG              0x0D00
+
+/* Wake up registers */
+#define TXGBE_PSR_WKUP_CTL      0x15B80
+#define TXGBE_PSR_WKUP_IPV      0x15B84
+#define TXGBE_PSR_LAN_FLEX_SEL  0x15B8C
+#define TXGBE_PSR_WKUP_IP4TBL(_i)       (0x15BC0 + ((_i) * 4))
+#define TXGBE_PSR_WKUP_IP6TBL(_i)       (0x15BE0 + ((_i) * 4))
+#define TXGBE_PSR_LAN_FLEX_DW_L(_i)     (0x15C00 + ((_i) * 16))
+#define TXGBE_PSR_LAN_FLEX_DW_H(_i)     (0x15C04 + ((_i) * 16))
+#define TXGBE_PSR_LAN_FLEX_MSK(_i)      (0x15C08 + ((_i) * 16))
+#define TXGBE_PSR_LAN_FLEX_CTL  0x15CFC
+/* Wake Up Filter Control Bit */
+#define TXGBE_PSR_WKUP_CTL_LNKC 0x00000001U /* Link Status Change Wakeup Enable*/
+#define TXGBE_PSR_WKUP_CTL_MAG  0x00000002U /* Magic Packet Wakeup Enable */
+#define TXGBE_PSR_WKUP_CTL_EX   0x00000004U /* Directed Exact Wakeup Enable */
+#define TXGBE_PSR_WKUP_CTL_MC   0x00000008U /* Directed Multicast Wakeup Enable*/
+#define TXGBE_PSR_WKUP_CTL_BC   0x00000010U /* Broadcast Wakeup Enable */
+#define TXGBE_PSR_WKUP_CTL_ARP  0x00000020U /* ARP Request Packet Wakeup Enable*/
+#define TXGBE_PSR_WKUP_CTL_IPV4 0x00000040U /* Directed IPv4 Pkt Wakeup Enable */
+#define TXGBE_PSR_WKUP_CTL_IPV6 0x00000080U /* Directed IPv6 Pkt Wakeup Enable */
+#define TXGBE_PSR_WKUP_CTL_IGNORE_TCO   0x00008000U /* Ignore WakeOn TCO pkts */
+#define TXGBE_PSR_WKUP_CTL_FLX0         0x00010000U /* Flexible Filter 0 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX1         0x00020000U /* Flexible Filter 1 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX2         0x00040000U /* Flexible Filter 2 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX3         0x00080000U /* Flexible Filter 3 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX4         0x00100000U /* Flexible Filter 4 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX5         0x00200000U /* Flexible Filter 5 Ena */
+#define TXGBE_PSR_WKUP_CTL_FLX_FILTERS  0x000F0000U /* Mask for 4 flex filters */
+#define TXGBE_PSR_WKUP_CTL_FLX_FILTERS_6 0x003F0000U /* Mask for 6 flex filters*/
+#define TXGBE_PSR_WKUP_CTL_FLX_FILTERS_8 0x00FF0000U /* Mask for 8 flex filters*/
+#define TXGBE_PSR_WKUP_CTL_FW_RST_WK    0x80000000U /* Ena wake on FW reset
+													 * assertion */
+/* Mask for Ext. flex filters */
+#define TXGBE_PSR_WKUP_CTL_EXT_FLX_FILTERS  0x00300000U
+#define TXGBE_PSR_WKUP_CTL_ALL_FILTERS   0x000F00FFU /* Mask all 4 flex filters*/
+#define TXGBE_PSR_WKUP_CTL_ALL_FILTERS_6 0x003F00FFU /* Mask all 6 flex filters*/
+#define TXGBE_PSR_WKUP_CTL_ALL_FILTERS_8 0x00FF00FFU /* Mask all 8 flex filters*/
+#define TXGBE_PSR_WKUP_CTL_FLX_OFFSET    16 /* Offset to the Flex Filters bits*/
+
+#define TXGBE_PSR_MAX_SZ                0x15020
+
+/****************************** TDB ******************************************/
+#define TXGBE_TDB_TFCS                  0x1CE00
+#define TXGBE_TDB_PB_SZ(_i)             (0x1CC00 + ((_i) * 4)) /* 8 of these */
+#define TXGBE_TDB_MNG_TC                0x1CD10
+#define TXGBE_TDB_PRB_CTL               0x17010
+#define TXGBE_TDB_PBRARB_CTL            0x1CD00
+#define TXGBE_TDB_UP2TC                 0x1C800
+#define TXGBE_TDB_PBRARB_CFG(_i)        (0x1CD20 + ((_i) * 4)) /* 8 of (0-7) */
+
+#define TXGBE_TDB_PB_SZ_20KB    0x00005000U /* 20KB Packet Buffer */
+#define TXGBE_TDB_PB_SZ_40KB    0x0000A000U /* 40KB Packet Buffer */
+#define TXGBE_TDB_PB_SZ_MAX     0x00028000U /* 160KB Packet Buffer */
+#define TXGBE_TXPKT_SIZE_MAX    0xA /* Max Tx Packet size */
+#define TXGBE_MAX_PB            8
+
+/****************************** TSEC *****************************************/
+/* Security Control Registers */
+#define TXGBE_TSC_CTL                   0x1D000
+#define TXGBE_TSC_ST                    0x1D004
+#define TXGBE_TSC_BUF_AF                0x1D008
+#define TXGBE_TSC_BUF_AE                0x1D00C
+#define TXGBE_TSC_PRB_CTL               0x1D010
+#define TXGBE_TSC_MIN_IFG               0x1D020
+/* Security Bit Fields and Masks */
+#define TXGBE_TSC_CTL_SECTX_DIS         0x00000001U
+#define TXGBE_TSC_CTL_TX_DIS            0x00000002U
+#define TXGBE_TSC_CTL_STORE_FORWARD     0x00000004U
+#define TXGBE_TSC_CTL_IV_MSK_EN         0x00000008U
+#define TXGBE_TSC_ST_SECTX_RDY          0x00000001U
+#define TXGBE_TSC_ST_OFF_DIS            0x00000002U
+#define TXGBE_TSC_ST_ECC_TXERR          0x00000004U
+
+/* LinkSec (MacSec) Registers */
+#define TXGBE_TSC_LSEC_CAP              0x1D200
+#define TXGBE_TSC_LSEC_CTL              0x1D204
+#define TXGBE_TSC_LSEC_SCI_L            0x1D208
+#define TXGBE_TSC_LSEC_SCI_H            0x1D20C
+#define TXGBE_TSC_LSEC_SA               0x1D210
+#define TXGBE_TSC_LSEC_PKTNUM0          0x1D214
+#define TXGBE_TSC_LSEC_PKTNUM1          0x1D218
+#define TXGBE_TSC_LSEC_KEY0(_n)         0x1D21C
+#define TXGBE_TSC_LSEC_KEY1(_n)         0x1D22C
+#define TXGBE_TSC_LSEC_UNTAG_PKT        0x1D23C
+#define TXGBE_TSC_LSEC_ENC_PKT          0x1D240
+#define TXGBE_TSC_LSEC_PROT_PKT         0x1D244
+#define TXGBE_TSC_LSEC_ENC_OCTET        0x1D248
+#define TXGBE_TSC_LSEC_PROT_OCTET       0x1D24C
+
+/* IpSec Registers */
+#define TXGBE_TSC_IPS_IDX               0x1D100
+#define TXGBE_TSC_IPS_IDX_WT        0x80000000U
+#define TXGBE_TSC_IPS_IDX_RD        0x40000000U
+#define TXGBE_TSC_IPS_IDX_SD_IDX    0x0U /* */
+#define TXGBE_TSC_IPS_IDX_EN        0x00000001U
+#define TXGBE_TSC_IPS_SALT              0x1D104
+#define TXGBE_TSC_IPS_KEY(i)            (0x1D108 + ((i) * 4))
+
+/* 1588 */
+#define TXGBE_TSC_1588_CTL              0x1D400 /* Tx Time Sync Control reg */
+#define TXGBE_TSC_1588_STMPL            0x1D404 /* Tx timestamp value Low */
+#define TXGBE_TSC_1588_STMPH            0x1D408 /* Tx timestamp value High */
+#define TXGBE_TSC_1588_SYSTIML          0x1D40C /* System time register Low */
+#define TXGBE_TSC_1588_SYSTIMH          0x1D410 /* System time register High */
+#define TXGBE_TSC_1588_INC              0x1D414 /* Increment attributes reg */
+#define TXGBE_TSC_1588_INC_IV(v)   (((v) & 0xFFFFFF))
+#define TXGBE_TSC_1588_INC_IP(v)   (((v) & 0xFF) << 24)
+#define TXGBE_TSC_1588_INC_IVP(v, p)  \
+				(((v) & 0xFFFFFF) | TXGBE_TSC_1588_INC_IP(p))
+
+#define TXGBE_TSC_1588_ADJL         0x1D418 /* Time Adjustment Offset reg Low */
+#define TXGBE_TSC_1588_ADJH         0x1D41C /* Time Adjustment Offset reg High*/
+/* 1588 fields */
+#define TXGBE_TSC_1588_CTL_VALID    0x00000001U /* Tx timestamp valid */
+#define TXGBE_TSC_1588_CTL_ENABLED  0x00000010U /* Tx timestamping enabled */
+
+
+/********************************* RSEC **************************************/
+/* general rsec */
+#define TXGBE_RSC_CTL                   0x17000
+#define TXGBE_RSC_ST                    0x17004
+/* general rsec fields */
+#define TXGBE_RSC_CTL_SECRX_DIS         0x00000001U
+#define TXGBE_RSC_CTL_RX_DIS            0x00000002U
+#define TXGBE_RSC_CTL_CRC_STRIP         0x00000004U
+#define TXGBE_RSC_CTL_IV_MSK_EN         0x00000008U
+#define TXGBE_RSC_CTL_SAVE_MAC_ERR      0x00000040U
+#define TXGBE_RSC_ST_RSEC_RDY           0x00000001U
+#define TXGBE_RSC_ST_RSEC_OFLD_DIS      0x00000002U
+#define TXGBE_RSC_ST_ECC_RXERR          0x00000004U
+
+/* link sec */
+#define TXGBE_RSC_LSEC_CAP              0x17200
+#define TXGBE_RSC_LSEC_CTL              0x17204
+#define TXGBE_RSC_LSEC_SCI_L            0x17208
+#define TXGBE_RSC_LSEC_SCI_H            0x1720C
+#define TXGBE_RSC_LSEC_SA0              0x17210
+#define TXGBE_RSC_LSEC_SA1              0x17214
+#define TXGBE_RSC_LSEC_PKNUM0           0x17218
+#define TXGBE_RSC_LSEC_PKNUM1           0x1721C
+#define TXGBE_RSC_LSEC_KEY0(_n)         0x17220
+#define TXGBE_RSC_LSEC_KEY1(_n)         0x17230
+#define TXGBE_RSC_LSEC_UNTAG_PKT        0x17240
+#define TXGBE_RSC_LSEC_DEC_OCTET        0x17244
+#define TXGBE_RSC_LSEC_VLD_OCTET        0x17248
+#define TXGBE_RSC_LSEC_BAD_PKT          0x1724C
+#define TXGBE_RSC_LSEC_NOSCI_PKT        0x17250
+#define TXGBE_RSC_LSEC_UNSCI_PKT        0x17254
+#define TXGBE_RSC_LSEC_UNCHK_PKT        0x17258
+#define TXGBE_RSC_LSEC_DLY_PKT          0x1725C
+#define TXGBE_RSC_LSEC_LATE_PKT         0x17260
+#define TXGBE_RSC_LSEC_OK_PKT(_n)       0x17264
+#define TXGBE_RSC_LSEC_INV_PKT(_n)      0x17274
+#define TXGBE_RSC_LSEC_BADSA_PKT        0x1727C
+#define TXGBE_RSC_LSEC_INVSA_PKT        0x17280
+
+/* ipsec */
+#define TXGBE_RSC_IPS_IDX               0x17100
+#define TXGBE_RSC_IPS_IDX_WT        0x80000000U
+#define TXGBE_RSC_IPS_IDX_RD        0x40000000U
+#define TXGBE_RSC_IPS_IDX_TB_IDX    0x0U /* */
+#define TXGBE_RSC_IPS_IDX_TB_IP     0x00000002U
+#define TXGBE_RSC_IPS_IDX_TB_SPI    0x00000004U
+#define TXGBE_RSC_IPS_IDX_TB_KEY    0x00000006U
+#define TXGBE_RSC_IPS_IDX_EN        0x00000001U
+#define TXGBE_RSC_IPS_IP(i)             (0x17104 + ((i) * 4))
+#define TXGBE_RSC_IPS_SPI               0x17114
+#define TXGBE_RSC_IPS_IP_IDX            0x17118
+#define TXGBE_RSC_IPS_KEY(i)            (0x1711C + ((i) * 4))
+#define TXGBE_RSC_IPS_SALT              0x1712C
+#define TXGBE_RSC_IPS_MODE              0x17130
+#define TXGBE_RSC_IPS_MODE_IPV6         0x00000010
+#define TXGBE_RSC_IPS_MODE_DEC          0x00000008
+#define TXGBE_RSC_IPS_MODE_ESP          0x00000004
+#define TXGBE_RSC_IPS_MODE_AH           0x00000002
+#define TXGBE_RSC_IPS_MODE_VALID        0x00000001
+
+/************************************** ETH PHY ******************************/
+#define TXGBE_XPCS_IDA_ADDR    0x13000
+#define TXGBE_XPCS_IDA_DATA    0x13004
+#define TXGBE_ETHPHY_IDA_ADDR  0x13008
+#define TXGBE_ETHPHY_IDA_DATA  0x1300C
+
+/************************************** MNG ********************************/
+#define TXGBE_MNG_FW_SM         0x1E000
+#define TXGBE_MNG_SW_SM         0x1E004
+#define TXGBE_MNG_SWFW_SYNC     0x1E008
+#define TXGBE_MNG_MBOX          0x1E100
+#define TXGBE_MNG_MBOX_CTL      0x1E044
+#define TXGBE_MNG_OS2BMC_CNT    0x1E094
+#define TXGBE_MNG_BMC2OS_CNT    0x1E090
+
+/* Firmware Semaphore Register */
+#define TXGBE_MNG_FW_SM_MODE_MASK       0xE
+#define TXGBE_MNG_FW_SM_TS_ENABLED      0x1
+/* SW Semaphore Register bitmasks */
+#define TXGBE_MNG_SW_SM_SM              0x00000001U /* software Semaphore */
+
+/* SW_FW_SYNC definitions */
+#define TXGBE_MNG_SWFW_SYNC_SW_PHY      0x0001
+#define TXGBE_MNG_SWFW_SYNC_SW_FLASH    0x0008
+#define TXGBE_MNG_SWFW_SYNC_SW_MB       0x0004
+
+#define TXGBE_MNG_MBOX_CTL_SWRDY        0x1
+#define TXGBE_MNG_MBOX_CTL_SWACK        0x2
+#define TXGBE_MNG_MBOX_CTL_FWRDY        0x4
+#define TXGBE_MNG_MBOX_CTL_FWACK        0x8
+
+/************************************* ETH MAC *****************************/
+#define TXGBE_MAC_TX_CFG                0x11000
+#define TXGBE_MAC_RX_CFG                0x11004
+#define TXGBE_MAC_PKT_FLT               0x11008
+#define TXGBE_MAC_PKT_FLT_PR            (0x1) /* promiscuous mode */
+#define TXGBE_MAC_PKT_FLT_RA            (0x80000000) /* receive all */
+#define TXGBE_MAC_WDG_TIMEOUT           0x1100C
+#define TXGBE_MAC_RX_FLOW_CTRL          0x11090
+#define TXGBE_MAC_ADDRESS0_HIGH         0x11300
+#define TXGBE_MAC_ADDRESS0_LOW          0x11304
+
+#define TXGBE_MAC_TX_CFG_TE             0x00000001U
+#define TXGBE_MAC_TX_CFG_SPEED_MASK     0x60000000U
+#define TXGBE_MAC_TX_CFG_SPEED_10G      0x00000000U
+#define TXGBE_MAC_TX_CFG_SPEED_1G       0x60000000U
+#define TXGBE_MAC_RX_CFG_RE             0x00000001U
+#define TXGBE_MAC_RX_CFG_JE             0x00000100U
+#define TXGBE_MAC_RX_CFG_LM             0x00000400U
+#define TXGBE_MAC_WDG_TIMEOUT_PWE       0x00000100U
+#define TXGBE_MAC_WDG_TIMEOUT_WTO_MASK  0x0000000FU
+#define TXGBE_MAC_WDG_TIMEOUT_WTO_DELTA 2
+
+#define TXGBE_MAC_RX_FLOW_CTRL_RFE      0x00000001U /* receive fc enable */
+#define TXGBE_MAC_RX_FLOW_CTRL_PFCE     0x00000100U /* pfc enable */
+
+#define TXGBE_MSCA                      0x11200
+#define TXGBE_MSCA_RA(v)                ((0xFFFF & (v)))
+#define TXGBE_MSCA_PA(v)                ((0x1F & (v)) << 16)
+#define TXGBE_MSCA_DA(v)                ((0x1F & (v)) << 21)
+#define TXGBE_MSCC                      0x11204
+#define TXGBE_MSCC_DATA(v)              ((0xFFFF & (v)))
+#define TXGBE_MSCC_CMD(v)               ((0x3 & (v)) << 16)
+enum TXGBE_MSCA_CMD_value {
+	TXGBE_MSCA_CMD_RSV = 0,
+	TXGBE_MSCA_CMD_WRITE,
+	TXGBE_MSCA_CMD_POST_READ,
+	TXGBE_MSCA_CMD_READ,
+};
+#define TXGBE_MSCC_SADDR                ((0x1U) << 18)
+#define TXGBE_MSCC_CR(v)                ((0x8U & (v)) << 19)
+#define TXGBE_MSCC_BUSY                 ((0x1U) << 22)
+
+/* EEE registers */
+
+/* statistic */
+#define TXGBE_MAC_LXONRXC               0x11E0C
+#define TXGBE_MAC_LXOFFRXC              0x11988
+#define TXGBE_MAC_PXONRXC(_i)           (0x11E30 + ((_i) * 4)) /* 8 of these */
+#define TXGBE_MAC_PXOFFRXC          	0x119DC
+#define TXGBE_RX_BC_FRAMES_GOOD_LOW     0x11918
+#define TXGBE_RX_CRC_ERROR_FRAMES_LOW   0x11928
+#define TXGBE_RX_LEN_ERROR_FRAMES_LOW   0x11978
+#define TXGBE_RX_UNDERSIZE_FRAMES_GOOD  0x11938
+#define TXGBE_RX_OVERSIZE_FRAMES_GOOD   0x1193C
+#define TXGBE_RX_FRAME_CNT_GOOD_BAD_LOW 0x11900
+#define TXGBE_TX_FRAME_CNT_GOOD_BAD_LOW 0x1181C
+#define TXGBE_TX_MC_FRAMES_GOOD_LOW     0x1182C
+#define TXGBE_TX_BC_FRAMES_GOOD_LOW     0x11824
+#define TXGBE_MMC_CONTROL               0x11800
+#define TXGBE_MMC_CONTROL_RSTONRD       0x4 /* reset on read */
+#define TXGBE_MMC_CONTROL_UP            0x700
+
+
+/********************************* BAR registers ***************************/
+/* Interrupt Registers */
+#define TXGBE_BME_CTL							0x12020
+#define TXGBE_PX_MISC_IC                        0x100
+#define TXGBE_PX_MISC_ICS                       0x104
+#define TXGBE_PX_MISC_IEN                       0x108
+#define TXGBE_PX_MISC_IVAR                      0x4FC
+#define TXGBE_PX_GPIE                           0x118
+#define TXGBE_PX_ISB_ADDR_L                     0x160
+#define TXGBE_PX_ISB_ADDR_H                     0x164
+#define TXGBE_PX_TCP_TIMER                      0x170
+#define TXGBE_PX_ITRSEL                         0x180
+#define TXGBE_PX_IC(_i)                         (0x120 + (_i) * 4)
+#define TXGBE_PX_ICS(_i)                        (0x130 + (_i) * 4)
+#define TXGBE_PX_IMS(_i)                        (0x140 + (_i) * 4)
+#define TXGBE_PX_IMC(_i)                        (0x150 + (_i) * 4)
+#define TXGBE_PX_IVAR(_i)                       (0x500 + (_i) * 4)
+#define TXGBE_PX_ITR(_i)                        (0x200 + (_i) * 4)
+#define TXGBE_PX_TRANSACTION_PENDING            0x168
+#define TXGBE_PX_INTA                           0x110
+
+/* Interrupt register bitmasks */
+/* Extended Interrupt Cause Read */
+#define TXGBE_PX_MISC_IC_ETH_LKDN       0x00000100U /* eth link down */
+#define TXGBE_PX_MISC_IC_DEV_RST        0x00000400U /* device reset event */
+#define TXGBE_PX_MISC_IC_TIMESYNC       0x00000800U /* time sync */
+#define TXGBE_PX_MISC_IC_STALL          0x00001000U /* trans or recv path is
+													 * stalled */
+#define TXGBE_PX_MISC_IC_LINKSEC        0x00002000U /* Tx LinkSec require key
+													 * exchange */
+#define TXGBE_PX_MISC_IC_RX_MISS        0x00004000U /* Packet Buffer Overrun */
+#define TXGBE_PX_MISC_IC_FLOW_DIR       0x00008000U /* FDir Exception */
+#define TXGBE_PX_MISC_IC_I2C            0x00010000U /* I2C interrupt */
+#define TXGBE_PX_MISC_IC_ETH_EVENT      0x00020000U /* err reported by MAC except
+													 * eth link down */
+#define TXGBE_PX_MISC_IC_ETH_LK         0x00040000U /* link up */
+#define TXGBE_PX_MISC_IC_ETH_AN         0x00080000U /* link auto-nego done */
+#define TXGBE_PX_MISC_IC_INT_ERR        0x00100000U /* integrity error */
+#define TXGBE_PX_MISC_IC_SPI            0x00200000U /* SPI interface */
+#define TXGBE_PX_MISC_IC_VF_MBOX        0x00800000U /* VF-PF message box */
+#define TXGBE_PX_MISC_IC_GPIO           0x04000000U /* GPIO interrupt */
+#define TXGBE_PX_MISC_IC_PCIE_REQ_ERR   0x08000000U /* pcie request error int */
+#define TXGBE_PX_MISC_IC_OVER_HEAT      0x10000000U /* overheat detection */
+#define TXGBE_PX_MISC_IC_PROBE_MATCH    0x20000000U /* probe match */
+#define TXGBE_PX_MISC_IC_MNG_HOST_MBOX  0x40000000U /* mng mailbox */
+#define TXGBE_PX_MISC_IC_TIMER          0x80000000U /* tcp timer */
+
+/* Extended Interrupt Cause Set */
+#define TXGBE_PX_MISC_ICS_ETH_LKDN      0x00000100U
+#define TXGBE_PX_MISC_ICS_DEV_RST       0x00000400U
+#define TXGBE_PX_MISC_ICS_TIMESYNC      0x00000800U
+#define TXGBE_PX_MISC_ICS_STALL         0x00001000U
+#define TXGBE_PX_MISC_ICS_LINKSEC       0x00002000U
+#define TXGBE_PX_MISC_ICS_RX_MISS       0x00004000U
+#define TXGBE_PX_MISC_ICS_FLOW_DIR      0x00008000U
+#define TXGBE_PX_MISC_ICS_I2C           0x00010000U
+#define TXGBE_PX_MISC_ICS_ETH_EVENT     0x00020000U
+#define TXGBE_PX_MISC_ICS_ETH_LK        0x00040000U
+#define TXGBE_PX_MISC_ICS_ETH_AN        0x00080000U
+#define TXGBE_PX_MISC_ICS_INT_ERR       0x00100000U
+#define TXGBE_PX_MISC_ICS_SPI           0x00200000U
+#define TXGBE_PX_MISC_ICS_VF_MBOX       0x00800000U
+#define TXGBE_PX_MISC_ICS_GPIO          0x04000000U
+#define TXGBE_PX_MISC_ICS_PCIE_REQ_ERR  0x08000000U
+#define TXGBE_PX_MISC_ICS_OVER_HEAT     0x10000000U
+#define TXGBE_PX_MISC_ICS_PROBE_MATCH   0x20000000U
+#define TXGBE_PX_MISC_ICS_MNG_HOST_MBOX 0x40000000U
+#define TXGBE_PX_MISC_ICS_TIMER         0x80000000U
+
+/* Extended Interrupt Enable Set */
+#define TXGBE_PX_MISC_IEN_ETH_LKDN      0x00000100U
+#define TXGBE_PX_MISC_IEN_DEV_RST       0x00000400U
+#define TXGBE_PX_MISC_IEN_TIMESYNC      0x00000800U
+#define TXGBE_PX_MISC_IEN_STALL         0x00001000U
+#define TXGBE_PX_MISC_IEN_LINKSEC       0x00002000U
+#define TXGBE_PX_MISC_IEN_RX_MISS       0x00004000U
+#define TXGBE_PX_MISC_IEN_FLOW_DIR      0x00008000U
+#define TXGBE_PX_MISC_IEN_I2C           0x00010000U
+#define TXGBE_PX_MISC_IEN_ETH_EVENT     0x00020000U
+#define TXGBE_PX_MISC_IEN_ETH_LK        0x00040000U
+#define TXGBE_PX_MISC_IEN_ETH_AN        0x00080000U
+#define TXGBE_PX_MISC_IEN_INT_ERR       0x00100000U
+#define TXGBE_PX_MISC_IEN_SPI           0x00200000U
+#define TXGBE_PX_MISC_IEN_VF_MBOX       0x00800000U
+#define TXGBE_PX_MISC_IEN_GPIO          0x04000000U
+#define TXGBE_PX_MISC_IEN_PCIE_REQ_ERR  0x08000000U
+#define TXGBE_PX_MISC_IEN_OVER_HEAT     0x10000000U
+#define TXGBE_PX_MISC_IEN_PROBE_MATCH   0x20000000U
+#define TXGBE_PX_MISC_IEN_MNG_HOST_MBOX 0x40000000U
+#define TXGBE_PX_MISC_IEN_TIMER         0x80000000U
+
+#define TXGBE_PX_MISC_IEN_MASK ( \
+				TXGBE_PX_MISC_IEN_ETH_LKDN| \
+				TXGBE_PX_MISC_IEN_DEV_RST | \
+				TXGBE_PX_MISC_IEN_ETH_EVENT | \
+				TXGBE_PX_MISC_IEN_ETH_LK | \
+				TXGBE_PX_MISC_IEN_ETH_AN | \
+				TXGBE_PX_MISC_IEN_INT_ERR | \
+				TXGBE_PX_MISC_IEN_VF_MBOX | \
+				TXGBE_PX_MISC_IEN_GPIO | \
+				TXGBE_PX_MISC_IEN_MNG_HOST_MBOX | \
+				TXGBE_PX_MISC_IEN_STALL | \
+				TXGBE_PX_MISC_IEN_PCIE_REQ_ERR | \
+				TXGBE_PX_MISC_IEN_TIMER)
+
+/* General purpose Interrupt Enable */
+#define TXGBE_PX_GPIE_MODEL             0x00000001U
+#define TXGBE_PX_GPIE_IMEN              0x00000002U
+#define TXGBE_PX_GPIE_LL_INTERVAL       0x000000F0U
+#define TXGBE_PX_GPIE_RSC_DELAY         0x00000700U
+
+/* Interrupt Vector Allocation Registers */
+#define TXGBE_PX_IVAR_REG_NUM              64
+#define TXGBE_PX_IVAR_ALLOC_VAL            0x80 /* Interrupt Allocation valid */
+
+#define TXGBE_MAX_INT_RATE              500000
+#define TXGBE_MIN_INT_RATE              980
+#define TXGBE_MAX_EITR                  0x00000FF8U
+#define TXGBE_MIN_EITR                  8
+#define TXGBE_PX_ITR_ITR_INT_MASK       0x00000FF8U
+#define TXGBE_PX_ITR_LLI_CREDIT         0x001f0000U
+#define TXGBE_PX_ITR_LLI_MOD            0x00008000U
+#define TXGBE_PX_ITR_CNT_WDIS           0x80000000U
+#define TXGBE_PX_ITR_ITR_CNT            0x0FE00000U
+
+/* transmit DMA Registers */
+#define TXGBE_PX_TR_BAL(_i)     (0x03000 + ((_i) * 0x40))
+#define TXGBE_PX_TR_BAH(_i)     (0x03004 + ((_i) * 0x40))
+#define TXGBE_PX_TR_WP(_i)      (0x03008 + ((_i) * 0x40))
+#define TXGBE_PX_TR_RP(_i)      (0x0300C + ((_i) * 0x40))
+#define TXGBE_PX_TR_CFG(_i)     (0x03010 + ((_i) * 0x40))
+/* Transmit Config masks */
+#define TXGBE_PX_TR_CFG_ENABLE          (1) /* Ena specific Tx Queue */
+#define TXGBE_PX_TR_CFG_TR_SIZE_SHIFT   1 /* tx desc number per ring */
+#define TXGBE_PX_TR_CFG_SWFLSH          (1 << 26) /* Tx Desc. wr-bk flushing */
+#define TXGBE_PX_TR_CFG_WTHRESH_SHIFT   16 /* shift to WTHRESH bits */
+#define TXGBE_PX_TR_CFG_THRE_SHIFT      8
+
+
+#define TXGBE_PX_TR_RPn(q_per_pool, vf_number, vf_q_index) \
+		(TXGBE_PX_TR_RP((q_per_pool)*(vf_number) + (vf_q_index)))
+#define TXGBE_PX_TR_WPn(q_per_pool, vf_number, vf_q_index) \
+		(TXGBE_PX_TR_WP((q_per_pool)*(vf_number) + (vf_q_index)))
+
+/* Receive DMA Registers */
+#define TXGBE_PX_RR_BAL(_i)             (0x01000 + ((_i) * 0x40))
+#define TXGBE_PX_RR_BAH(_i)             (0x01004 + ((_i) * 0x40))
+#define TXGBE_PX_RR_WP(_i)              (0x01008 + ((_i) * 0x40))
+#define TXGBE_PX_RR_RP(_i)              (0x0100C + ((_i) * 0x40))
+#define TXGBE_PX_RR_CFG(_i)             (0x01010 + ((_i) * 0x40))
+/* PX_RR_CFG bit definitions */
+#define TXGBE_PX_RR_CFG_RR_SIZE_SHIFT           1
+#define TXGBE_PX_RR_CFG_BSIZEPKT_SHIFT          2 /* so many KBs */
+#define TXGBE_PX_RR_CFG_BSIZEHDRSIZE_SHIFT      6 /* 64byte resolution (>> 6)
+						* + at bit 8 offset (<< 12)
+						*  = (<< 6)
+						*/
+#define TXGBE_PX_RR_CFG_DROP_EN         0x40000000U
+#define TXGBE_PX_RR_CFG_VLAN            0x80000000U
+#define TXGBE_PX_RR_CFG_RSC             0x20000000U
+#define TXGBE_PX_RR_CFG_CNTAG           0x10000000U
+#define TXGBE_PX_RR_CFG_RSC_CNT_MD      0x08000000U
+#define TXGBE_PX_RR_CFG_SPLIT_MODE      0x04000000U
+#define TXGBE_PX_RR_CFG_STALL           0x02000000U
+#define TXGBE_PX_RR_CFG_MAX_RSCBUF_1    0x00000000U
+#define TXGBE_PX_RR_CFG_MAX_RSCBUF_4    0x00800000U
+#define TXGBE_PX_RR_CFG_MAX_RSCBUF_8    0x01000000U
+#define TXGBE_PX_RR_CFG_MAX_RSCBUF_16   0x01800000U
+#define TXGBE_PX_RR_CFG_RR_THER         0x00070000U
+#define TXGBE_PX_RR_CFG_RR_THER_SHIFT   16
+
+#define TXGBE_PX_RR_CFG_RR_HDR_SZ       0x0000F000U
+#define TXGBE_PX_RR_CFG_RR_BUF_SZ       0x00000F00U
+#define TXGBE_PX_RR_CFG_RR_SZ           0x0000007EU
+#define TXGBE_PX_RR_CFG_RR_EN           0x00000001U
+
+/* statistic */
+#define TXGBE_PX_MPRC(_i)               (0x1020 + ((_i) * 64))
+#define TXGBE_VX_GPRC(_i)               (0x01014 + (0x40 * (_i)))
+#define TXGBE_VX_GPTC(_i)               (0x03014 + (0x40 * (_i)))
+#define TXGBE_VX_GORC_LSB(_i)           (0x01018 + (0x40 * (_i)))
+#define TXGBE_VX_GORC_MSB(_i)           (0x0101C + (0x40 * (_i)))
+#define TXGBE_VX_GOTC_LSB(_i)           (0x03018 + (0x40 * (_i)))
+#define TXGBE_VX_GOTC_MSB(_i)           (0x0301C + (0x40 * (_i)))
+#define TXGBE_VX_MPRC(_i)               (0x01020 + (0x40 * (_i)))
+
+#define TXGBE_PX_GPRC                   0x12504
+#define TXGBE_PX_GPTC                   0x18308
+
+#define TXGBE_PX_GORC_LSB               0x12508
+#define TXGBE_PX_GORC_MSB               0x1250C
+
+#define TXGBE_PX_GOTC_LSB               0x1830C
+#define TXGBE_PX_GOTC_MSB               0x18310
+
+/************************************* Stats registers ************************/
+
+
+
+#define TXGBE_FCCRC         0x15160 /* Num of Good Eth CRC w/ Bad FC CRC */
+#define TXGBE_FCOERPDC      0x12514 /* FCoE Rx Packets Dropped Count */
+#define TXGBE_FCLAST        0x12518 /* FCoE Last Error Count */
+#define TXGBE_FCOEPRC       0x15164 /* Number of FCoE Packets Received */
+#define TXGBE_FCOEDWRC      0x15168 /* Number of FCoE DWords Received */
+#define TXGBE_FCOEPTC       0x18318 /* Number of FCoE Packets Transmitted */
+#define TXGBE_FCOEDWTC      0x1831C /* Number of FCoE DWords Transmitted */
+
+
+
+
+
+/*************************** Flash region definition *************************/
+/* EEC Register */
+#define TXGBE_EEC_SK            0x00000001U /* EEPROM Clock */
+#define TXGBE_EEC_CS            0x00000002U /* EEPROM Chip Select */
+#define TXGBE_EEC_DI            0x00000004U /* EEPROM Data In */
+#define TXGBE_EEC_DO            0x00000008U /* EEPROM Data Out */
+#define TXGBE_EEC_FWE_MASK      0x00000030U /* FLASH Write Enable */
+#define TXGBE_EEC_FWE_DIS       0x00000010U /* Disable FLASH writes */
+#define TXGBE_EEC_FWE_EN        0x00000020U /* Enable FLASH writes */
+#define TXGBE_EEC_FWE_SHIFT     4
+#define TXGBE_EEC_REQ           0x00000040U /* EEPROM Access Request */
+#define TXGBE_EEC_GNT           0x00000080U /* EEPROM Access Grant */
+#define TXGBE_EEC_PRES          0x00000100U /* EEPROM Present */
+#define TXGBE_EEC_ARD           0x00000200U /* EEPROM Auto Read Done */
+#define TXGBE_EEC_FLUP          0x00800000U /* Flash update command */
+#define TXGBE_EEC_SEC1VAL       0x02000000U /* Sector 1 Valid */
+#define TXGBE_EEC_FLUDONE       0x04000000U /* Flash update done */
+/* EEPROM Addressing bits based on type (0-small, 1-large) */
+#define TXGBE_EEC_ADDR_SIZE     0x00000400U
+#define TXGBE_EEC_SIZE          0x00007800U /* EEPROM Size */
+#define TXGBE_EERD_MAX_ADDR     0x00003FFFU /* EERD alows 14 bits for addr. */
+
+#define TXGBE_EEC_SIZE_SHIFT            11
+#define TXGBE_EEPROM_WORD_SIZE_SHIFT    6
+#define TXGBE_EEPROM_OPCODE_BITS        8
+
+/* FLA Register */
+#define TXGBE_FLA_LOCKED        0x00000040U
+
+/* Part Number String Length */
+#define TXGBE_PBANUM_LENGTH     32
+
+/* Checksum and EEPROM pointers */
+#define TXGBE_PBANUM_PTR_GUARD          0xFAFA
+#define TXGBE_EEPROM_CHECKSUM           0x2F
+#define TXGBE_EEPROM_SUM                0xBABA
+#define TXGBE_ATLAS0_CONFIG_PTR         0x04
+#define TXGBE_PHY_PTR                   0x04
+#define TXGBE_ATLAS1_CONFIG_PTR         0x05
+#define TXGBE_OPTION_ROM_PTR            0x05
+#define TXGBE_PCIE_GENERAL_PTR          0x06
+#define TXGBE_PCIE_CONFIG0_PTR          0x07
+#define TXGBE_PCIE_CONFIG1_PTR          0x08
+#define TXGBE_CORE0_PTR                 0x09
+#define TXGBE_CORE1_PTR                 0x0A
+#define TXGBE_MAC0_PTR                  0x0B
+#define TXGBE_MAC1_PTR                  0x0C
+#define TXGBE_CSR0_CONFIG_PTR           0x0D
+#define TXGBE_CSR1_CONFIG_PTR           0x0E
+#define TXGBE_PCIE_ANALOG_PTR           0x02
+#define TXGBE_SHADOW_RAM_SIZE           0x4000
+#define TXGBE_TXGBE_PCIE_GENERAL_SIZE   0x24
+#define TXGBE_PCIE_CONFIG_SIZE          0x08
+#define TXGBE_EEPROM_LAST_WORD          0x800
+#define TXGBE_FW_PTR                    0x0F
+#define TXGBE_PBANUM0_PTR               0x05
+#define TXGBE_PBANUM1_PTR               0x06
+#define TXGBE_ALT_MAC_ADDR_PTR          0x37
+#define TXGBE_FREE_SPACE_PTR            0x3E
+#define TXGBE_SW_REGION_PTR             0x1C
+
+#define TXGBE_SAN_MAC_ADDR_PTR          0x18
+#define TXGBE_DEVICE_CAPS               0x1C
+#define TXGBE_EEPROM_VERSION_L          0x1D
+#define TXGBE_EEPROM_VERSION_H          0x1E
+#define TXGBE_ISCSI_BOOT_CONFIG         0x07
+
+#define TXGBE_SERIAL_NUMBER_MAC_ADDR    0x11
+#define TXGBE_MAX_MSIX_VECTORS_SAPPHIRE 0x09
+
+/* MSI-X capability fields masks */
+#define TXGBE_PCIE_MSIX_TBL_SZ_MASK     0x7FF
+
+/* Legacy EEPROM word offsets */
+#define TXGBE_ISCSI_BOOT_CAPS           0x0033
+#define TXGBE_ISCSI_SETUP_PORT_0        0x0030
+#define TXGBE_ISCSI_SETUP_PORT_1        0x0034
+
+/* EEPROM Commands - SPI */
+#define TXGBE_EEPROM_MAX_RETRY_SPI      5000 /* Max wait 5ms for RDY signal */
+#define TXGBE_EEPROM_STATUS_RDY_SPI     0x01
+#define TXGBE_EEPROM_READ_OPCODE_SPI    0x03  /* EEPROM read opcode */
+#define TXGBE_EEPROM_WRITE_OPCODE_SPI   0x02  /* EEPROM write opcode */
+#define TXGBE_EEPROM_A8_OPCODE_SPI      0x08  /* opcode bit-3 = addr bit-8 */
+#define TXGBE_EEPROM_WREN_OPCODE_SPI    0x06  /* EEPROM set Write Ena latch */
+/* EEPROM reset Write Enable latch */
+#define TXGBE_EEPROM_WRDI_OPCODE_SPI        0x04
+#define TXGBE_EEPROM_RDSR_OPCODE_SPI        0x05  /* EEPROM read Status reg */
+#define TXGBE_EEPROM_WRSR_OPCODE_SPI        0x01  /* EEPROM write Status reg */
+#define TXGBE_EEPROM_ERASE4K_OPCODE_SPI     0x20  /* EEPROM ERASE 4KB */
+#define TXGBE_EEPROM_ERASE64K_OPCODE_SPI    0xD8  /* EEPROM ERASE 64KB */
+#define TXGBE_EEPROM_ERASE256_OPCODE_SPI    0xDB  /* EEPROM ERASE 256B */
+
+/* EEPROM Read Register */
+#define TXGBE_EEPROM_RW_REG_DATA        16 /* data offset in EEPROM read reg */
+#define TXGBE_EEPROM_RW_REG_DONE        2 /* Offset to READ done bit */
+#define TXGBE_EEPROM_RW_REG_START       1 /* First bit to start operation */
+#define TXGBE_EEPROM_RW_ADDR_SHIFT      2 /* Shift to the address bits */
+#define TXGBE_NVM_POLL_WRITE            1 /* Flag for polling for wr complete */
+#define TXGBE_NVM_POLL_READ             0 /* Flag for polling for rd complete */
+
+#define NVM_INIT_CTRL_3                 0x38
+#define NVM_INIT_CTRL_3_LPLU            0x8
+#define NVM_INIT_CTRL_3_D10GMP_PORT0    0x40
+#define NVM_INIT_CTRL_3_D10GMP_PORT1    0x100
+
+#define TXGBE_ETH_LENGTH_OF_ADDRESS     6
+
+#define TXGBE_EEPROM_PAGE_SIZE_MAX      128
+#define TXGBE_EEPROM_RD_BUFFER_MAX_COUNT        256 /* words rd in burst */
+#define TXGBE_EEPROM_WR_BUFFER_MAX_COUNT        256 /* words wr in burst */
+#define TXGBE_EEPROM_CTRL_2             1 /* EEPROM CTRL word 2 */
+#define TXGBE_EEPROM_CCD_BIT            2
+
+#ifndef TXGBE_EEPROM_GRANT_ATTEMPTS
+#define TXGBE_EEPROM_GRANT_ATTEMPTS     1000 /* EEPROM attempts to gain grant */
+#endif
+
+#ifndef TXGBE_EERD_EEWR_ATTEMPTS
+/* Number of 5 microseconds we wait for EERD read and
+ * EERW write to complete */
+#define TXGBE_EERD_EEWR_ATTEMPTS        100000
+#endif
+
+#ifndef TXGBE_FLUDONE_ATTEMPTS
+/* # attempts we wait for flush update to complete */
+#define TXGBE_FLUDONE_ATTEMPTS          20000
+#endif
+
+#define TXGBE_PCIE_CTRL2                0x5   /* PCIe Control 2 Offset */
+#define TXGBE_PCIE_CTRL2_DUMMY_ENABLE   0x8   /* Dummy Function Enable */
+#define TXGBE_PCIE_CTRL2_LAN_DISABLE    0x2   /* LAN PCI Disable */
+#define TXGBE_PCIE_CTRL2_DISABLE_SELECT 0x1   /* LAN Disable Select */
+
+#define TXGBE_SAN_MAC_ADDR_PORT0_OFFSET         0x0
+#define TXGBE_SAN_MAC_ADDR_PORT1_OFFSET         0x3
+#define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP         0x1
+#define TXGBE_DEVICE_CAPS_FCOE_OFFLOADS         0x2
+#define TXGBE_FW_LESM_PARAMETERS_PTR            0x2
+#define TXGBE_FW_LESM_STATE_1                   0x1
+#define TXGBE_FW_LESM_STATE_ENABLED             0x8000 /* LESM Enable bit */
+#define TXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR   0x4
+#define TXGBE_FW_PATCH_VERSION_4                0x7
+#define TXGBE_FCOE_IBA_CAPS_BLK_PTR             0x33 /* iSCSI/FCOE block */
+#define TXGBE_FCOE_IBA_CAPS_FCOE                0x20 /* FCOE flags */
+#define TXGBE_ISCSI_FCOE_BLK_PTR                0x17 /* iSCSI/FCOE block */
+#define TXGBE_ISCSI_FCOE_FLAGS_OFFSET           0x0 /* FCOE flags */
+#define TXGBE_ISCSI_FCOE_FLAGS_ENABLE           0x1 /* FCOE flags enable bit */
+#define TXGBE_ALT_SAN_MAC_ADDR_BLK_PTR          0x17 /* Alt. SAN MAC block */
+#define TXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET      0x0 /* Alt SAN MAC capability */
+#define TXGBE_ALT_SAN_MAC_ADDR_PORT0_OFFSET     0x1 /* Alt SAN MAC 0 offset */
+#define TXGBE_ALT_SAN_MAC_ADDR_PORT1_OFFSET     0x4 /* Alt SAN MAC 1 offset */
+#define TXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET      0x7 /* Alt WWNN prefix offset */
+#define TXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET      0x8 /* Alt WWPN prefix offset */
+#define TXGBE_ALT_SAN_MAC_ADDR_CAPS_SANMAC      0x0 /* Alt SAN MAC exists */
+#define TXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN      0x1 /* Alt WWN base exists */
+#define TXGBE_DEVICE_CAPS_WOL_PORT0_1   0x4 /* WoL supported on ports 0 & 1 */
+#define TXGBE_DEVICE_CAPS_WOL_PORT0     0x8 /* WoL supported on port 0 */
+#define TXGBE_DEVICE_CAPS_WOL_MASK      0xC /* Mask for WoL capabilities */
+
+/******************************** PCI Bus Info *******************************/
+#define TXGBE_PCI_DEVICE_STATUS         0xAA
+#define TXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING     0x0020
+#define TXGBE_PCI_LINK_STATUS           0xB2
+#define TXGBE_PCI_DEVICE_CONTROL2       0xC8
+#define TXGBE_PCI_LINK_WIDTH            0x3F0
+#define TXGBE_PCI_LINK_WIDTH_1          0x10
+#define TXGBE_PCI_LINK_WIDTH_2          0x20
+#define TXGBE_PCI_LINK_WIDTH_4          0x40
+#define TXGBE_PCI_LINK_WIDTH_8          0x80
+#define TXGBE_PCI_LINK_SPEED            0xF
+#define TXGBE_PCI_LINK_SPEED_2500       0x1
+#define TXGBE_PCI_LINK_SPEED_5000       0x2
+#define TXGBE_PCI_LINK_SPEED_8000       0x3
+#define TXGBE_PCI_HEADER_TYPE_REGISTER  0x0E
+#define TXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define TXGBE_PCI_DEVICE_CONTROL2_16ms  0x0005
+
+#define TXGBE_PCIDEVCTRL2_RELAX_ORDER_OFFSET    4
+#define TXGBE_PCIDEVCTRL2_RELAX_ORDER_MASK      \
+				(0x0001 << TXGBE_PCIDEVCTRL2_RELAX_ORDER_OFFSET)
+#define TXGBE_PCIDEVCTRL2_RELAX_ORDER_ENABLE    \
+				(0x01 << TXGBE_PCIDEVCTRL2_RELAX_ORDER_OFFSET)
+
+#define TXGBE_PCIDEVCTRL2_TIMEO_MASK    0xf
+#define TXGBE_PCIDEVCTRL2_16_32ms_def   0x0
+#define TXGBE_PCIDEVCTRL2_50_100us      0x1
+#define TXGBE_PCIDEVCTRL2_1_2ms         0x2
+#define TXGBE_PCIDEVCTRL2_16_32ms       0x5
+#define TXGBE_PCIDEVCTRL2_65_130ms      0x6
+#define TXGBE_PCIDEVCTRL2_260_520ms     0x9
+#define TXGBE_PCIDEVCTRL2_1_2s          0xa
+#define TXGBE_PCIDEVCTRL2_4_8s          0xd
+#define TXGBE_PCIDEVCTRL2_17_34s        0xe
+
+
+/******************* Receive Descriptor bit definitions **********************/
+#define TXGBE_RXD_IPSEC_STATUS_SECP             0x00020000U
+#define TXGBE_RXD_IPSEC_ERROR_INVALID_PROTOCOL  0x08000000U
+#define TXGBE_RXD_IPSEC_ERROR_INVALID_LENGTH    0x10000000U
+#define TXGBE_RXD_IPSEC_ERROR_AUTH_FAILED       0x18000000U
+#define TXGBE_RXD_IPSEC_ERROR_BIT_MASK          0x18000000U
+
+#define TXGBE_RXD_NEXTP_MASK            0x000FFFF0U /* Next Descriptor Index */
+#define TXGBE_RXD_NEXTP_SHIFT           0x00000004U
+#define TXGBE_RXD_STAT_MASK             0x000fffffU /* Stat/NEXTP: bit 0-19 */
+#define TXGBE_RXD_STAT_DD               0x00000001U /* Done */
+#define TXGBE_RXD_STAT_EOP              0x00000002U /* End of Packet */
+#define TXGBE_RXD_STAT_CLASS_ID_MASK    0x0000001CU
+#define TXGBE_RXD_STAT_CLASS_ID_TC_RSS  0x00000000U
+#define TXGBE_RXD_STAT_CLASS_ID_FLM     0x00000004U /* FDir Match */
+#define TXGBE_RXD_STAT_CLASS_ID_SYN     0x00000008U
+#define TXGBE_RXD_STAT_CLASS_ID_5_TUPLE 0x0000000CU
+#define TXGBE_RXD_STAT_CLASS_ID_L2_ETYPE 0x00000010U
+#define TXGBE_RXD_STAT_VP               0x00000020U /* IEEE VLAN Pkt */
+#define TXGBE_RXD_STAT_UDPCS            0x00000040U /* UDP xsum calculated */
+#define TXGBE_RXD_STAT_L4CS             0x00000080U /* L4 xsum calculated */
+#define TXGBE_RXD_STAT_IPCS             0x00000100U /* IP xsum calculated */
+#define TXGBE_RXD_STAT_PIF              0x00000200U /* passed in-exact filter */
+#define TXGBE_RXD_STAT_OUTERIPCS        0x00000400U /* Cloud IP xsum calculated*/
+#define TXGBE_RXD_STAT_VEXT             0x00000800U /* 1st VLAN found */
+#define TXGBE_RXD_STAT_LLINT            0x00002000U /* Pkt caused Low Latency
+													 * Int */
+#define TXGBE_RXD_STAT_TS               0x00004000U /* IEEE1588 Time Stamp */
+#define TXGBE_RXD_STAT_SECP             0x00008000U /* Security Processing */
+#define TXGBE_RXD_STAT_LB               0x00010000U /* Loopback Status */
+#define TXGBE_RXD_STAT_FCEOFS           0x00020000U /* FCoE EOF/SOF Stat */
+#define TXGBE_RXD_STAT_FCSTAT           0x000C0000U /* FCoE Pkt Stat */
+#define TXGBE_RXD_STAT_FCSTAT_NOMTCH    0x00000000U /* 00: No Ctxt Match */
+#define TXGBE_RXD_STAT_FCSTAT_NODDP     0x00040000U /* 01: Ctxt w/o DDP */
+#define TXGBE_RXD_STAT_FCSTAT_FCPRSP    0x00080000U /* 10: Recv. FCP_RSP */
+#define TXGBE_RXD_STAT_FCSTAT_DDP       0x000C0000U /* 11: Ctxt w/ DDP */
+
+#define TXGBE_RXD_ERR_MASK              0xfff00000U /* RDESC.ERRORS mask */
+#define TXGBE_RXD_ERR_SHIFT             20         /* RDESC.ERRORS shift */
+#define TXGBE_RXD_ERR_FCEOFE            0x80000000U /* FCEOFe/IPE */
+#define TXGBE_RXD_ERR_FCERR             0x00700000U /* FCERR/FDIRERR */
+#define TXGBE_RXD_ERR_FDIR_LEN          0x00100000U /* FDIR Length error */
+#define TXGBE_RXD_ERR_FDIR_DROP         0x00200000U /* FDIR Drop error */
+#define TXGBE_RXD_ERR_FDIR_COLL         0x00400000U /* FDIR Collision error */
+#define TXGBE_RXD_ERR_HBO               0x00800000U /*Header Buffer Overflow */
+#define TXGBE_RXD_ERR_OUTERIPER         0x04000000U /* CRC IP Header error */
+#define TXGBE_RXD_ERR_SECERR_MASK       0x18000000U
+#define TXGBE_RXD_ERR_RXE               0x20000000U /* Any MAC Error */
+#define TXGBE_RXD_ERR_TCPE              0x40000000U /* TCP/UDP Checksum Error */
+#define TXGBE_RXD_ERR_IPE               0x80000000U /* IP Checksum Error */
+
+#define TXGBE_RXDPS_HDRSTAT_HDRSP       0x00008000U
+#define TXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FFU
+
+#define TXGBE_RXD_RSSTYPE_MASK          0x0000000FU
+#define TXGBE_RXD_TPID_MASK             0x000001C0U
+#define TXGBE_RXD_TPID_SHIFT            6
+#define TXGBE_RXD_HDRBUFLEN_MASK        0x00007FE0U
+#define TXGBE_RXD_RSCCNT_MASK           0x001E0000U
+#define TXGBE_RXD_RSCCNT_SHIFT          17
+#define TXGBE_RXD_HDRBUFLEN_SHIFT       5
+#define TXGBE_RXD_SPLITHEADER_EN        0x00001000U
+#define TXGBE_RXD_SPH                   0x8000
+
+/* RSS Hash results */
+#define TXGBE_RXD_RSSTYPE_NONE          0x00000000U
+#define TXGBE_RXD_RSSTYPE_IPV4_TCP      0x00000001U
+#define TXGBE_RXD_RSSTYPE_IPV4          0x00000002U
+#define TXGBE_RXD_RSSTYPE_IPV6_TCP      0x00000003U
+#define TXGBE_RXD_RSSTYPE_IPV4_SCTP     0x00000004U
+#define TXGBE_RXD_RSSTYPE_IPV6          0x00000005U
+#define TXGBE_RXD_RSSTYPE_IPV6_SCTP     0x00000006U
+#define TXGBE_RXD_RSSTYPE_IPV4_UDP      0x00000007U
+#define TXGBE_RXD_RSSTYPE_IPV6_UDP      0x00000008U
+
+/**
+ * receive packet type
+ * PTYPE:8 = TUN:2 + PKT:2 + TYP:4
+ **/
+/* TUN */
+#define TXGBE_PTYPE_TUN_IPV4            (0x80)
+#define TXGBE_PTYPE_TUN_IPV6            (0xC0)
+
+/* PKT for TUN */
+#define TXGBE_PTYPE_PKT_IPIP            (0x00) /* IP+IP */
+#define TXGBE_PTYPE_PKT_IG              (0x10) /* IP+GRE */
+#define TXGBE_PTYPE_PKT_IGM             (0x20) /* IP+GRE+MAC */
+#define TXGBE_PTYPE_PKT_IGMV            (0x30) /* IP+GRE+MAC+VLAN */
+/* PKT for !TUN */
+#define TXGBE_PTYPE_PKT_MAC             (0x10)
+#define TXGBE_PTYPE_PKT_IP              (0x20)
+#define TXGBE_PTYPE_PKT_FCOE            (0x30)
+
+/* TYP for PKT=mac */
+#define TXGBE_PTYPE_TYP_MAC             (0x01)
+#define TXGBE_PTYPE_TYP_TS              (0x02) /* time sync */
+#define TXGBE_PTYPE_TYP_FIP             (0x03)
+#define TXGBE_PTYPE_TYP_LLDP            (0x04)
+#define TXGBE_PTYPE_TYP_CNM             (0x05)
+#define TXGBE_PTYPE_TYP_EAPOL           (0x06)
+#define TXGBE_PTYPE_TYP_ARP             (0x07)
+/* TYP for PKT=ip */
+#define TXGBE_PTYPE_PKT_IPV6            (0x08)
+#define TXGBE_PTYPE_TYP_IPFRAG          (0x01)
+#define TXGBE_PTYPE_TYP_IP              (0x02)
+#define TXGBE_PTYPE_TYP_UDP             (0x03)
+#define TXGBE_PTYPE_TYP_TCP             (0x04)
+#define TXGBE_PTYPE_TYP_SCTP            (0x05)
+/* TYP for PKT=fcoe */
+#define TXGBE_PTYPE_PKT_VFT             (0x08)
+#define TXGBE_PTYPE_TYP_FCOE            (0x00)
+#define TXGBE_PTYPE_TYP_FCDATA          (0x01)
+#define TXGBE_PTYPE_TYP_FCRDY           (0x02)
+#define TXGBE_PTYPE_TYP_FCRSP           (0x03)
+#define TXGBE_PTYPE_TYP_FCOTHER         (0x04)
+
+/* Packet type non-ip values */
+enum txgbe_l2_ptypes {
+	TXGBE_PTYPE_L2_ABORTED = (TXGBE_PTYPE_PKT_MAC),
+	TXGBE_PTYPE_L2_MAC = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_MAC),
+	TXGBE_PTYPE_L2_TS = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_TS),
+	TXGBE_PTYPE_L2_FIP = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_FIP),
+	TXGBE_PTYPE_L2_LLDP = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_LLDP),
+	TXGBE_PTYPE_L2_CNM = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_CNM),
+	TXGBE_PTYPE_L2_EAPOL = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_EAPOL),
+	TXGBE_PTYPE_L2_ARP = (TXGBE_PTYPE_PKT_MAC | TXGBE_PTYPE_TYP_ARP),
+
+	TXGBE_PTYPE_L2_IPV4_FRAG = (TXGBE_PTYPE_PKT_IP |
+				    TXGBE_PTYPE_TYP_IPFRAG),
+	TXGBE_PTYPE_L2_IPV4 = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_TYP_IP),
+	TXGBE_PTYPE_L2_IPV4_UDP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_TYP_UDP),
+	TXGBE_PTYPE_L2_IPV4_TCP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_TYP_TCP),
+	TXGBE_PTYPE_L2_IPV4_SCTP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_TYP_SCTP),
+	TXGBE_PTYPE_L2_IPV6_FRAG = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6 |
+				    TXGBE_PTYPE_TYP_IPFRAG),
+	TXGBE_PTYPE_L2_IPV6 = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6 |
+			       TXGBE_PTYPE_TYP_IP),
+	TXGBE_PTYPE_L2_IPV6_UDP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6 |
+				   TXGBE_PTYPE_TYP_UDP),
+	TXGBE_PTYPE_L2_IPV6_TCP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6 |
+				   TXGBE_PTYPE_TYP_TCP),
+	TXGBE_PTYPE_L2_IPV6_SCTP = (TXGBE_PTYPE_PKT_IP | TXGBE_PTYPE_PKT_IPV6 |
+				    TXGBE_PTYPE_TYP_SCTP),
+
+	TXGBE_PTYPE_L2_FCOE = (TXGBE_PTYPE_PKT_FCOE | TXGBE_PTYPE_TYP_FCOE),
+	TXGBE_PTYPE_L2_FCOE_FCDATA = (TXGBE_PTYPE_PKT_FCOE |
+				      TXGBE_PTYPE_TYP_FCDATA),
+	TXGBE_PTYPE_L2_FCOE_FCRDY = (TXGBE_PTYPE_PKT_FCOE |
+				     TXGBE_PTYPE_TYP_FCRDY),
+	TXGBE_PTYPE_L2_FCOE_FCRSP = (TXGBE_PTYPE_PKT_FCOE |
+				     TXGBE_PTYPE_TYP_FCRSP),
+	TXGBE_PTYPE_L2_FCOE_FCOTHER = (TXGBE_PTYPE_PKT_FCOE |
+				       TXGBE_PTYPE_TYP_FCOTHER),
+	TXGBE_PTYPE_L2_FCOE_VFT = (TXGBE_PTYPE_PKT_FCOE | TXGBE_PTYPE_PKT_VFT),
+	TXGBE_PTYPE_L2_FCOE_VFT_FCDATA = (TXGBE_PTYPE_PKT_FCOE |
+				TXGBE_PTYPE_PKT_VFT | TXGBE_PTYPE_TYP_FCDATA),
+	TXGBE_PTYPE_L2_FCOE_VFT_FCRDY = (TXGBE_PTYPE_PKT_FCOE |
+				TXGBE_PTYPE_PKT_VFT | TXGBE_PTYPE_TYP_FCRDY),
+	TXGBE_PTYPE_L2_FCOE_VFT_FCRSP = (TXGBE_PTYPE_PKT_FCOE |
+				TXGBE_PTYPE_PKT_VFT | TXGBE_PTYPE_TYP_FCRSP),
+	TXGBE_PTYPE_L2_FCOE_VFT_FCOTHER = (TXGBE_PTYPE_PKT_FCOE |
+				TXGBE_PTYPE_PKT_VFT | TXGBE_PTYPE_TYP_FCOTHER),
+
+	TXGBE_PTYPE_L2_TUN4_MAC = (TXGBE_PTYPE_TUN_IPV4 | TXGBE_PTYPE_PKT_IGM),
+	TXGBE_PTYPE_L2_TUN6_MAC = (TXGBE_PTYPE_TUN_IPV6 | TXGBE_PTYPE_PKT_IGM),
+};
+
+#define TXGBE_RXD_PKTTYPE(_rxd) \
+	((le32_to_cpu((_rxd)->wb.lower.lo_dword.data) >> 9) & 0xFF)
+#define TXGBE_PTYPE_TUN(_pt) ((_pt) & 0xC0)
+#define TXGBE_PTYPE_PKT(_pt) ((_pt) & 0x30)
+#define TXGBE_PTYPE_TYP(_pt) ((_pt) & 0x0F)
+#define TXGBE_PTYPE_TYPL4(_pt) ((_pt) & 0x07)
+
+#define TXGBE_RXD_IPV6EX(_rxd) \
+	((le32_to_cpu((_rxd)->wb.lower.lo_dword.data) >> 6) & 0x1)
+
+/* Security Processing bit Indication */
+#define TXGBE_RXD_LNKSEC_STATUS_SECP            0x00020000U
+#define TXGBE_RXD_LNKSEC_ERROR_NO_SA_MATCH      0x08000000U
+#define TXGBE_RXD_LNKSEC_ERROR_REPLAY_ERROR     0x10000000U
+#define TXGBE_RXD_LNKSEC_ERROR_BIT_MASK         0x18000000U
+#define TXGBE_RXD_LNKSEC_ERROR_BAD_SIG          0x18000000U
+
+/* Masks to determine if packets should be dropped due to frame errors */
+#define TXGBE_RXD_ERR_FRAME_ERR_MASK    TXGBE_RXD_ERR_RXE
+
+/*********************** Adv Transmit Descriptor Config Masks ****************/
+#define TXGBE_TXD_DTALEN_MASK           0x0000FFFFU /* Data buf length(bytes) */
+#define TXGBE_TXD_MAC_LINKSEC           0x00040000U /* Insert LinkSec */
+#define TXGBE_TXD_MAC_TSTAMP            0x00080000U /* IEEE1588 time stamp */
+#define TXGBE_TXD_IPSEC_SA_INDEX_MASK   0x000003FFU /* IPSec SA index */
+#define TXGBE_TXD_IPSEC_ESP_LEN_MASK    0x000001FFU /* IPSec ESP length */
+#define TXGBE_TXD_DTYP_MASK             0x00F00000U /* DTYP mask */
+#define TXGBE_TXD_DTYP_CTXT             0x00100000U /* Adv Context Desc */
+#define TXGBE_TXD_DTYP_DATA             0x00000000U /* Adv Data Descriptor */
+#define TXGBE_TXD_EOP                   0x01000000U  /* End of Packet */
+#define TXGBE_TXD_IFCS                  0x02000000U /* Insert FCS */
+#define TXGBE_TXD_LINKSEC               0x04000000U /* enable linksec */
+#define TXGBE_TXD_RS                    0x08000000U /* Report Status */
+#define TXGBE_TXD_ECU                   0x10000000U /* DDP hdr type or iSCSI */
+#define TXGBE_TXD_QCN                   0x20000000U /* cntag insertion enable */
+#define TXGBE_TXD_VLE                   0x40000000U /* VLAN pkt enable */
+#define TXGBE_TXD_TSE                   0x80000000U /* TCP Seg enable */
+#define TXGBE_TXD_STAT_DD               0x00000001U /* Descriptor Done */
+#define TXGBE_TXD_IDX_SHIFT             4 /* Adv desc Index shift */
+#define TXGBE_TXD_CC                    0x00000080U /* Check Context */
+#define TXGBE_TXD_IPSEC                 0x00000100U /* enable ipsec esp */
+#define TXGBE_TXD_IIPCS                 0x00000400U
+#define TXGBE_TXD_EIPCS                 0x00000800U
+#define TXGBE_TXD_L4CS                  0x00000200U
+#define TXGBE_TXD_PAYLEN_SHIFT          13 /* Adv desc PAYLEN shift */
+#define TXGBE_TXD_MACLEN_SHIFT          9  /* Adv ctxt desc mac len shift */
+#define TXGBE_TXD_VLAN_SHIFT            16  /* Adv ctxt vlan tag shift */
+#define TXGBE_TXD_TAG_TPID_SEL_SHIFT    11
+#define TXGBE_TXD_IPSEC_TYPE_SHIFT      14
+#define TXGBE_TXD_ENC_SHIFT             15
+
+#define TXGBE_TXD_TUCMD_IPSEC_TYPE_ESP  0x00004000U /* IPSec Type ESP */
+#define TXGBE_TXD_TUCMD_IPSEC_ENCRYPT_EN 0x00008000/* ESP Encrypt Enable */
+#define TXGBE_TXD_TUCMD_FCOE            0x00010000U /* FCoE Frame Type */
+#define TXGBE_TXD_FCOEF_EOF_MASK        (0x3 << 10) /* FC EOF index */
+#define TXGBE_TXD_FCOEF_SOF             ((1 << 2) << 10) /* FC SOF index */
+#define TXGBE_TXD_FCOEF_PARINC          ((1 << 3) << 10) /* Rel_Off in F_CTL */
+#define TXGBE_TXD_FCOEF_ORIE            ((1 << 4) << 10) /* Orientation End */
+#define TXGBE_TXD_FCOEF_ORIS            ((1 << 5) << 10) /* Orientation Start */
+#define TXGBE_TXD_FCOEF_EOF_N           (0x0 << 10) /* 00: EOFn */
+#define TXGBE_TXD_FCOEF_EOF_T           (0x1 << 10) /* 01: EOFt */
+#define TXGBE_TXD_FCOEF_EOF_NI          (0x2 << 10) /* 10: EOFni */
+#define TXGBE_TXD_FCOEF_EOF_A           (0x3 << 10) /* 11: EOFa */
+#define TXGBE_TXD_L4LEN_SHIFT           8  /* Adv ctxt L4LEN shift */
+#define TXGBE_TXD_MSS_SHIFT             16  /* Adv ctxt MSS shift */
+
+#define TXGBE_TXD_OUTER_IPLEN_SHIFT     12 /* Adv ctxt OUTERIPLEN shift */
+#define TXGBE_TXD_TUNNEL_LEN_SHIFT      21 /* Adv ctxt TUNNELLEN shift */
+#define TXGBE_TXD_TUNNEL_TYPE_SHIFT     11 /* Adv Tx Desc Tunnel Type shift */
+#define TXGBE_TXD_TUNNEL_DECTTL_SHIFT   27 /* Adv ctxt DECTTL shift */
+#define TXGBE_TXD_TUNNEL_UDP            (0x0ULL << TXGBE_TXD_TUNNEL_TYPE_SHIFT)
+#define TXGBE_TXD_TUNNEL_GRE            (0x1ULL << TXGBE_TXD_TUNNEL_TYPE_SHIFT)
+
+
+/************ txgbe_type.h ************/
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define TXGBE_REQ_TX_DESCRIPTOR_MULTIPLE        8
+#define TXGBE_REQ_RX_DESCRIPTOR_MULTIPLE        8
+#define TXGBE_REQ_TX_BUFFER_GRANULARITY         1024
+
+/* Vlan-specific macros */
+#define TXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */
+#define TXGBE_RX_DESC_SPECIAL_PRI_MASK  0xE000 /* Priority in upper 3 bits */
+#define TXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */
+#define TXGBE_TX_DESC_SPECIAL_PRI_SHIFT TXGBE_RX_DESC_SPECIAL_PRI_SHIFT
+
+/* Transmit Descriptor */
+union txgbe_tx_desc {
+	struct {
+		__le64 buffer_addr; /* Address of descriptor's data buf */
+		__le32 cmd_type_len;
+		__le32 olinfo_status;
+	} read;
+	struct {
+		__le64 rsvd; /* Reserved */
+		__le32 nxtseq_seed;
+		__le32 status;
+	} wb;
+};
+
+/* Receive Descriptor */
+union txgbe_rx_desc {
+	struct {
+		__le64 pkt_addr; /* Packet buffer address */
+		__le64 hdr_addr; /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			union {
+				__le32 data;
+				struct {
+					__le16 pkt_info; /* RSS, Pkt type */
+					__le16 hdr_info; /* Splithdr, hdrlen */
+				} hs_rss;
+			} lo_dword;
+			union {
+				__le32 rss; /* RSS Hash */
+				struct {
+					__le16 ip_id; /* IP id */
+					__le16 csum; /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			__le32 status_error; /* ext status/error */
+			__le16 length; /* Packet length */
+			__le16 vlan; /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+/* Context descriptors */
+struct txgbe_tx_context_desc {
+	__le32 vlan_macip_lens;
+	__le32 seqnum_seed;
+	__le32 type_tucmd_mlhl;
+	__le32 mss_l4len_idx;
+};
+
+/************************* Flow Directory HASH *******************************/
+/* Software ATR hash keys */
+#define TXGBE_ATR_BUCKET_HASH_KEY       0x3DAD14E2
+#define TXGBE_ATR_SIGNATURE_HASH_KEY    0x174D3614
+
+/* Software ATR input stream values and masks */
+#define TXGBE_ATR_HASH_MASK             0x7fff
+#define TXGBE_ATR_L4TYPE_MASK           0x3
+#define TXGBE_ATR_L4TYPE_UDP            0x1
+#define TXGBE_ATR_L4TYPE_TCP            0x2
+#define TXGBE_ATR_L4TYPE_SCTP           0x3
+#define TXGBE_ATR_L4TYPE_IPV6_MASK      0x4
+#define TXGBE_ATR_L4TYPE_TUNNEL_MASK    0x10
+enum txgbe_atr_flow_type {
+	TXGBE_ATR_FLOW_TYPE_IPV4        = 0x0,
+	TXGBE_ATR_FLOW_TYPE_UDPV4       = 0x1,
+	TXGBE_ATR_FLOW_TYPE_TCPV4       = 0x2,
+	TXGBE_ATR_FLOW_TYPE_SCTPV4      = 0x3,
+	TXGBE_ATR_FLOW_TYPE_IPV6        = 0x4,
+	TXGBE_ATR_FLOW_TYPE_UDPV6       = 0x5,
+	TXGBE_ATR_FLOW_TYPE_TCPV6       = 0x6,
+	TXGBE_ATR_FLOW_TYPE_SCTPV6      = 0x7,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_IPV4       = 0x10,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_UDPV4      = 0x11,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_TCPV4      = 0x12,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_SCTPV4     = 0x13,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_IPV6       = 0x14,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_UDPV6      = 0x15,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_TCPV6      = 0x16,
+	TXGBE_ATR_FLOW_TYPE_TUNNELED_SCTPV6     = 0x17,
+};
+
+/* Flow Director ATR input struct. */
+union txgbe_atr_input {
+	/*
+	 * Byte layout in order, all values with MSB first:
+	 *
+	 * vm_pool      - 1 byte
+	 * flow_type    - 1 byte
+	 * vlan_id      - 2 bytes
+	 * src_ip       - 16 bytes
+	 * inner_mac    - 6 bytes
+	 * cloud_mode   - 2 bytes
+	 * tni_vni      - 4 bytes
+	 * dst_ip       - 16 bytes
+	 * src_port     - 2 bytes
+	 * dst_port     - 2 bytes
+	 * flex_bytes   - 2 bytes
+	 * bkt_hash     - 2 bytes
+	 */
+	struct {
+		u8 vm_pool;
+		u8 flow_type;
+		__be16 vlan_id;
+		__be32 dst_ip[4];
+		__be32 src_ip[4];
+		__be16 src_port;
+		__be16 dst_port;
+		__be16 flex_bytes;
+		__be16 bkt_hash;
+	} formatted;
+	__be32 dword_stream[11];
+};
+
+/* Flow Director compressed ATR hash input struct */
+union txgbe_atr_hash_dword {
+	struct {
+		u8 vm_pool;
+		u8 flow_type;
+		__be16 vlan_id;
+	} formatted;
+	__be32 ip;
+	struct {
+		__be16 src;
+		__be16 dst;
+	} port;
+	__be16 flex_bytes;
+	__be32 dword;
+};
+
+
+/****************** Manageablility Host Interface defines ********************/
+#define TXGBE_HI_MAX_BLOCK_BYTE_LENGTH  256 /* Num of bytes in range */
+#define TXGBE_HI_MAX_BLOCK_DWORD_LENGTH 64 /* Num of dwords in range */
+#define TXGBE_HI_COMMAND_TIMEOUT        5000 /* Process HI command limit */
+#define TXGBE_HI_FLASH_ERASE_TIMEOUT    5000 /* Process Erase command limit */
+#define TXGBE_HI_FLASH_UPDATE_TIMEOUT   5000 /* Process Update command limit */
+#define TXGBE_HI_FLASH_VERIFY_TIMEOUT   60000 /* Process Apply command limit */
+#define TXGBE_HI_PHY_MGMT_REQ_TIMEOUT   2000 /* Wait up to 2 seconds */
+
+/* CEM Support */
+#define FW_CEM_HDR_LEN                  0x4
+#define FW_CEM_CMD_DRIVER_INFO          0xDD
+#define FW_CEM_CMD_DRIVER_INFO_LEN      0x5
+#define FW_CEM_CMD_RESERVED             0X0
+#define FW_CEM_UNUSED_VER               0x0
+#define FW_CEM_MAX_RETRIES              3
+#define FW_CEM_RESP_STATUS_SUCCESS      0x1
+#define FW_READ_SHADOW_RAM_CMD          0x31
+#define FW_READ_SHADOW_RAM_LEN          0x6
+#define FW_WRITE_SHADOW_RAM_CMD         0x33
+#define FW_WRITE_SHADOW_RAM_LEN         0xA /* 8 plus 1 WORD to write */
+#define FW_SHADOW_RAM_DUMP_CMD          0x36
+#define FW_SHADOW_RAM_DUMP_LEN          0
+#define FW_DEFAULT_CHECKSUM             0xFF /* checksum always 0xFF */
+#define FW_NVM_DATA_OFFSET              3
+#define FW_MAX_READ_BUFFER_SIZE         244
+#define FW_DISABLE_RXEN_CMD             0xDE
+#define FW_DISABLE_RXEN_LEN             0x1
+#define FW_PHY_MGMT_REQ_CMD             0x20
+#define FW_RESET_CMD                    0xDF
+#define FW_RESET_LEN                    0x2
+#define FW_SETUP_MAC_LINK_CMD           0xE0
+#define FW_SETUP_MAC_LINK_LEN           0x2
+#define FW_FLASH_UPGRADE_START_CMD      0xE3
+#define FW_FLASH_UPGRADE_START_LEN      0x1
+#define FW_FLASH_UPGRADE_WRITE_CMD      0xE4
+#define FW_FLASH_UPGRADE_VERIFY_CMD     0xE5
+#define FW_FLASH_UPGRADE_VERIFY_LEN     0x4
+#define FW_DW_OPEN_NOTIFY               0xE9
+#define FW_DW_CLOSE_NOTIFY              0xEA
+
+#define TXGBE_CHECKSUM_CAP_ST_PASS      0x80658383
+#define TXGBE_CHECKSUM_CAP_ST_FAIL      0x70657376
+
+/* Host Interface Command Structures */
+struct txgbe_hic_hdr {
+	u8 cmd;
+	u8 buf_len;
+	union {
+		u8 cmd_resv;
+		u8 ret_status;
+	} cmd_or_resp;
+	u8 checksum;
+};
+
+struct txgbe_hic_hdr2_req {
+	u8 cmd;
+	u8 buf_lenh;
+	u8 buf_lenl;
+	u8 checksum;
+};
+
+struct txgbe_hic_hdr2_rsp {
+	u8 cmd;
+	u8 buf_lenl;
+	u8 buf_lenh_status;     /* 7-5: high bits of buf_len, 4-0: status */
+	u8 checksum;
+};
+
+union txgbe_hic_hdr2 {
+	struct txgbe_hic_hdr2_req req;
+	struct txgbe_hic_hdr2_rsp rsp;
+};
+
+struct txgbe_hic_drv_info {
+	struct txgbe_hic_hdr hdr;
+	u8 port_num;
+	u8 ver_sub;
+	u8 ver_build;
+	u8 ver_min;
+	u8 ver_maj;
+	u8 pad; /* end spacing to ensure length is mult. of dword */
+	u16 pad2; /* end spacing to ensure length is mult. of dword2 */
+};
+
+/* These need to be dword aligned */
+struct txgbe_hic_read_shadow_ram {
+	union txgbe_hic_hdr2 hdr;
+	u32 address;
+	u16 length;
+	u16 pad2;
+	u16 data;
+	u16 pad3;
+};
+
+struct txgbe_hic_write_shadow_ram {
+	union txgbe_hic_hdr2 hdr;
+	u32 address;
+	u16 length;
+	u16 pad2;
+	u16 data;
+	u16 pad3;
+};
+
+struct txgbe_hic_disable_rxen {
+	struct txgbe_hic_hdr hdr;
+	u8  port_number;
+	u8  pad2;
+	u16 pad3;
+};
+
+struct txgbe_hic_reset {
+	struct txgbe_hic_hdr hdr;
+	u16 lan_id;
+	u16 reset_type;
+};
+
+struct txgbe_hic_phy_cfg {
+	struct txgbe_hic_hdr hdr;
+	u8 lan_id;
+	u8 phy_mode;
+	u16 phy_speed;
+};
+
+enum txgbe_module_id {
+	TXGBE_MODULE_EEPROM = 0,
+	TXGBE_MODULE_FIRMWARE,
+	TXGBE_MODULE_HARDWARE,
+	TXGBE_MODULE_PCIE
+};
+
+struct txgbe_hic_upg_start {
+	struct txgbe_hic_hdr hdr;
+	u8 module_id;
+	u8  pad2;
+	u16 pad3;
+};
+
+struct txgbe_hic_upg_write {
+	struct txgbe_hic_hdr hdr;
+	u8 data_len;
+	u8 eof_flag;
+	u16 check_sum;
+	u32 data[62];
+};
+
+enum txgbe_upg_flag {
+	TXGBE_RESET_NONE = 0,
+	TXGBE_RESET_FIRMWARE,
+	TXGBE_RELOAD_EEPROM,
+	TXGBE_RESET_LAN
+};
+
+struct txgbe_hic_upg_verify {
+	struct txgbe_hic_hdr hdr;
+	u32 action_flag;
+};
+
+struct txgbe_hic_write_lldp{
+	struct txgbe_hic_hdr hdr;
+	u8 func;
+	u8 pad2;
+	u16 pad3;
+};
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define TXGBE_PCI_MASTER_DISABLE_TIMEOUT        800
+
+/* Check whether address is multicast. This is little-endian specific check.*/
+#define TXGBE_IS_MULTICAST(Address) \
+		(bool)(((u8 *)(Address))[0] & ((u8)0x01))
+
+/* Check whether an address is broadcast. */
+#define TXGBE_IS_BROADCAST(Address) \
+		((((u8 *)(Address))[0] == ((u8)0xff)) && \
+		(((u8 *)(Address))[1] == ((u8)0xff)))
+
+/* DCB registers */
+#define TXGBE_DCB_MAX_TRAFFIC_CLASS     8
+
+/* Power Management */
+/* DMA Coalescing configuration */
+struct txgbe_dmac_config {
+	u16     watchdog_timer; /* usec units */
+	bool    fcoe_en;
+	u32     link_speed;
+	u8      fcoe_tc;
+	u8      num_tcs;
+};
+
+/* Autonegotiation advertised speeds */
+typedef u32 txgbe_autoneg_advertised;
+/* Link speed */
+#define TXGBE_LINK_SPEED_UNKNOWN        0
+#define TXGBE_LINK_SPEED_100_FULL       1
+#define TXGBE_LINK_SPEED_1GB_FULL       2
+#define TXGBE_LINK_SPEED_10GB_FULL      4
+#define TXGBE_LINK_SPEED_10_FULL        8
+#define TXGBE_LINK_SPEED_AUTONEG  (TXGBE_LINK_SPEED_100_FULL | \
+				   TXGBE_LINK_SPEED_1GB_FULL | \
+				   TXGBE_LINK_SPEED_10GB_FULL | \
+				   TXGBE_LINK_SPEED_10_FULL)
+
+/* Physical layer type */
+typedef u32 txgbe_physical_layer;
+#define TXGBE_PHYSICAL_LAYER_UNKNOWN            0
+#define TXGBE_PHYSICAL_LAYER_10GBASE_T          0x0001
+#define TXGBE_PHYSICAL_LAYER_1000BASE_T         0x0002
+#define TXGBE_PHYSICAL_LAYER_100BASE_TX         0x0004
+#define TXGBE_PHYSICAL_LAYER_SFP_PLUS_CU        0x0008
+#define TXGBE_PHYSICAL_LAYER_10GBASE_LR         0x0010
+#define TXGBE_PHYSICAL_LAYER_10GBASE_LRM        0x0020
+#define TXGBE_PHYSICAL_LAYER_10GBASE_SR         0x0040
+#define TXGBE_PHYSICAL_LAYER_10GBASE_KX4        0x0080
+#define TXGBE_PHYSICAL_LAYER_1000BASE_KX        0x0200
+#define TXGBE_PHYSICAL_LAYER_1000BASE_BX        0x0400
+#define TXGBE_PHYSICAL_LAYER_10GBASE_KR         0x0800
+#define TXGBE_PHYSICAL_LAYER_10GBASE_XAUI       0x1000
+#define TXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA      0x2000
+#define TXGBE_PHYSICAL_LAYER_1000BASE_SX        0x4000
+
+
+/* Special PHY Init Routine */
+#define TXGBE_PHY_INIT_OFFSET_NL        0x002B
+#define TXGBE_PHY_INIT_END_NL           0xFFFF
+#define TXGBE_CONTROL_MASK_NL           0xF000
+#define TXGBE_DATA_MASK_NL              0x0FFF
+#define TXGBE_CONTROL_SHIFT_NL          12
+#define TXGBE_DELAY_NL                  0
+#define TXGBE_DATA_NL                   1
+#define TXGBE_CONTROL_NL                0x000F
+#define TXGBE_CONTROL_EOL_NL            0x0FFF
+#define TXGBE_CONTROL_SOL_NL            0x0000
+
+
+
+/* Flow Control Data Sheet defined values
+ * Calculation and defines taken from 802.1bb Annex O
+ */
+
+/* BitTimes (BT) conversion */
+#define TXGBE_BT2KB(BT)         ((BT + (8 * 1024 - 1)) / (8 * 1024))
+#define TXGBE_B2BT(BT)          (BT * 8)
+
+/* Calculate Delay to respond to PFC */
+#define TXGBE_PFC_D     672
+
+/* Calculate Cable Delay */
+#define TXGBE_CABLE_DC  5556 /* Delay Copper */
+#define TXGBE_CABLE_DO  5000 /* Delay Optical */
+
+/* Calculate Interface Delay X540 */
+#define TXGBE_PHY_DC    25600 /* Delay 10G BASET */
+#define TXGBE_MAC_DC    8192  /* Delay Copper XAUI interface */
+#define TXGBE_XAUI_DC   (2 * 2048) /* Delay Copper Phy */
+
+#define TXGBE_ID_X540   (TXGBE_MAC_DC + TXGBE_XAUI_DC + TXGBE_PHY_DC)
+
+/* Calculate Interface Delay */
+#define TXGBE_PHY_D     12800
+#define TXGBE_MAC_D     4096
+#define TXGBE_XAUI_D    (2 * 1024)
+
+#define TXGBE_ID        (TXGBE_MAC_D + TXGBE_XAUI_D + TXGBE_PHY_D)
+
+/* Calculate Delay incurred from higher layer */
+#define TXGBE_HD        6144
+
+/* Calculate PCI Bus delay for low thresholds */
+#define TXGBE_PCI_DELAY 10000
+
+/* Calculate X540 delay value in bit times */
+#define TXGBE_DV_X540(_max_frame_link, _max_frame_tc) \
+			((36 * \
+			  (TXGBE_B2BT(_max_frame_link) + \
+			   TXGBE_PFC_D + \
+			   (2 * TXGBE_CABLE_DC) + \
+			   (2 * TXGBE_ID_X540) + \
+			   TXGBE_HD) / 25 + 1) + \
+			 2 * TXGBE_B2BT(_max_frame_tc))
+
+
+/* Calculate delay value in bit times */
+#define TXGBE_DV(_max_frame_link, _max_frame_tc) \
+			((36 * \
+			  (TXGBE_B2BT(_max_frame_link) + \
+			   TXGBE_PFC_D + \
+			   (2 * TXGBE_CABLE_DC) + \
+			   (2 * TXGBE_ID) + \
+			   TXGBE_HD) / 25 + 1) + \
+			 2 * TXGBE_B2BT(_max_frame_tc))
+
+/* Calculate low threshold delay values */
+#define TXGBE_LOW_DV_X540(_max_frame_tc) \
+			(2 * TXGBE_B2BT(_max_frame_tc) + \
+			(36 * TXGBE_PCI_DELAY / 25) + 1)
+
+#define TXGBE_LOW_DV(_max_frame_tc) \
+			(2 * TXGBE_LOW_DV_X540(_max_frame_tc))
+
+
+/*
+ * Unavailable: The FCoE Boot Option ROM is not present in the flash.
+ * Disabled: Present; boot order is not set for any targets on the port.
+ * Enabled: Present; boot order is set for at least one target on the port.
+ */
+enum txgbe_fcoe_boot_status {
+	txgbe_fcoe_bootstatus_disabled = 0,
+	txgbe_fcoe_bootstatus_enabled = 1,
+	txgbe_fcoe_bootstatus_unavailable = 0xFFFF
+};
+
+enum txgbe_eeprom_type {
+	txgbe_eeprom_uninitialized = 0,
+	txgbe_eeprom_spi,
+	txgbe_flash,
+	txgbe_eeprom_none /* No NVM support */
+};
+
+enum txgbe_phy_type {
+	txgbe_phy_unknown = 0,
+	txgbe_phy_none,
+	txgbe_phy_tn,
+	txgbe_phy_aq,
+	txgbe_phy_cu_unknown,
+	txgbe_phy_qt,
+	txgbe_phy_xaui,
+	txgbe_phy_nl,
+	txgbe_phy_sfp_passive_tyco,
+	txgbe_phy_sfp_passive_unknown,
+	txgbe_phy_sfp_active_unknown,
+	txgbe_phy_sfp_avago,
+	txgbe_phy_sfp_ftl,
+	txgbe_phy_sfp_ftl_active,
+	txgbe_phy_sfp_unknown,
+	txgbe_phy_sfp_intel,
+	txgbe_phy_sfp_unsupported, /*Enforce bit set with unsupported module*/
+	txgbe_phy_generic
+};
+
+/*
+ * SFP+ module type IDs:
+ *
+ * ID   Module Type
+ * =============
+ * 0    SFP_DA_CU
+ * 1    SFP_SR
+ * 2    SFP_LR
+ * 3    SFP_DA_CU_CORE0
+ * 4    SFP_DA_CU_CORE1
+ * 5    SFP_SR/LR_CORE0
+ * 6    SFP_SR/LR_CORE1
+ */
+enum txgbe_sfp_type {
+	txgbe_sfp_type_da_cu = 0,
+	txgbe_sfp_type_sr = 1,
+	txgbe_sfp_type_lr = 2,
+	txgbe_sfp_type_da_cu_core0 = 3,
+	txgbe_sfp_type_da_cu_core1 = 4,
+	txgbe_sfp_type_srlr_core0 = 5,
+	txgbe_sfp_type_srlr_core1 = 6,
+	txgbe_sfp_type_da_act_lmt_core0 = 7,
+	txgbe_sfp_type_da_act_lmt_core1 = 8,
+	txgbe_sfp_type_1g_cu_core0 = 9,
+	txgbe_sfp_type_1g_cu_core1 = 10,
+	txgbe_sfp_type_1g_sx_core0 = 11,
+	txgbe_sfp_type_1g_sx_core1 = 12,
+	txgbe_sfp_type_1g_lx_core0 = 13,
+	txgbe_sfp_type_1g_lx_core1 = 14,
+	txgbe_sfp_type_not_present = 0xFFFE,
+	txgbe_sfp_type_unknown = 0xFFFF
+};
+
+enum txgbe_media_type {
+	txgbe_media_type_unknown = 0,
+	txgbe_media_type_fiber,
+	txgbe_media_type_copper,
+	txgbe_media_type_backplane,
+	txgbe_media_type_virtual
+};
+
+/* Flow Control Settings */
+enum txgbe_fc_mode {
+	txgbe_fc_none = 0,
+	txgbe_fc_rx_pause,
+	txgbe_fc_tx_pause,
+	txgbe_fc_full,
+	txgbe_fc_default
+};
+
+/* Smart Speed Settings */
+#define TXGBE_SMARTSPEED_MAX_RETRIES    3
+enum txgbe_smart_speed {
+	txgbe_smart_speed_auto = 0,
+	txgbe_smart_speed_on,
+	txgbe_smart_speed_off
+};
+
+/* PCI bus types */
+enum txgbe_bus_type {
+	txgbe_bus_type_unknown = 0,
+	txgbe_bus_type_pci,
+	txgbe_bus_type_pcix,
+	txgbe_bus_type_pci_express,
+	txgbe_bus_type_internal,
+	txgbe_bus_type_reserved
+};
+
+/* PCI bus speeds */
+enum txgbe_bus_speed {
+	txgbe_bus_speed_unknown	= 0,
+	txgbe_bus_speed_33	= 33,
+	txgbe_bus_speed_66	= 66,
+	txgbe_bus_speed_100	= 100,
+	txgbe_bus_speed_120	= 120,
+	txgbe_bus_speed_133	= 133,
+	txgbe_bus_speed_2500	= 2500,
+	txgbe_bus_speed_5000	= 5000,
+	txgbe_bus_speed_8000	= 8000,
+	txgbe_bus_speed_reserved
+};
+
+/* PCI bus widths */
+enum txgbe_bus_width {
+	txgbe_bus_width_unknown	= 0,
+	txgbe_bus_width_pcie_x1	= 1,
+	txgbe_bus_width_pcie_x2	= 2,
+	txgbe_bus_width_pcie_x4	= 4,
+	txgbe_bus_width_pcie_x8	= 8,
+	txgbe_bus_width_32	= 32,
+	txgbe_bus_width_64	= 64,
+	txgbe_bus_width_reserved
+};
+
+struct txgbe_addr_filter_info {
+	u32 num_mc_addrs;
+	u32 rar_used_count;
+	u32 mta_in_use;
+	u32 overflow_promisc;
+	bool user_set_promisc;
+};
+
+/* Bus parameters */
+struct txgbe_bus_info {
+	enum pci_bus_speed speed;
+	enum pcie_link_width width;
+	enum txgbe_bus_type type;
+
+	u16 func;
+	u16 lan_id;
+};
+
+/* Flow control parameters */
+struct txgbe_fc_info {
+	u32 high_water[TXGBE_DCB_MAX_TRAFFIC_CLASS]; /* Flow Ctrl High-water */
+	u32 low_water[TXGBE_DCB_MAX_TRAFFIC_CLASS]; /* Flow Ctrl Low-water */
+	u16 pause_time; /* Flow Control Pause timer */
+	bool send_xon; /* Flow control send XON */
+	bool strict_ieee; /* Strict IEEE mode */
+	bool disable_fc_autoneg; /* Do not autonegotiate FC */
+	bool fc_was_autonegged; /* Is current_mode the result of autonegging? */
+	enum txgbe_fc_mode current_mode; /* FC mode in effect */
+	enum txgbe_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+/* Statistics counters collected by the MAC */
+struct txgbe_hw_stats {
+	u64 crcerrs;
+	u64 illerrc;
+	u64 errbc;
+	u64 mspdc;
+	u64 mpctotal;
+	u64 mpc[8];
+	u64 mlfc;
+	u64 mrfc;
+	u64 rlec;
+	u64 lxontxc;
+	u64 lxonrxc;
+	u64 lxofftxc;
+	u64 lxoffrxc;
+	u64 pxontxc[8];
+	u64 pxonrxc[8];
+	u64 pxofftxc[8];
+	u64 pxoffrxc[8];
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc[8];
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mngprc;
+	u64 mngpdc;
+	u64 mngptc;
+	u64 tor;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 xec;
+	u64 qprc[16];
+	u64 qptc[16];
+	u64 qbrc[16];
+	u64 qbtc[16];
+	u64 qprdc[16];
+	u64 pxon2offc[8];
+	u64 fdirustat_add;
+	u64 fdirustat_remove;
+	u64 fdirfstat_fadd;
+	u64 fdirfstat_fremove;
+	u64 fdirmatch;
+	u64 fdirmiss;
+	u64 fccrc;
+	u64 fclast;
+	u64 fcoerpdc;
+	u64 fcoeprc;
+	u64 fcoeptc;
+	u64 fcoedwrc;
+	u64 fcoedwtc;
+	u64 fcoe_noddp;
+	u64 fcoe_noddp_ext_buff;
+	u64 ldpcec;
+	u64 pcrc8ec;
+	u64 b2ospc;
+	u64 b2ogprc;
+	u64 o2bgptc;
+	u64 o2bspc;
+};
+
+/* forward declaration */
+struct txgbe_hw;
+
+/* iterator type for walking multicast address lists */
+typedef u8* (*txgbe_mc_addr_itr) (struct txgbe_hw *hw, u8 **mc_addr_ptr,
+				  u32 *vmdq);
+
+/* Function pointer table */
+struct txgbe_eeprom_operations {
+	s32 (*init_params)(struct txgbe_hw *);
+	s32 (*read)(struct txgbe_hw *, u16, u16 *);
+	s32 (*read_buffer)(struct txgbe_hw *, u16, u16, u16 *);
+	s32 (*write)(struct txgbe_hw *, u16, u16);
+	s32 (*write_buffer)(struct txgbe_hw *, u16, u16, u16 *);
+	s32 (*validate_checksum)(struct txgbe_hw *, u16 *);
+	s32 (*update_checksum)(struct txgbe_hw *);
+	s32 (*calc_checksum)(struct txgbe_hw *);
+};
+
+struct txgbe_flash_operations {
+	s32 (*init_params)(struct txgbe_hw *);
+	s32 (*read_buffer)(struct txgbe_hw *, u32, u32, u32 *);
+	s32 (*write_buffer)(struct txgbe_hw *, u32, u32, u32 *);
+};
+
+struct txgbe_mac_operations {
+	s32 (*init_hw)(struct txgbe_hw *);
+	s32 (*reset_hw)(struct txgbe_hw *);
+	s32 (*start_hw)(struct txgbe_hw *);
+	s32 (*clear_hw_cntrs)(struct txgbe_hw *);
+	enum txgbe_media_type (*get_media_type)(struct txgbe_hw *);
+	s32 (*get_mac_addr)(struct txgbe_hw *, u8 *);
+	s32 (*get_san_mac_addr)(struct txgbe_hw *, u8 *);
+	s32 (*set_san_mac_addr)(struct txgbe_hw *, u8 *);
+	s32 (*get_device_caps)(struct txgbe_hw *, u16 *);
+	s32 (*get_wwn_prefix)(struct txgbe_hw *, u16 *, u16 *);
+	s32 (*stop_adapter)(struct txgbe_hw *);
+	s32 (*get_bus_info)(struct txgbe_hw *);
+	void (*set_lan_id)(struct txgbe_hw *);
+	s32 (*enable_rx_dma)(struct txgbe_hw *, u32);
+	s32 (*disable_sec_rx_path)(struct txgbe_hw *);
+	s32 (*enable_sec_rx_path)(struct txgbe_hw *);
+	s32 (*acquire_swfw_sync)(struct txgbe_hw *, u32);
+	void (*release_swfw_sync)(struct txgbe_hw *, u32);
+
+	/* Link */
+	void (*disable_tx_laser)(struct txgbe_hw *);
+	void (*enable_tx_laser)(struct txgbe_hw *);
+	void (*flap_tx_laser)(struct txgbe_hw *);
+	s32 (*setup_link)(struct txgbe_hw *, u32, bool);
+	s32 (*setup_mac_link)(struct txgbe_hw *, u32, bool);
+	s32 (*check_link)(struct txgbe_hw *, u32 *, bool *, bool);
+	s32 (*get_link_capabilities)(struct txgbe_hw *, u32 *,
+				     bool *);
+	void (*set_rate_select_speed)(struct txgbe_hw *, u32);
+
+	/* Packet Buffer manipulation */
+	void (*setup_rxpba)(struct txgbe_hw *, int, u32, int);
+
+	/* LED */
+	s32 (*led_on)(struct txgbe_hw *, u32);
+	s32 (*led_off)(struct txgbe_hw *, u32);
+
+	/* RAR, Multicast, VLAN */
+	s32 (*set_rar)(struct txgbe_hw *, u32, u8 *, u64, u32);
+	s32 (*clear_rar)(struct txgbe_hw *, u32);
+	s32 (*insert_mac_addr)(struct txgbe_hw *, u8 *, u32);
+	s32 (*set_vmdq)(struct txgbe_hw *, u32, u32);
+	s32 (*set_vmdq_san_mac)(struct txgbe_hw *, u32);
+	s32 (*clear_vmdq)(struct txgbe_hw *, u32, u32);
+	s32 (*init_rx_addrs)(struct txgbe_hw *);
+	s32 (*update_uc_addr_list)(struct txgbe_hw *, u8 *, u32,
+				   txgbe_mc_addr_itr);
+	s32 (*update_mc_addr_list)(struct txgbe_hw *, u8 *, u32,
+				   txgbe_mc_addr_itr, bool clear);
+	s32 (*enable_mc)(struct txgbe_hw *);
+	s32 (*disable_mc)(struct txgbe_hw *);
+	s32 (*clear_vfta)(struct txgbe_hw *);
+	s32 (*set_vfta)(struct txgbe_hw *, u32, u32, bool);
+	s32 (*set_vlvf)(struct txgbe_hw *, u32, u32, bool, bool *);
+	s32 (*init_uta_tables)(struct txgbe_hw *);
+	void (*set_mac_anti_spoofing)(struct txgbe_hw *, bool, int);
+	void (*set_vlan_anti_spoofing)(struct txgbe_hw *, bool, int);
+
+	/* Flow Control */
+	s32 (*fc_enable)(struct txgbe_hw *);
+	s32 (*setup_fc)(struct txgbe_hw *);
+
+	/* Manageability interface */
+	s32 (*set_fw_drv_ver)(struct txgbe_hw *, u8, u8, u8, u8);
+	s32 (*get_thermal_sensor_data)(struct txgbe_hw *);
+	s32 (*init_thermal_sensor_thresh)(struct txgbe_hw *hw);
+	void (*get_rtrup2tc)(struct txgbe_hw *hw, u8 *map);
+	void (*disable_rx)(struct txgbe_hw *hw);
+	void (*enable_rx)(struct txgbe_hw *hw);
+	void (*set_source_address_pruning)(struct txgbe_hw *, bool,
+					   unsigned int);
+	void (*set_ethertype_anti_spoofing)(struct txgbe_hw *, bool, int);
+	s32 (*dmac_config)(struct txgbe_hw *hw);
+	s32 (*setup_eee)(struct txgbe_hw *hw, bool enable_eee);
+};
+
+struct txgbe_phy_operations {
+	s32 (*identify)(struct txgbe_hw *);
+	s32 (*identify_sfp)(struct txgbe_hw *);
+	s32 (*init)(struct txgbe_hw *);
+	s32 (*reset)(struct txgbe_hw *);
+	s32 (*read_reg)(struct txgbe_hw *, u32, u32, u16 *);
+	s32 (*write_reg)(struct txgbe_hw *, u32, u32, u16);
+	s32 (*read_reg_mdi)(struct txgbe_hw *, u32, u32, u16 *);
+	s32 (*write_reg_mdi)(struct txgbe_hw *, u32, u32, u16);
+	u32 (*setup_link)(struct txgbe_hw *, u32, bool);
+	s32 (*setup_internal_link)(struct txgbe_hw *);
+	u32 (*setup_link_speed)(struct txgbe_hw *, u32, bool);
+	s32 (*check_link)(struct txgbe_hw *, u32 *, bool *);
+	s32 (*get_firmware_version)(struct txgbe_hw *, u16 *);
+	s32 (*read_i2c_byte)(struct txgbe_hw *, u8, u8, u8 *);
+	s32 (*write_i2c_byte)(struct txgbe_hw *, u8, u8, u8);
+	s32 (*read_i2c_sff8472)(struct txgbe_hw *, u8, u8 *);
+	s32 (*read_i2c_eeprom)(struct txgbe_hw *, u8, u8 *);
+	s32 (*read_i2c_sfp_phy)(struct txgbe_hw *, u16, u16 *);
+	s32 (*write_i2c_eeprom)(struct txgbe_hw *, u8, u8);
+	s32 (*check_overtemp)(struct txgbe_hw *);
+};
+
+struct txgbe_eeprom_info {
+	struct txgbe_eeprom_operations ops;
+	enum txgbe_eeprom_type type;
+	u32 semaphore_delay;
+	u16 word_size;
+	u16 address_bits;
+	u16 word_page_size;
+	u16 ctrl_word_3;
+	u16 sw_region_offset;
+};
+
+struct txgbe_flash_info {
+	struct txgbe_flash_operations ops;
+	u32 semaphore_delay;
+	u32 dword_size;
+	u16 address_bits;
+};
+
+
+#define TXGBE_FLAGS_DOUBLE_RESET_REQUIRED       0x01
+struct txgbe_mac_info {
+	struct txgbe_mac_operations ops;
+	u8 addr[TXGBE_ETH_LENGTH_OF_ADDRESS];
+	u8 perm_addr[TXGBE_ETH_LENGTH_OF_ADDRESS];
+	u8 san_addr[TXGBE_ETH_LENGTH_OF_ADDRESS];
+	/* prefix for World Wide Node Name (WWNN) */
+	u16 wwnn_prefix;
+	/* prefix for World Wide Port Name (WWPN) */
+	u16 wwpn_prefix;
+#define TXGBE_MAX_MTA                   128
+#define TXGBE_MAX_VFTA_ENTRIES          128
+	u32 mta_shadow[TXGBE_MAX_MTA];
+	s32 mc_filter_type;
+	u32 mcft_size;
+	u32 vft_shadow[TXGBE_MAX_VFTA_ENTRIES];
+	u32 vft_size;
+	u32 num_rar_entries;
+	u32 rar_highwater;
+	u32 rx_pb_size;
+	u32 max_tx_queues;
+	u32 max_rx_queues;
+	u32 orig_sr_pcs_ctl2;
+	u32 orig_sr_pma_mmd_ctl1;
+	u32 orig_sr_an_mmd_ctl;
+	u32 orig_sr_an_mmd_adv_reg2;
+	u32 orig_vr_xs_or_pcs_mmd_digi_ctl1;
+	u8  san_mac_rar_index;
+	bool get_link_status;
+	u16 max_msix_vectors;
+	bool arc_subsystem_valid;
+	bool orig_link_settings_stored;
+	bool autotry_restart;
+	u8 flags;
+	struct txgbe_thermal_sensor_data  thermal_sensor_data;
+	bool thermal_sensor_enabled;
+	struct txgbe_dmac_config dmac_config;
+	bool set_lben;
+};
+
+struct txgbe_phy_info {
+	struct txgbe_phy_operations ops;
+	enum txgbe_phy_type type;
+	u32 addr;
+	u32 id;
+	enum txgbe_sfp_type sfp_type;
+	bool sfp_setup_needed;
+	u32 revision;
+	enum txgbe_media_type media_type;
+	u32 phy_semaphore_mask;
+	u8 lan_id; /* to be delete */
+	txgbe_autoneg_advertised autoneg_advertised;
+	enum txgbe_smart_speed smart_speed;
+	bool smart_speed_active;
+	bool multispeed_fiber;
+	bool reset_if_overtemp;
+	txgbe_physical_layer link_mode;
+};
+
+#include "txgbe_mbx.h"
+
+struct txgbe_mbx_operations {
+	void (*init_params)(struct txgbe_hw *hw);
+	s32  (*read)(struct txgbe_hw *, u32 *, u16,  u16);
+	s32  (*write)(struct txgbe_hw *, u32 *, u16, u16);
+	s32  (*read_posted)(struct txgbe_hw *, u32 *, u16,  u16);
+	s32  (*write_posted)(struct txgbe_hw *, u32 *, u16, u16);
+	s32  (*check_for_msg)(struct txgbe_hw *, u16);
+	s32  (*check_for_ack)(struct txgbe_hw *, u16);
+	s32  (*check_for_rst)(struct txgbe_hw *, u16);
+};
+
+struct txgbe_mbx_stats {
+	u32 msgs_tx;
+	u32 msgs_rx;
+
+	u32 acks;
+	u32 reqs;
+	u32 rsts;
+};
+
+struct txgbe_mbx_info {
+	struct txgbe_mbx_operations ops;
+	struct txgbe_mbx_stats stats;
+	u32 timeout;
+	u32 udelay;
+	u32 v2p_mailbox;
+	u16 size;
+};
+
+enum txgbe_reset_type {
+	TXGBE_LAN_RESET = 0,
+	TXGBE_SW_RESET,
+	TXGBE_GLOBAL_RESET
+};
+
+enum txgbe_link_status {
+	TXGBE_LINK_STATUS_NONE = 0,
+	TXGBE_LINK_STATUS_KX,
+	TXGBE_LINK_STATUS_KX4
+};
+
+struct txgbe_hw {
+	u8 IOMEM *hw_addr;
+	void *back;
+	struct txgbe_mac_info mac;
+	struct txgbe_addr_filter_info addr_ctrl;
+	struct txgbe_fc_info fc;
+	struct txgbe_phy_info phy;
+	struct txgbe_eeprom_info eeprom;
+	struct txgbe_flash_info flash;
+	struct txgbe_bus_info bus;
+	struct txgbe_mbx_info mbx;
+	u16 device_id;
+	u16 vendor_id;
+	u16 subsystem_device_id;
+	u16 subsystem_vendor_id;
+	u8 revision_id;
+	bool adapter_stopped;
+	int api_version;
+	enum txgbe_reset_type reset_type;
+	bool force_full_reset;
+	bool allow_unsupported_sfp;
+	bool wol_enabled;
+	bool Fdir_enabled;
+	MTD_DEV phy_dev;
+	enum txgbe_link_status link_status;
+	u16 tpid[8];
+	u16 oem_ssid;
+	u16 oem_svid;
+	bool f2c_mod_status;         /* fiber to copper modules internal phy link status */
+};
+
+#define TCALL(hw, func, args...) (((hw)->func != NULL) \
+		? (hw)->func((hw), ##args) : TXGBE_NOT_IMPLEMENTED)
+
+/* Error Codes */
+#define TXGBE_ERR                                100
+#define TXGBE_NOT_IMPLEMENTED                    0x7FFFFFFF
+/* (-TXGBE_ERR, TXGBE_ERR): reserved for non-txgbe defined error code */
+#define TXGBE_ERR_NOSUPP                        -(TXGBE_ERR+0)
+#define TXGBE_ERR_EEPROM                        -(TXGBE_ERR+1)
+#define TXGBE_ERR_EEPROM_CHECKSUM               -(TXGBE_ERR+2)
+#define TXGBE_ERR_PHY                           -(TXGBE_ERR+3)
+#define TXGBE_ERR_CONFIG                        -(TXGBE_ERR+4)
+#define TXGBE_ERR_PARAM                         -(TXGBE_ERR+5)
+#define TXGBE_ERR_MAC_TYPE                      -(TXGBE_ERR+6)
+#define TXGBE_ERR_UNKNOWN_PHY                   -(TXGBE_ERR+7)
+#define TXGBE_ERR_LINK_SETUP                    -(TXGBE_ERR+8)
+#define TXGBE_ERR_ADAPTER_STOPPED               -(TXGBE_ERR+09)
+#define TXGBE_ERR_INVALID_MAC_ADDR              -(TXGBE_ERR+10)
+#define TXGBE_ERR_DEVICE_NOT_SUPPORTED          -(TXGBE_ERR+11)
+#define TXGBE_ERR_MASTER_REQUESTS_PENDING       -(TXGBE_ERR+12)
+#define TXGBE_ERR_INVALID_LINK_SETTINGS         -(TXGBE_ERR+13)
+#define TXGBE_ERR_AUTONEG_NOT_COMPLETE          -(TXGBE_ERR+14)
+#define TXGBE_ERR_RESET_FAILED                  -(TXGBE_ERR+15)
+#define TXGBE_ERR_SWFW_SYNC                     -(TXGBE_ERR+16)
+#define TXGBE_ERR_PHY_ADDR_INVALID              -(TXGBE_ERR+17)
+#define TXGBE_ERR_I2C                           -(TXGBE_ERR+18)
+#define TXGBE_ERR_SFP_NOT_SUPPORTED             -(TXGBE_ERR+19)
+#define TXGBE_ERR_SFP_NOT_PRESENT               -(TXGBE_ERR+20)
+#define TXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT       -(TXGBE_ERR+21)
+#define TXGBE_ERR_NO_SAN_ADDR_PTR               -(TXGBE_ERR+22)
+#define TXGBE_ERR_FDIR_REINIT_FAILED            -(TXGBE_ERR+23)
+#define TXGBE_ERR_EEPROM_VERSION                -(TXGBE_ERR+24)
+#define TXGBE_ERR_NO_SPACE                      -(TXGBE_ERR+25)
+#define TXGBE_ERR_OVERTEMP                      -(TXGBE_ERR+26)
+#define TXGBE_ERR_UNDERTEMP                     -(TXGBE_ERR+27)
+#define TXGBE_ERR_FC_NOT_NEGOTIATED             -(TXGBE_ERR+28)
+#define TXGBE_ERR_FC_NOT_SUPPORTED              -(TXGBE_ERR+29)
+#define TXGBE_ERR_SFP_SETUP_NOT_COMPLETE        -(TXGBE_ERR+30)
+#define TXGBE_ERR_PBA_SECTION                   -(TXGBE_ERR+31)
+#define TXGBE_ERR_INVALID_ARGUMENT              -(TXGBE_ERR+32)
+#define TXGBE_ERR_HOST_INTERFACE_COMMAND        -(TXGBE_ERR+33)
+#define TXGBE_ERR_OUT_OF_MEM                    -(TXGBE_ERR+34)
+#define TXGBE_ERR_FEATURE_NOT_SUPPORTED         -(TXGBE_ERR+36)
+#define TXGBE_ERR_EEPROM_PROTECTED_REGION       -(TXGBE_ERR+37)
+#define TXGBE_ERR_FDIR_CMD_INCOMPLETE           -(TXGBE_ERR+38)
+#define TXGBE_ERR_FLASH_LOADING_FAILED          -(TXGBE_ERR+39)
+#define TXGBE_ERR_XPCS_POWER_UP_FAILED          -(TXGBE_ERR+40)
+#define TXGBE_ERR_FW_RESP_INVALID               -(TXGBE_ERR+41)
+#define TXGBE_ERR_PHY_INIT_NOT_DONE             -(TXGBE_ERR+42)
+#define TXGBE_ERR_TIMEOUT                       -(TXGBE_ERR+43)
+#define TXGBE_ERR_TOKEN_RETRY                   -(TXGBE_ERR+44)
+#define TXGBE_ERR_REGISTER                      -(TXGBE_ERR+45)
+#define TXGBE_ERR_MBX                           -(TXGBE_ERR+46)
+#define TXGBE_ERR_MNG_ACCESS_FAILED             -(TXGBE_ERR+47)
+
+/**
+ * register operations
+ **/
+/* read register */
+#define TXGBE_DEAD_READ_RETRIES     10
+#define TXGBE_DEAD_READ_REG         0xdeadbeefU
+#define TXGBE_DEAD_READ_REG64       0xdeadbeefdeadbeefULL
+#define TXGBE_FAILED_READ_REG       0xffffffffU
+#define TXGBE_FAILED_READ_REG64     0xffffffffffffffffULL
+
+#define TXGBE_LLDP_REG 			0xf1000
+#define TXGBE_LLDP_ON 			0x0000000f
+
+static inline bool TXGBE_REMOVED(void __iomem *addr)
+{
+	return unlikely(!addr);
+}
+
+static inline u32
+txgbe_rd32(u8 __iomem *base)
+{
+	return readl(base);
+}
+
+static inline u32
+rd32(struct txgbe_hw *hw, u32 reg)
+{
+	u8 __iomem *base = READ_ONCE(hw->hw_addr);
+	u32 val = TXGBE_FAILED_READ_REG;
+
+	if (unlikely(!base))
+		return val;
+
+	val = txgbe_rd32(base + reg);
+
+	return val;
+}
+#define rd32a(a, reg, offset) ( \
+	rd32((a), (reg) + ((offset) << 2)))
+
+static inline u32
+rd32m(struct txgbe_hw *hw, u32 reg, u32 mask)
+{
+	u8 __iomem *base = READ_ONCE(hw->hw_addr);
+	u32 val = TXGBE_FAILED_READ_REG;
+
+	if (unlikely(!base))
+		return val;
+
+	val = txgbe_rd32(base + reg);
+	if (unlikely(val == TXGBE_FAILED_READ_REG))
+		return val;
+
+	return val & mask;
+}
+
+/* write register */
+static inline void
+txgbe_wr32(u8 __iomem *base, u32 val)
+{
+	writel(val, base);
+}
+
+static inline void
+wr32(struct txgbe_hw *hw, u32 reg, u32 val)
+{
+	u8 __iomem *base = READ_ONCE(hw->hw_addr);
+
+	if (unlikely(!base))
+		return;
+
+	txgbe_wr32(base + reg, val);
+}
+#define wr32a(a, reg, off, val) \
+	wr32((a), (reg) + ((off) << 2), (val))
+
+static inline void
+wr32m(struct txgbe_hw *hw, u32 reg, u32 mask, u32 field)
+{
+	u8 __iomem *base = READ_ONCE(hw->hw_addr);
+	u32 val;
+
+	if (unlikely(!base))
+		return;
+
+	val = txgbe_rd32(base + reg);
+	if (unlikely(val == TXGBE_FAILED_READ_REG))
+		return;
+
+	val = ((val & ~mask) | (field & mask));
+	txgbe_wr32(base + reg, val);
+}
+
+/* poll register */
+#define TXGBE_MDIO_TIMEOUT 1000
+#define TXGBE_I2C_TIMEOUT  1000
+#define TXGBE_SPI_TIMEOUT  1000
+static inline s32
+po32m(struct txgbe_hw *hw, u32 reg,
+		u32 mask, u32 field, int usecs, int count)
+{
+	int loop;
+
+	loop = (count ? count : (usecs + 9) / 10);
+	usecs = (loop ? (usecs + loop - 1) / loop : 0);
+
+	count = loop;
+	do {
+		u32 value = rd32(hw, reg);
+		if ((value & mask) == (field & mask)) {
+			break;
+		}
+
+		if (loop-- <= 0)
+			break;
+		usec_delay(usecs);
+	} while (true);
+
+	return (count - loop <= count ? 0 : TXGBE_ERR_TIMEOUT);
+}
+
+#define TXGBE_WRITE_FLUSH(H) rd32(H, TXGBE_MIS_PWR)
+
 #endif /* _TXGBE_TYPE_H_ */
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index 5d30564190e1..cd5dfa687898 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -42,6 +42,17 @@ config PCIE_CADENCE_PLAT_EP
 	  endpoint mode. This PCIe controller may be embedded into many
 	  different vendors SoCs.
 
+config PCIE_CADENCE_SOPHGO
+	bool "Cadence Sophgo PCIe Host controller"
+	depends on OF
+	select IRQ_DOMAIN
+	select PCIE_CADENCE
+	help
+	  Say Y here if you want to support the Cadence PCIe controller in host mode
+	  for Sophgo SoCs. this PCIe controller is from cadence, integrated into the
+	  Sophgo SoCs. PCIe is one of subsystems, it is choisable, Don't be
+	  care of this if it is not used in your systems.
+
 config PCI_J721E
 	bool
 
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 9bac5fb2f13d..edac7c5e94a3 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
 obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
 obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
 obj-$(CONFIG_PCI_J721E) += pci-j721e.o
+obj-$(CONFIG_PCIE_CADENCE_SOPHGO) += pcie-cadence-sophgo.o
diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.c b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c
new file mode 100644
index 000000000000..feb9bfdc7e75
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c
@@ -0,0 +1,963 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe host controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/msi.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "pcie-cadence.h"
+#include "pcie-cadence-sophgo.h"
+
+#define MAX_MSI_IRQS			512
+#define MAX_MSI_IRQS_PER_CTRL		1
+#define MAX_MSI_CTRLS			(MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
+#define MSI_DEF_NUM_VECTORS		512
+#define BYTE_NUM_PER_MSI_VEC		4
+
+// mango sideband signals
+#define CDNS_PCIE_CFG_MANGO_APB     0x1800000
+#define CDNS_PCIE_IRS_REG0400       0x0400
+#define CDNS_PCIE_IRS_REG0404       0x0404
+#define CDNS_PCIE_IRS_REG0418       0x0418
+#define CDNS_PCIE_IRS_REG041C       0x041C
+#define CDNS_PCIE_IRS_REG0804       0x0804
+#define CDNS_PCIE_IRS_REG080C       0x080C
+#define CDNS_PCIE_IRS_REG0810       0x0810
+#define CDNS_PCIE_IRS_REG085C       0x085C
+#define CDNS_PCIE_IRS_REG0860       0x0860
+#define CDNS_PCIE_IRS_REG0864       0x0864
+#define CDNS_PCIE_IRS_REG0868       0x0868
+#define CDNS_PCIE_IRS_REG086C       0x086C
+
+#define CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT		2
+#define CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT		3
+#define CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT		2
+#define CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT		3
+
+#define CDNS_PLAT_CPU_TO_BUS_ADDR       0xCFFFFFFFFF
+
+struct cdns_pcie_database {
+	void __iomem *pcie_reg_base;
+};
+
+static struct cdns_pcie_database cdns_pcie_db;
+
+static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie,
+				       u32 reg, u32 value)
+{
+	writel(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie,
+				       u32 reg)
+{
+	return readl(pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+/**
+ * struct cdns_mango_pcie_rc - private data for this PCIe Root Complex driver
+ * @pcie: Cadence PCIe controller
+ * @dev: pointer to PCIe device
+ * @cfg_res: start/end offsets in the physical system memory to map PCI
+ *           configuration space accesses
+ * @bus_range: first/last buses behind the PCIe host controller
+ * @cfg_base: IO mapped window to access the PCI configuration space of a
+ *            single function at a time
+ * @max_regions: maximum number of regions supported by the hardware
+ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
+ *                translation (nbits sets into the "no BAR match" register)
+ * @vendor_id: PCI vendor ID
+ * @device_id: PCI device ID
+ */
+struct cdns_mango_pcie_rc {
+	struct cdns_pcie	pcie;
+	struct device		*dev;
+	struct resource		*cfg_res;
+	struct resource		*bus_range;
+	void __iomem		*cfg_base;
+	u32			max_regions;
+	u32			no_bar_nbits;
+	u16			vendor_id;
+	u16			device_id;
+	u16			pcie_id;
+	u16			link_id;
+	u32			top_intc_used;
+	u32			msix_supported;
+	struct irq_domain	*msi_domain;
+	int			msi_irq;
+	struct irq_domain	*irq_domain;
+	dma_addr_t		msi_data;
+	void			*msi_page;
+	struct irq_chip		*msi_irq_chip;
+	u32			num_vectors;
+	u32			num_applied_vecs;
+	u32			irq_mask[MAX_MSI_CTRLS];
+	struct pci_bus		*root_bus;
+	raw_spinlock_t		lock;
+	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
+};
+
+static u64 cdns_mango_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
+{
+	return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
+}
+
+static const struct cdns_pcie_ops cdns_mango_ops = {
+	.cpu_addr_fixup = cdns_mango_cpu_addr_fixup,
+};
+
+static void __iomem *cdns_mango_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+					    int where)
+{
+	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+	struct cdns_mango_pcie_rc *rc = pci_host_bridge_priv(bridge);
+	struct cdns_pcie *pcie = &rc->pcie;
+	unsigned int busn = bus->number;
+	u32 addr0, desc0;
+
+	if (pci_is_root_bus(bus)) {
+		/*
+		 * Only the root port (devfn == 0) is connected to this bus.
+		 * All other PCI devices are behind some bridge hence on another
+		 * bus.
+		 */
+		if (devfn)
+			return NULL;
+
+		return pcie->reg_base + CDNS_PCIE_RP_BASE + (where & 0xfff);
+	}
+	/* Check that the link is up */
+	if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1))
+		return NULL;
+	/* Clear AXI link-down status */
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0);
+
+	/* Update Output registers for AXI region 0. */
+	addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
+		CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
+		CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
+
+	/* Configuration Type 0 or Type 1 access. */
+	desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+		CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+	/*
+	 * The bus number was already set once for all in desc1 by
+	 * cdns_pcie_host_init_address_translation().
+	 */
+	if (busn == bridge->busnr + 1)
+		desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
+	else
+		desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
+
+	return rc->cfg_base + (where & 0xfff);
+}
+
+int cdns_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+			    int where, int size, u32 *val)
+{
+	unsigned long addr;
+	unsigned int value, offset;
+	void __iomem *aligned_addr;
+
+	if ((bus->number != 0) && (bus->number != 0x40) &&
+	    (bus->number != 0x80) && (bus->number != 0xc0))
+		return pci_generic_config_read(bus, devfn, where, size, val);
+
+	addr = (unsigned long)bus->ops->map_bus(bus, devfn, where);
+	if (!addr) {
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	if (size == 1) {
+		offset = addr & 0x3;
+		aligned_addr = (void __iomem *)(addr & ~0x3UL);
+		value = readl(aligned_addr);
+		*val = (value >> (8 * offset)) & 0xff;
+	} else if (size == 2) {
+		WARN_ON((addr & 0x1) != 0); // address should be aligned to 2 bytes
+		offset = addr & 0x3;
+		aligned_addr = (void __iomem *)(addr & ~0x3UL);
+		value = readl(aligned_addr);
+		*val = (value >> (8 * offset)) & 0xffff;
+	} else {
+		WARN_ON((addr & 0x3) != 0); // address should be aligned to 4 bytes
+		*val = readl((void __iomem *)(addr));
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int cdns_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+			     int where, int size, u32 val)
+{
+	unsigned long addr;
+	unsigned int value, offset;
+	void __iomem *aligned_addr;
+
+	if ((bus->number != 0) && (bus->number != 0x40) &&
+	    (bus->number != 0x80) && (bus->number != 0xc0))
+		return pci_generic_config_write(bus, devfn, where, size, val);
+
+	addr = (unsigned long)bus->ops->map_bus(bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (size == 1) {
+		offset = addr & 0x3;
+		aligned_addr = (void __iomem *)(addr & ~0x3UL);
+		value = readl(aligned_addr);
+		value &= ~(0xFF << (8 * offset));
+		value |= ((val << (8 * offset)) & (0xFF << (8 * offset)));
+		writel(value, aligned_addr);
+	} else if (size == 2) {
+		WARN_ON((addr & 0x1) != 0);
+		offset = addr & 0x3;
+		aligned_addr = (void __iomem *)(addr & ~0x3UL);
+		value = readl(aligned_addr);
+		value &= ~(0xFFFF << (8 * offset));
+		value |= ((val << (8 * offset)) & (0xFFFF << (8 * offset)));
+		writel(value, aligned_addr);
+	} else {
+		WARN_ON((addr & 0x3) != 0);
+		writel(val, (void __iomem *)(addr));
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static struct pci_ops cdns_pcie_host_ops = {
+	.map_bus	= cdns_mango_pci_map_bus,
+	.read		= cdns_pcie_config_read,
+	.write		= cdns_pcie_config_write,
+};
+
+static const struct of_device_id cdns_pcie_host_of_match[] = {
+	{ .compatible = "sophgo,cdns-pcie-host" },
+
+	{ },
+};
+
+static int cdns_pcie_host_init_root_port(struct cdns_mango_pcie_rc *rc)
+{
+	struct cdns_pcie *pcie = &rc->pcie;
+	u32 value, ctrl;
+	u32 id;
+
+	/*
+	 * Set the root complex BAR configuration register:
+	 * - disable both BAR0 and BAR1.
+	 * - enable Prefetchable Memory Base and Limit registers in type 1
+	 *   config space (64 bits).
+	 * - enable IO Base and Limit registers in type 1 config
+	 *   space (32 bits).
+	 */
+	ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+	value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
+		CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
+		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
+		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
+		CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
+		CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
+	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
+
+	/* Set root port configuration space */
+	if (rc->vendor_id != 0xffff) {
+		id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
+			CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
+		cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+	}
+
+	if (rc->device_id != 0xffff) {
+		value = cdns_pcie_rp_readl(pcie, PCI_VENDOR_ID);
+		value &= 0x0000FFFF;
+		value |= (rc->device_id << 16);
+		cdns_pcie_rp_writel(pcie, PCI_VENDOR_ID, value);
+	}
+
+	cdns_pcie_rp_writel(pcie, PCI_CLASS_REVISION, PCI_CLASS_BRIDGE_PCI << 16);
+
+	return 0;
+}
+
+static int cdns_pcie_host_init_address_translation(struct cdns_mango_pcie_rc *rc)
+{
+	struct cdns_pcie *pcie = &rc->pcie;
+	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
+	struct resource *cfg_res = rc->cfg_res;
+	struct resource_entry *entry = NULL;
+	u32 addr0, addr1, desc1;
+	u64 cpu_addr;
+	int r, busnr = 0;
+
+	entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
+	if (entry)
+		busnr = entry->res->start;
+
+	/*
+	 * Reserve region 0 for PCI configure space accesses:
+	 * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
+	 * cdns_pci_map_bus(), other region registers are set here once for all.
+	 */
+	addr1 = 0; /* Should be programmed to zero. */
+	desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
+
+	cpu_addr = cfg_res->start;
+	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
+		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
+	addr1 = upper_32_bits(cpu_addr);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
+
+	r = 1;
+	resource_list_for_each_entry(entry, &bridge->windows) {
+		struct resource *res = entry->res;
+		u64 pci_addr = res->start - entry->offset;
+
+		if (resource_type(res) == IORESOURCE_IO)
+			cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
+						      true,
+						      pci_pio_to_address(res->start),
+						      pci_addr,
+						      resource_size(res));
+		else
+			cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
+						      false,
+						      res->start,
+						      pci_addr,
+						      resource_size(res));
+
+		r++;
+	}
+
+	/*
+	 * Set Root Port no BAR match Inbound Translation registers:
+	 * needed for MSI and DMA.
+	 * Root Port BAR0 and BAR1 are disabled, hence no need to set their
+	 * inbound translation registers.
+	 */
+	addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
+	addr1 = 0;
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
+	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
+
+	return 0;
+}
+
+static int cdns_pcie_msi_init(struct cdns_mango_pcie_rc *rc)
+{
+	struct device *dev = rc->dev;
+	struct cdns_pcie *pcie = &rc->pcie;
+	u32 apb_base = CDNS_PCIE_CFG_MANGO_APB;
+	u64 msi_target = 0;
+	u32 value = 0;
+
+	// support 512 msi vectors
+	rc->msi_page = dma_alloc_coherent(dev, 2048, &rc->msi_data,
+					  (GFP_KERNEL|GFP_DMA32|__GFP_ZERO));
+	if (rc->msi_page == NULL)
+		return -1;
+
+	dev_info(dev, "msi_data is 0x%llx\n", rc->msi_data);
+	msi_target = (u64)rc->msi_data;
+
+	if (rc->link_id == 1) {
+		apb_base -= 0x800000;
+		/* Program the msi_data */
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0868),
+				 lower_32_bits(msi_target));
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG086C),
+				 upper_32_bits(msi_target));
+
+		value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG080C));
+		value = (value & 0xffff0000) | MAX_MSI_IRQS;
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG080C), value);
+	} else {
+		/* Program the msi_data */
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0860),
+				 lower_32_bits(msi_target));
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0864),
+				 upper_32_bits(msi_target));
+
+		value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG085C));
+		value = (value & 0x0000ffff) | (MAX_MSI_IRQS << 16);
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG085C), value);
+	}
+
+	return 0;
+}
+
+static int cdns_pcie_host_init(struct device *dev, struct cdns_mango_pcie_rc *rc)
+{
+	int err;
+
+	err = cdns_pcie_host_init_root_port(rc);
+	if (err)
+		return err;
+
+	err = cdns_pcie_host_init_address_translation(rc);
+	if (err)
+		return err;
+
+	if (rc->top_intc_used == 0) {
+		rc->num_vectors = MSI_DEF_NUM_VECTORS;
+		rc->num_applied_vecs = 0;
+		if (IS_ENABLED(CONFIG_PCI_MSI)) {
+			err = cdns_pcie_msi_init(rc);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+
+static void cdns_pcie_msi_ack_irq(struct irq_data *d)
+{
+	irq_chip_ack_parent(d);
+}
+
+static void cdns_pcie_msi_mask_irq(struct irq_data *d)
+{
+	pci_msi_mask_irq(d);
+	irq_chip_mask_parent(d);
+}
+
+static void cdns_pcie_msi_unmask_irq(struct irq_data *d)
+{
+	pci_msi_unmask_irq(d);
+	irq_chip_unmask_parent(d);
+}
+
+static struct irq_chip cdns_pcie_msi_irq_chip = {
+	.name = "cdns-msi",
+	.irq_ack = cdns_pcie_msi_ack_irq,
+	.irq_mask = cdns_pcie_msi_mask_irq,
+	.irq_unmask = cdns_pcie_msi_unmask_irq,
+};
+
+static struct msi_domain_info cdns_pcie_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+	.chip	= &cdns_pcie_msi_irq_chip,
+};
+
+static struct msi_domain_info cdns_pcie_top_intr_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS
+		   | MSI_FLAG_PCI_MSIX),
+	.chip	= &cdns_pcie_msi_irq_chip,
+};
+
+struct vendor_id_list vendor_id_list[] = {
+	{"Inter X520", 0x8086, 0x10fb},
+    //{"WangXun RP1000", 0x8088},
+	{"Switchtec", 0x11f8,4052},
+};
+
+size_t vendor_id_list_num = ARRAY_SIZE(vendor_id_list);
+
+int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list[],
+			size_t vendor_id_list_num)
+{
+	uint16_t device_vendor_id;
+	uint16_t device_id;
+
+	if (pci_read_config_word(dev, PCI_VENDOR_ID, &device_vendor_id) != 0) {
+		pr_err("Failed to read device vendor ID\n");
+		return 0;
+	}
+
+	if (pci_read_config_word(dev, PCI_DEVICE_ID, &device_id) != 0) {
+		pr_err("Failed to read device vendor ID\n");
+		return 0;
+	}
+
+	for (int i = 0; i < vendor_id_list_num; ++i) {
+		if (device_vendor_id == vendor_id_list[i].vendor_id && device_id == vendor_id_list[i].device_id) {
+			pr_info("dev: %s vendor ID: 0x%04x device ID: 0x%04x Enable MSI-X IRQ\n",
+				vendor_id_list[i].name, device_vendor_id, device_id);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+
+static int cdns_pcie_msi_setup_for_top_intc(struct cdns_mango_pcie_rc *rc, int intc_id)
+{
+	struct irq_domain *irq_parent = cdns_pcie_get_parent_irq_domain(intc_id);
+	struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node);
+
+	if (rc->msix_supported == 1) {
+		rc->msi_domain = pci_msi_create_irq_domain(fwnode,
+							   &cdns_pcie_top_intr_msi_domain_info,
+							   irq_parent);
+	} else {
+		rc->msi_domain = pci_msi_create_irq_domain(fwnode,
+							   &cdns_pcie_msi_domain_info,
+							   irq_parent);
+	}
+
+	if (!rc->msi_domain) {
+		dev_err(rc->dev, "create msi irq domain failed\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* MSI int handler */
+irqreturn_t cdns_handle_msi_irq(struct cdns_mango_pcie_rc *rc)
+{
+	u32 i, pos, irq;
+	unsigned long val;
+	u32 status, num_vectors;
+	irqreturn_t ret = IRQ_NONE;
+
+	num_vectors = rc->num_applied_vecs;
+	for (i = 0; i <= num_vectors; i++) {
+		status = readl((void *)(rc->msi_page + i * BYTE_NUM_PER_MSI_VEC));
+		if (!status)
+			continue;
+
+		ret = IRQ_HANDLED;
+		val = status;
+		pos = 0;
+		while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL,
+					    pos)) != MAX_MSI_IRQS_PER_CTRL) {
+			irq = irq_find_mapping(rc->irq_domain,
+					       (i * MAX_MSI_IRQS_PER_CTRL) +
+					       pos);
+			generic_handle_irq(irq);
+			pos++;
+		}
+		writel(0, ((void *)(rc->msi_page) + i * BYTE_NUM_PER_MSI_VEC));
+	}
+	if (ret == IRQ_NONE) {
+		ret = IRQ_HANDLED;
+		for (i = 0; i <= num_vectors; i++) {
+			for (pos = 0; pos < MAX_MSI_IRQS_PER_CTRL; pos++) {
+				irq = irq_find_mapping(rc->irq_domain,
+						       (i * MAX_MSI_IRQS_PER_CTRL) +
+						       pos);
+				if (!irq)
+					continue;
+				generic_handle_irq(irq);
+			}
+		}
+	}
+
+	return ret;
+}
+
+static irqreturn_t cdns_pcie_irq_handler(int irq, void *arg)
+{
+	struct cdns_mango_pcie_rc *rc = arg;
+	struct cdns_pcie *pcie = &rc->pcie;
+	u32 apb_base = CDNS_PCIE_CFG_MANGO_APB;
+	u32 status = 0;
+	u32 st_msi_in_bit = 0;
+	u32 clr_msi_in_bit = 0;
+
+	if (rc->link_id == 1) {
+		apb_base -= 0x800000;
+		st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT;
+		clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT;
+	} else {
+		st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT;
+		clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT;
+	}
+
+	status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810));
+	if ((status >> st_msi_in_bit) & 0x1) {
+		WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI));
+
+		//clear msi interrupt bit reg0810[2]
+		status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804));
+		status |= ((u32)0x1 << clr_msi_in_bit);
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status);
+
+		status &= ~((u32)0x1 << clr_msi_in_bit);
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status);
+
+		cdns_handle_msi_irq(rc);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Chained MSI interrupt service routine */
+static void cdns_chained_msi_isr(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct cdns_mango_pcie_rc *rc;
+	struct cdns_pcie *pcie;
+	u32 apb_base = CDNS_PCIE_CFG_MANGO_APB;
+	u32 status = 0;
+	u32 st_msi_in_bit = 0;
+	u32 clr_msi_in_bit = 0;
+
+	chained_irq_enter(chip, desc);
+
+	rc = irq_desc_get_handler_data(desc);
+	pcie = &rc->pcie;
+	if (rc->link_id == 1) {
+		apb_base -= 0x800000;
+		st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT;
+		clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT;
+	} else {
+		st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT;
+		clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT;
+	}
+
+	status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810));
+	if ((status >> st_msi_in_bit) & 0x1) {
+		WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI));
+
+		//clear msi interrupt bit reg0810[2]
+		status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804));
+		status |= ((u32)0x1 << clr_msi_in_bit);
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status);
+
+		status &= ~((u32)0x1 << clr_msi_in_bit);
+		cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status);
+
+		cdns_handle_msi_irq(rc);
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static int cdns_pci_msi_set_affinity(struct irq_data *d,
+				   const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void cdns_pci_bottom_mask(struct irq_data *d)
+{
+}
+
+static void cdns_pci_bottom_unmask(struct irq_data *d)
+{
+}
+
+static void cdns_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d);
+	u64 msi_target;
+
+	msi_target = (u64)rc->msi_data;
+
+	msg->address_lo = lower_32_bits(msi_target) + BYTE_NUM_PER_MSI_VEC * d->hwirq;
+	msg->address_hi = upper_32_bits(msi_target);
+	msg->data = 1;
+
+	rc->num_applied_vecs = d->hwirq;
+
+	dev_err(rc->dev, "msi#%d address_hi %#x address_lo %#x\n",
+		(int)d->hwirq, msg->address_hi, msg->address_lo);
+}
+
+static void cdns_pci_bottom_ack(struct irq_data *d)
+{
+}
+
+static struct irq_chip cdns_pci_msi_bottom_irq_chip = {
+	.name = "CDNS-PCI-MSI",
+	.irq_ack = cdns_pci_bottom_ack,
+	.irq_compose_msi_msg = cdns_pci_setup_msi_msg,
+	.irq_set_affinity = cdns_pci_msi_set_affinity,
+	.irq_mask = cdns_pci_bottom_mask,
+	.irq_unmask = cdns_pci_bottom_unmask,
+};
+
+static int cdns_pcie_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *args)
+{
+	struct cdns_mango_pcie_rc *rc = domain->host_data;
+	unsigned long flags;
+	u32 i;
+	int bit;
+
+	raw_spin_lock_irqsave(&rc->lock, flags);
+
+	bit = bitmap_find_free_region(rc->msi_irq_in_use, rc->num_vectors,
+				      order_base_2(nr_irqs));
+
+	raw_spin_unlock_irqrestore(&rc->lock, flags);
+
+	if (bit < 0)
+		return -ENOSPC;
+
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_info(domain, virq + i, bit + i,
+				    rc->msi_irq_chip,
+				    rc, handle_edge_irq,
+				    NULL, NULL);
+
+	return 0;
+}
+
+static void cdns_pcie_irq_domain_free(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&rc->lock, flags);
+
+	bitmap_release_region(rc->msi_irq_in_use, d->hwirq,
+			      order_base_2(nr_irqs));
+
+	raw_spin_unlock_irqrestore(&rc->lock, flags);
+}
+
+static const struct irq_domain_ops cdns_pcie_msi_domain_ops = {
+	.alloc	= cdns_pcie_irq_domain_alloc,
+	.free	= cdns_pcie_irq_domain_free,
+};
+
+int cdns_pcie_allocate_domains(struct cdns_mango_pcie_rc *rc)
+{
+	struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node);
+
+	rc->irq_domain = irq_domain_create_linear(fwnode, rc->num_vectors,
+					       &cdns_pcie_msi_domain_ops, rc);
+	if (!rc->irq_domain) {
+		dev_err(rc->dev, "Failed to create IRQ domain\n");
+		return -ENOMEM;
+	}
+
+	irq_domain_update_bus_token(rc->irq_domain, DOMAIN_BUS_NEXUS);
+
+	rc->msi_domain = pci_msi_create_irq_domain(fwnode,
+						   &cdns_pcie_msi_domain_info,
+						   rc->irq_domain);
+	if (!rc->msi_domain) {
+		dev_err(rc->dev, "Failed to create MSI domain\n");
+		irq_domain_remove(rc->irq_domain);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void cdns_pcie_free_msi(struct cdns_mango_pcie_rc *rc)
+{
+	if (rc->msi_irq) {
+		irq_set_chained_handler(rc->msi_irq, NULL);
+		irq_set_handler_data(rc->msi_irq, NULL);
+	}
+
+	irq_domain_remove(rc->msi_domain);
+	irq_domain_remove(rc->irq_domain);
+
+	if (rc->msi_page)
+		dma_free_coherent(rc->dev, 1024, rc->msi_page, rc->msi_data);
+
+}
+
+static int cdns_pcie_msi_setup(struct cdns_mango_pcie_rc *rc)
+{
+	int ret = 0;
+
+	raw_spin_lock_init(&rc->lock);
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		rc->msi_irq_chip = &cdns_pci_msi_bottom_irq_chip;
+
+		ret = cdns_pcie_allocate_domains(rc);
+		if (ret)
+			return ret;
+
+		if (rc->msi_irq)
+			irq_set_chained_handler_and_data(rc->msi_irq, cdns_chained_msi_isr, rc);
+	}
+
+	return ret;
+}
+
+static int cdns_pcie_host_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct pci_host_bridge *bridge;
+	struct cdns_mango_pcie_rc *rc;
+	struct cdns_pcie *pcie;
+	struct resource *res;
+	int ret;
+	int phy_count;
+	int top_intc_id = -1;
+
+	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+	if (!bridge)
+		return -ENOMEM;
+
+	rc = pci_host_bridge_priv(bridge);
+	rc->dev = dev;
+
+	pcie = &rc->pcie;
+	pcie->is_rc = true;
+	pcie->ops = &cdns_mango_ops;
+
+	rc->max_regions = 32;
+	of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
+
+	rc->no_bar_nbits = 32;
+	of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
+
+	rc->vendor_id = 0xffff;
+	of_property_read_u16(np, "vendor-id", &rc->vendor_id);
+
+	rc->device_id = 0xffff;
+	of_property_read_u16(np, "device-id", &rc->device_id);
+
+	rc->pcie_id = 0xffff;
+	of_property_read_u16(np, "pcie-id", &rc->pcie_id);
+
+	rc->link_id = 0xffff;
+	of_property_read_u16(np, "link-id", &rc->link_id);
+
+	rc->msix_supported = 0;
+	of_property_read_u32(np, "msix-supported", &rc->msix_supported);
+
+	rc->top_intc_used = 0;
+	of_property_read_u32(np, "top-intc-used", &rc->top_intc_used);
+	if (rc->top_intc_used == 1)
+		of_property_read_u32(np, "top-intc-id", &top_intc_id);
+
+	if (rc->link_id == 0) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+		pcie->reg_base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(pcie->reg_base)) {
+			dev_err(dev, "missing \"reg\"\n");
+			return PTR_ERR(pcie->reg_base);
+		}
+		cdns_pcie_db.pcie_reg_base = pcie->reg_base;
+	} else if (rc->link_id == 1) {
+		pcie->reg_base = cdns_pcie_db.pcie_reg_base + 0x800000;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+	rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
+	if (IS_ERR(rc->cfg_base)) {
+		dev_err(dev, "missing \"cfg\"\n");
+		return PTR_ERR(rc->cfg_base);
+	}
+	rc->cfg_res = res;
+
+	ret = cdns_pcie_init_phy(dev, pcie);
+	if (ret) {
+		dev_err(dev, "failed to init phy\n");
+		return ret;
+	}
+	platform_set_drvdata(pdev, pcie);
+
+	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "pm_runtime_get_sync() failed\n");
+		goto err_get_sync;
+	}
+
+	ret = cdns_pcie_host_init(dev, rc);
+	if (ret)
+		goto err_init;
+
+	if ((rc->top_intc_used == 0) && (IS_ENABLED(CONFIG_PCI_MSI))) {
+		rc->msi_irq = platform_get_irq_byname(pdev, "msi");
+		if (rc->msi_irq <= 0) {
+			dev_err(dev, "failed to get MSI irq\n");
+			goto err_init_irq;
+		}
+
+		ret = devm_request_irq(dev, rc->msi_irq, cdns_pcie_irq_handler,
+				       IRQF_SHARED | IRQF_NO_THREAD,
+				       "cdns-pcie-irq", rc);
+
+		if (ret) {
+			dev_err(dev, "failed to request MSI irq\n");
+			goto err_init_irq;
+		}
+	}
+
+	bridge->dev.parent = dev;
+	bridge->ops = &cdns_pcie_host_ops;
+	bridge->map_irq = of_irq_parse_and_map_pci;
+	bridge->swizzle_irq = pci_common_swizzle;
+	if (rc->top_intc_used == 0)
+		bridge->sysdata = rc;
+
+	if (rc->top_intc_used == 0) {
+		ret = cdns_pcie_msi_setup(rc);
+		if (ret < 0)
+			goto err_host_probe;
+	} else if (rc->top_intc_used == 1) {
+		ret = cdns_pcie_msi_setup_for_top_intc(rc, top_intc_id);
+		if (ret < 0)
+			goto err_host_probe;
+	}
+
+	ret = pci_host_probe(bridge);
+	if (ret < 0)
+		goto err_host_probe;
+
+	return 0;
+
+ err_host_probe:
+ err_init_irq:
+	if ((rc->top_intc_used == 0) && pci_msi_enabled())
+		cdns_pcie_free_msi(rc);
+
+ err_init:
+	pm_runtime_put_sync(dev);
+
+ err_get_sync:
+	pm_runtime_disable(dev);
+	cdns_pcie_disable_phy(pcie);
+	phy_count = pcie->phy_count;
+	while (phy_count--)
+		device_link_del(pcie->link[phy_count]);
+
+	return ret;
+}
+
+static void cdns_pcie_shutdown(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cdns_pcie *pcie = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_put_sync(dev);
+	if (ret < 0)
+		dev_dbg(dev, "pm_runtime_put_sync failed\n");
+
+	pm_runtime_disable(dev);
+	cdns_pcie_disable_phy(pcie);
+}
+
+static struct platform_driver cdns_pcie_host_driver = {
+	.driver = {
+		.name = "cdns-pcie-host",
+		.of_match_table = cdns_pcie_host_of_match,
+		.pm	= &cdns_pcie_pm_ops,
+	},
+	.probe = cdns_pcie_host_probe,
+	.shutdown = cdns_pcie_shutdown,
+};
+builtin_platform_driver(cdns_pcie_host_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.h b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h
new file mode 100644
index 000000000000..ef46c46678ed
--- /dev/null
+++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h
@@ -0,0 +1,17 @@
+#ifndef PCIE_CADENCE_SOPHGO
+#define PCIE_CADENCE_SOPHGO
+
+
+struct vendor_id_list {
+	const char  *name;
+	uint16_t    vendor_id;
+	uint16_t    device_id;
+};
+
+extern struct vendor_id_list vendor_id_list[];
+extern size_t vendor_id_list_num;
+
+extern struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id);
+int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list[],
+			size_t vendor_id_list_num);
+#endif
diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
index fdd2ec09651e..f5919963e1e9 100644
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -12,6 +12,7 @@
 
 #include "../pci.h"
 #include "msi.h"
+#include "../controller/cadence/pcie-cadence-sophgo.h"
 
 static int pci_msi_enable = 1;
 int pci_msi_ignore_mask;
@@ -932,33 +933,37 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
 {
 	int rc, nvec = maxvec;
 
-	if (maxvec < minvec)
-		return -ERANGE;
+	if (check_vendor_id(dev, vendor_id_list, vendor_id_list_num)) {
+		if (maxvec < minvec)
+			return -ERANGE;
 
-	if (WARN_ON_ONCE(dev->msix_enabled))
-		return -EINVAL;
+		if (WARN_ON_ONCE(dev->msix_enabled))
+			return -EINVAL;
 
-	rc = pci_setup_msi_context(dev);
-	if (rc)
-		return rc;
+		rc = pci_setup_msi_context(dev);
+		if (rc)
+			return rc;
 
-	for (;;) {
-		if (affd) {
-			nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
-			if (nvec < minvec)
-				return -ENOSPC;
-		}
+		for (;;) {
+			if (affd) {
+				nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
+				if (nvec < minvec)
+					return -ENOSPC;
+			}
 
-		rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
-		if (rc == 0)
-			return nvec;
+			rc = __pci_enable_msix(dev, entries, nvec, affd, flags);
+			if (rc == 0)
+				return nvec;
 
-		if (rc < 0)
-			return rc;
-		if (rc < minvec)
-			return -ENOSPC;
+			if (rc < 0)
+				return rc;
+			if (rc < minvec)
+				return -ENOSPC;
 
-		nvec = rc;
+			nvec = rc;
+		}
+	} else {
+		return -1;
 	}
 }
 
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 7f8788a970ae..e059df451fac 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -20,7 +20,7 @@
 #include "portdrv.h"
 
 /* If this switch is set, PCIe port native services should not be enabled. */
-bool pcie_ports_disabled;
+bool pcie_ports_disabled = true;
 
 /*
  * If the user specified "pcie_ports=native", use the PCIe services regardless
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 382fe5ee6100..6f9ca2c42ffe 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -20,6 +20,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/sched/clock.h>
 
+#include <asm/errata_list.h>
 #include <asm/sbi.h>
 #include <asm/hwcap.h>
 
@@ -47,6 +48,8 @@ static const struct attribute_group *riscv_pmu_attr_groups[] = {
  * per_cpu in case of harts with different pmu counters
  */
 static union sbi_pmu_ctr_info *pmu_ctr_list;
+static bool riscv_pmu_use_irq;
+static unsigned int riscv_pmu_irq_num;
 static unsigned int riscv_pmu_irq;
 
 struct sbi_pmu_event_data {
@@ -580,7 +583,7 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 	fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
 	event = cpu_hw_evt->events[fidx];
 	if (!event) {
-		csr_clear(CSR_SIP, SIP_LCOFIP);
+		csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
 		return IRQ_NONE;
 	}
 
@@ -588,13 +591,13 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 	pmu_sbi_stop_hw_ctrs(pmu);
 
 	/* Overflow status register should only be read after counter are stopped */
-	overflow = csr_read(CSR_SSCOUNTOVF);
+	ALT_SBI_PMU_OVERFLOW(overflow);
 
 	/*
 	 * Overflow interrupt pending bit should only be cleared after stopping
 	 * all the counters to avoid any race condition.
 	 */
-	csr_clear(CSR_SIP, SIP_LCOFIP);
+	csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
 
 	/* No overflow bit is set */
 	if (!overflow)
@@ -661,10 +664,10 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
 	/* Stop all the counters so that they can be enabled from perf */
 	pmu_sbi_stop_all(pmu);
 
-	if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
+	if (riscv_pmu_use_irq) {
 		cpu_hw_evt->irq = riscv_pmu_irq;
-		csr_clear(CSR_IP, BIT(RV_IRQ_PMU));
-		csr_set(CSR_IE, BIT(RV_IRQ_PMU));
+		csr_clear(CSR_IP, BIT(riscv_pmu_irq_num));
+		csr_set(CSR_IE, BIT(riscv_pmu_irq_num));
 		enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE);
 	}
 
@@ -673,9 +676,9 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
 
 static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node)
 {
-	if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
+	if (riscv_pmu_use_irq) {
 		disable_percpu_irq(riscv_pmu_irq);
-		csr_clear(CSR_IE, BIT(RV_IRQ_PMU));
+		csr_clear(CSR_IE, BIT(riscv_pmu_irq_num));
 	}
 
 	/* Disable all counters access for user mode now */
@@ -691,7 +694,18 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
 	struct device_node *cpu, *child;
 	struct irq_domain *domain = NULL;
 
-	if (!riscv_isa_extension_available(NULL, SSCOFPMF))
+	if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
+		riscv_pmu_irq_num = RV_IRQ_PMU;
+		riscv_pmu_use_irq = true;
+	} else if (IS_ENABLED(CONFIG_ERRATA_THEAD_PMU) &&
+		   riscv_cached_mvendorid(0) == THEAD_VENDOR_ID &&
+		   riscv_cached_marchid(0) == 0 &&
+		   riscv_cached_mimpid(0) == 0) {
+		riscv_pmu_irq_num = THEAD_C9XX_RV_IRQ_PMU;
+		riscv_pmu_use_irq = true;
+	}
+
+	if (!riscv_pmu_use_irq)
 		return -EOPNOTSUPP;
 
 	for_each_of_cpu_node(cpu) {
@@ -713,7 +727,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
 		return -ENODEV;
 	}
 
-	riscv_pmu_irq = irq_create_mapping(domain, RV_IRQ_PMU);
+	riscv_pmu_irq = irq_create_mapping(domain, riscv_pmu_irq_num);
 	if (!riscv_pmu_irq) {
 		pr_err("Failed to map PMU interrupt for node\n");
 		return -ENODEV;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index f71fefff400f..bd0308825ba5 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -22,7 +22,7 @@ config PINCONF
 	bool "Support pin configuration controllers" if COMPILE_TEST
 
 config GENERIC_PINCONF
-	bool
+	bool "GENERIC_PINCONF"
 	select PINCONF
 
 config DEBUG_PINCTRL
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 89bfa01b5231..041018cc79ab 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
 obj-$(CONFIG_PINCTRL_STM32)	+= stm32/
 obj-y				+= sunplus/
 obj-$(CONFIG_PINCTRL_SUNXI)	+= sunxi/
+obj-$(CONFIG_ARCH_SOPHGO)	+= sophgo/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-y				+= ti/
 obj-$(CONFIG_PINCTRL_UNIPHIER)	+= uniphier/
diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile
new file mode 100644
index 000000000000..2f2cd0d5a99d
--- /dev/null
+++ b/drivers/pinctrl/sophgo/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ARCH_SOPHGO)	+= pinctrl-sophgo.o
+obj-$(CONFIG_ARCH_SOPHGO)	+= pinctrl-mango.o
diff --git a/drivers/pinctrl/sophgo/pinctrl-mango.c b/drivers/pinctrl/sophgo/pinctrl-mango.c
new file mode 100644
index 000000000000..a5707bcd92c2
--- /dev/null
+++ b/drivers/pinctrl/sophgo/pinctrl-mango.c
@@ -0,0 +1,455 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/device.h>
+#include <linux/of.h>
+
+#include "../pinctrl-utils.h"
+#include "pinctrl-sophgo.h"
+
+#define DRV_PINCTRL_NAME "mango_pinctrl"
+#define DRV_PINMUX_NAME "mango_pinmux"
+
+#define FUNCTION(fname, gname, fmode) \
+	{ \
+		.name = #fname, \
+		.groups = gname##_group, \
+		.num_groups = ARRAY_SIZE(gname##_group), \
+		.mode = fmode, \
+	}
+
+#define PIN_GROUP(gname) \
+	{ \
+		.name = #gname "_grp", \
+		.pins = gname##_pins, \
+		.num_pins = ARRAY_SIZE(gname##_pins), \
+	}
+
+static const struct pinctrl_pin_desc mango_pins[] = {
+	PINCTRL_PIN(0,   "MIO0"),
+	PINCTRL_PIN(1,   "MIO1"),
+	PINCTRL_PIN(2,   "MIO2"),
+	PINCTRL_PIN(3,   "MIO3"),
+	PINCTRL_PIN(4,   "MIO4"),
+	PINCTRL_PIN(5,   "MIO5"),
+	PINCTRL_PIN(6,   "MIO6"),
+	PINCTRL_PIN(7,   "MIO7"),
+	PINCTRL_PIN(8,   "MIO8"),
+	PINCTRL_PIN(9,   "MIO9"),
+	PINCTRL_PIN(10,   "MIO10"),
+	PINCTRL_PIN(11,   "MIO11"),
+	PINCTRL_PIN(12,   "MIO12"),
+	PINCTRL_PIN(13,   "MIO13"),
+	PINCTRL_PIN(14,   "MIO14"),
+	PINCTRL_PIN(15,   "MIO15"),
+	PINCTRL_PIN(16,   "MIO16"),
+	PINCTRL_PIN(17,   "MIO17"),
+	PINCTRL_PIN(18,   "MIO18"),
+	PINCTRL_PIN(19,   "MIO19"),
+	PINCTRL_PIN(20,   "MIO20"),
+	PINCTRL_PIN(21,   "MIO21"),
+	PINCTRL_PIN(22,   "MIO22"),
+	PINCTRL_PIN(23,   "MIO23"),
+	PINCTRL_PIN(24,   "MIO24"),
+	PINCTRL_PIN(25,   "MIO25"),
+	PINCTRL_PIN(26,   "MIO26"),
+	PINCTRL_PIN(27,   "MIO27"),
+	PINCTRL_PIN(28,   "MIO28"),
+	PINCTRL_PIN(29,   "MIO29"),
+	PINCTRL_PIN(30,   "MIO30"),
+	PINCTRL_PIN(31,   "MIO31"),
+	PINCTRL_PIN(32,   "MIO32"),
+	PINCTRL_PIN(33,   "MIO33"),
+	PINCTRL_PIN(34,   "MIO34"),
+	PINCTRL_PIN(35,   "MIO35"),
+	PINCTRL_PIN(36,   "MIO36"),
+	PINCTRL_PIN(37,   "MIO37"),
+	PINCTRL_PIN(38,   "MIO38"),
+	PINCTRL_PIN(39,   "MIO39"),
+	PINCTRL_PIN(40,   "MIO40"),
+	PINCTRL_PIN(41,   "MIO41"),
+	PINCTRL_PIN(42,   "MIO42"),
+	PINCTRL_PIN(43,   "MIO43"),
+	PINCTRL_PIN(44,   "MIO44"),
+	PINCTRL_PIN(45,   "MIO45"),
+	PINCTRL_PIN(46,   "MIO46"),
+	PINCTRL_PIN(47,   "MIO47"),
+	PINCTRL_PIN(48,   "MIO48"),
+	PINCTRL_PIN(49,   "MIO49"),
+	PINCTRL_PIN(50,   "MIO50"),
+	PINCTRL_PIN(51,   "MIO51"),
+	PINCTRL_PIN(52,   "MIO52"),
+	PINCTRL_PIN(53,   "MIO53"),
+	PINCTRL_PIN(54,   "MIO54"),
+	PINCTRL_PIN(55,   "MIO55"),
+	PINCTRL_PIN(56,   "MIO56"),
+	PINCTRL_PIN(57,   "MIO57"),
+	PINCTRL_PIN(58,   "MIO58"),
+	PINCTRL_PIN(59,   "MIO59"),
+	PINCTRL_PIN(60,   "MIO60"),
+	PINCTRL_PIN(61,   "MIO61"),
+	PINCTRL_PIN(62,   "MIO62"),
+	PINCTRL_PIN(63,   "MIO63"),
+	PINCTRL_PIN(64,   "MIO64"),
+	PINCTRL_PIN(65,   "MIO65"),
+	PINCTRL_PIN(66,   "MIO66"),
+	PINCTRL_PIN(67,   "MIO67"),
+	PINCTRL_PIN(68,   "MIO68"),
+	PINCTRL_PIN(69,   "MIO69"),
+	PINCTRL_PIN(70,   "MIO70"),
+	PINCTRL_PIN(71,   "MIO71"),
+	PINCTRL_PIN(72,   "MIO72"),
+	PINCTRL_PIN(73,   "MIO73"),
+	PINCTRL_PIN(74,   "MIO74"),
+	PINCTRL_PIN(75,   "MIO75"),
+	PINCTRL_PIN(76,   "MIO76"),
+	PINCTRL_PIN(77,   "MIO77"),
+	PINCTRL_PIN(78,   "MIO78"),
+	PINCTRL_PIN(79,   "MIO79"),
+	PINCTRL_PIN(80,   "MIO80"),
+	PINCTRL_PIN(81,   "MIO81"),
+	PINCTRL_PIN(82,   "MIO82"),
+	PINCTRL_PIN(83,   "MIO83"),
+	PINCTRL_PIN(84,   "MIO84"),
+	PINCTRL_PIN(85,   "MIO85"),
+	PINCTRL_PIN(86,   "MIO86"),
+	PINCTRL_PIN(87,   "MIO87"),
+	PINCTRL_PIN(88,   "MIO88"),
+	PINCTRL_PIN(89,   "MIO89"),
+	PINCTRL_PIN(90,   "MIO90"),
+	PINCTRL_PIN(91,   "MIO91"),
+	PINCTRL_PIN(92,   "MIO92"),
+	PINCTRL_PIN(93,   "MIO93"),
+	PINCTRL_PIN(94,   "MIO94"),
+	PINCTRL_PIN(95,   "MIO95"),
+	PINCTRL_PIN(96,   "MIO96"),
+	PINCTRL_PIN(97,   "MIO97"),
+	PINCTRL_PIN(98,   "MIO98"),
+	PINCTRL_PIN(99,   "MIO99"),
+	PINCTRL_PIN(100,  "MIO100"),
+	PINCTRL_PIN(101,  "MIO101"),
+	PINCTRL_PIN(102,  "MIO102"),
+	PINCTRL_PIN(103,  "MIO103"),
+	PINCTRL_PIN(104,  "MIO104"),
+	PINCTRL_PIN(105,  "MIO105"),
+	PINCTRL_PIN(106,  "MIO106"),
+	PINCTRL_PIN(107,  "MIO107"),
+	PINCTRL_PIN(108,  "MIO108"),
+	PINCTRL_PIN(109,  "MIO109"),
+	PINCTRL_PIN(110,  "MIO110"),
+	PINCTRL_PIN(111,  "MIO111"),
+	PINCTRL_PIN(112,  "MIO112"),
+	PINCTRL_PIN(113,  "MIO113"),
+	PINCTRL_PIN(114,  "MIO114"),
+	PINCTRL_PIN(115,  "MIO115"),
+	PINCTRL_PIN(116,  "MIO116"),
+	PINCTRL_PIN(117,  "MIO117"),
+	PINCTRL_PIN(118,  "MIO118"),
+	PINCTRL_PIN(119,  "MIO119"),
+	PINCTRL_PIN(120,  "MIO120"),
+	PINCTRL_PIN(121,  "MIO121"),
+	PINCTRL_PIN(122,  "MIO122"),
+	PINCTRL_PIN(123,  "MIO123"),
+	PINCTRL_PIN(124,  "MIO124"),
+	PINCTRL_PIN(125,  "MIO125"),
+	PINCTRL_PIN(126,  "MIO126"),
+	PINCTRL_PIN(127,  "MIO127"),
+	PINCTRL_PIN(128,  "MIO128"),
+	PINCTRL_PIN(129,  "MIO129"),
+	PINCTRL_PIN(130,  "MIO130"),
+	PINCTRL_PIN(131,  "MIO131"),
+	PINCTRL_PIN(132,  "MIO132"),
+	PINCTRL_PIN(133,  "MIO133"),
+	PINCTRL_PIN(134,  "MIO134"),
+	PINCTRL_PIN(135,  "MIO135"),
+	PINCTRL_PIN(136,  "MIO136"),
+	PINCTRL_PIN(137,  "MIO137"),
+	PINCTRL_PIN(138,  "MIO138"),
+	PINCTRL_PIN(139,  "MIO139"),
+	PINCTRL_PIN(140,  "MIO140"),
+	PINCTRL_PIN(141,  "MIO141"),
+	PINCTRL_PIN(142,  "MIO142"),
+	PINCTRL_PIN(143,  "MIO143"),
+	PINCTRL_PIN(144,  "MIO144"),
+	PINCTRL_PIN(145,  "MIO145"),
+	PINCTRL_PIN(146,  "MIO146"),
+	PINCTRL_PIN(147,  "MIO147"),
+	PINCTRL_PIN(148,  "MIO148"),
+	PINCTRL_PIN(149,  "MIO149"),
+	PINCTRL_PIN(150,  "MIO150"),
+	PINCTRL_PIN(151,  "MIO151"),
+	PINCTRL_PIN(152,  "MIO152"),
+	PINCTRL_PIN(153,  "MIO153"),
+	PINCTRL_PIN(154,  "MIO154"),
+	PINCTRL_PIN(155,  "MIO155"),
+	PINCTRL_PIN(156,  "MIO156"),
+};
+
+static const unsigned int lpc_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+static const unsigned int pcie_pins[] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
+static const unsigned int spif_pins[] = {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40};
+static const unsigned int emmc_pins[] = {41, 42, 43, 44};
+static const unsigned int sdio_pins[] = {45, 46, 47, 48};
+static const unsigned int eth0_pins[] = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64};
+static const unsigned int pwm0_pins[] = {65};
+static const unsigned int pwm1_pins[] = {66};
+static const unsigned int pwm2_pins[] = {67};
+static const unsigned int pwm3_pins[] = {68};
+static const unsigned int fan0_pins[] = {69};
+static const unsigned int fan1_pins[] = {70};
+static const unsigned int fan2_pins[] = {71};
+static const unsigned int fan3_pins[] = {72};
+static const unsigned int i2c0_pins[] = {73, 74};
+static const unsigned int i2c1_pins[] = {75, 76};
+static const unsigned int i2c2_pins[] = {77, 78};
+static const unsigned int i2c3_pins[] = {79, 80};
+static const unsigned int uart0_pins[] = {81, 82, 83, 84};
+static const unsigned int uart1_pins[] = {85, 86, 87, 88};
+static const unsigned int uart2_pins[] = {89, 90, 91, 92};
+static const unsigned int uart3_pins[] = {93, 94, 95, 96};
+static const unsigned int spi0_pins[] = {97, 98, 99, 100, 101};
+static const unsigned int spi1_pins[] = {102, 103, 104, 105, 106};
+static const unsigned int jtag0_pins[] = {107, 108, 109, 110, 111, 112};
+static const unsigned int jtag1_pins[] = {113, 114, 115, 116, 117, 118};
+static const unsigned int jtag2_pins[] = {119, 120, 121, 122, 123, 124};
+static const unsigned int gpio0_pins[] = {125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,\
+					 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,\
+					 151, 152, 153};
+static const unsigned int dbgi2c_pins[] = {154, 155, 156};
+
+static const char * const lpc_group[] = {"lpc_grp"};
+static const char * const pcie_group[] = {"pcie_grp"};
+static const char * const spif_group[] = {"spif_grp"};
+static const char * const emmc_group[] = {"emmc_grp"};
+static const char * const sdio_group[] = {"sdio_grp"};
+static const char * const eth0_group[] = {"eth0_grp"};
+static const char * const pwm0_group[] = {"pwm0_grp"};
+static const char * const pwm1_group[] = {"pwm1_grp"};
+static const char * const pwm2_group[] = {"pwm2_grp"};
+static const char * const pwm3_group[] = {"pwm3_grp"};
+static const char * const fan0_group[] = {"fan0_grp"};
+static const char * const fan1_group[] = {"fan1_grp"};
+static const char * const fan2_group[] = {"fan2_grp"};
+static const char * const fan3_group[] = {"fan3_grp"};
+static const char * const i2c0_group[] = {"i2c0_grp"};
+static const char * const i2c1_group[] = {"i2c1_grp"};
+static const char * const i2c2_group[] = {"i2c2_grp"};
+static const char * const i2c3_group[] = {"i2c3_grp"};
+static const char * const uart0_group[] = {"uart0_grp"};
+static const char * const uart1_group[] = {"uart1_grp"};
+static const char * const uart2_group[] = {"uart2_grp"};
+static const char * const uart3_group[] = {"uart3_grp"};
+static const char * const spi0_group[] = {"spi0_grp"};
+static const char * const spi1_group[] = {"spi1_grp"};
+static const char * const jtag0_group[] = {"jtag0_grp"};
+static const char * const jtag1_group[] = {"jtag1_grp"};
+static const char * const jtag2_group[] = {"jtag2_grp"};
+static const char * const gpio0_group[] = {"gpio0_grp"};
+static const char * const dbgi2c_group[] = {"dbgi2c_grp"};
+
+static struct mango_group mango_groups[] = {
+	PIN_GROUP(lpc),
+	PIN_GROUP(pcie),
+	PIN_GROUP(spif),
+	PIN_GROUP(emmc),
+	PIN_GROUP(sdio),
+	PIN_GROUP(eth0),
+	PIN_GROUP(pwm0),
+	PIN_GROUP(pwm1),
+	PIN_GROUP(pwm2),
+	PIN_GROUP(pwm3),
+	PIN_GROUP(fan0),
+	PIN_GROUP(fan1),
+	PIN_GROUP(fan2),
+	PIN_GROUP(fan3),
+	PIN_GROUP(i2c0),
+	PIN_GROUP(i2c1),
+	PIN_GROUP(i2c2),
+	PIN_GROUP(i2c3),
+	PIN_GROUP(uart0),
+	PIN_GROUP(uart1),
+	PIN_GROUP(uart2),
+	PIN_GROUP(uart3),
+	PIN_GROUP(spi0),
+	PIN_GROUP(spi1),
+	PIN_GROUP(jtag0),
+	PIN_GROUP(jtag1),
+	PIN_GROUP(jtag2),
+	PIN_GROUP(gpio0),
+	PIN_GROUP(dbgi2c),
+};
+
+static const struct mango_pmx_func mango_funcs[] = {
+	FUNCTION(lpc_a, lpc, FUNC_MODE0),
+	FUNCTION(lpc_r, lpc, FUNC_MODE1),
+	FUNCTION(pcie_a, pcie, FUNC_MODE0),
+	FUNCTION(pcie_r, pcie, FUNC_MODE1),
+	FUNCTION(spif_a, spif, FUNC_MODE0),
+	FUNCTION(spif_r, spif, FUNC_MODE1),
+	FUNCTION(emmc_a, emmc, FUNC_MODE0),
+	FUNCTION(emmc_r, emmc, FUNC_MODE1),
+	FUNCTION(sdio_a, sdio, FUNC_MODE0),
+	FUNCTION(sdio_r, sdio, FUNC_MODE1),
+	FUNCTION(eth0_a, eth0, FUNC_MODE1),
+	FUNCTION(eth0_r, eth0, FUNC_MODE0),
+	FUNCTION(pwm0_a, pwm0, FUNC_MODE0),
+	FUNCTION(pwm0_r, pwm0, FUNC_MODE1),
+	FUNCTION(pwm1_a, pwm1, FUNC_MODE0),
+	FUNCTION(pwm1_r, pwm1, FUNC_MODE1),
+	FUNCTION(pwm2_a, pwm2, FUNC_MODE0),
+	FUNCTION(pwm2_r, pwm2, FUNC_MODE1),
+	FUNCTION(pwm3_a, pwm3, FUNC_MODE0),
+	FUNCTION(pwm3_r, pwm3, FUNC_MODE1),
+	FUNCTION(fan0_a, fan0, FUNC_MODE1),
+	FUNCTION(fan0_r, fan0, FUNC_MODE0),
+	FUNCTION(fan1_a, fan1, FUNC_MODE1),
+	FUNCTION(fan1_r, fan1, FUNC_MODE0),
+	FUNCTION(fan2_a, fan2, FUNC_MODE1),
+	FUNCTION(fan2_r, fan2, FUNC_MODE0),
+	FUNCTION(fan3_a, fan3, FUNC_MODE1),
+	FUNCTION(fan3_r, fan3, FUNC_MODE0),
+	FUNCTION(i2c0_a, i2c0, FUNC_MODE0),
+	FUNCTION(i2c0_r, i2c0, FUNC_MODE1),
+	FUNCTION(i2c1_a, i2c1, FUNC_MODE0),
+	FUNCTION(i2c1_r, i2c1, FUNC_MODE1),
+	FUNCTION(i2c2_a, i2c2, FUNC_MODE1),
+	FUNCTION(i2c2_r, i2c2, FUNC_MODE0),
+	FUNCTION(i2c3_a, i2c3, FUNC_MODE1),
+	FUNCTION(i2c3_r, i2c3, FUNC_MODE0),
+	FUNCTION(uart0_a, uart0, FUNC_MODE0),
+	FUNCTION(uart0_r, uart0, FUNC_MODE1),
+	FUNCTION(uart1_a, uart1, FUNC_MODE0),
+	FUNCTION(uart1_r, uart1, FUNC_MODE1),
+	FUNCTION(uart2_a, uart2, FUNC_MODE1),
+	FUNCTION(uart2_r, uart2, FUNC_MODE0),
+	FUNCTION(uart3_a, uart3, FUNC_MODE1),
+	FUNCTION(uart3_r, uart3, FUNC_MODE0),
+	FUNCTION(spi0_a, spi0, FUNC_MODE1),
+	FUNCTION(spi0_r, spi0, FUNC_MODE0),
+	FUNCTION(spi1_a, spi1, FUNC_MODE0),
+	FUNCTION(spi1_r, spi1, FUNC_MODE1),
+	FUNCTION(jtag0_a, jtag0, FUNC_MODE0),
+	FUNCTION(jtag0_r, jtag0, FUNC_MODE1),
+	FUNCTION(jtag1_a, jtag1, FUNC_MODE1),
+	FUNCTION(jtag1_r, jtag1, FUNC_MODE0),
+	FUNCTION(jtag2_a, jtag2, FUNC_MODE1),
+	FUNCTION(jtag2_r, jtag2, FUNC_MODE0),
+	FUNCTION(gpio0_a, gpio0, FUNC_MODE1),
+	FUNCTION(gpio0_r, gpio0, FUNC_MODE0),
+	FUNCTION(dbgi2c_a, dbgi2c, FUNC_MODE0),
+	FUNCTION(dbgi2c_r, dbgi2c, FUNC_MODE1),
+};
+
+static struct device_attribute lpc_attr =	__ATTR(lpc, 0664, pinmux_show, pinmux_store);
+static struct device_attribute pcie_attr =	__ATTR(pcie, 0664, pinmux_show, pinmux_store);
+static struct device_attribute spif_attr =	__ATTR(spif, 0664, pinmux_show, pinmux_store);
+static struct device_attribute emmc_attr =	__ATTR(emmc, 0664, pinmux_show, pinmux_store);
+static struct device_attribute sdio_attr =	__ATTR(sdio, 0664, pinmux_show, pinmux_store);
+static struct device_attribute eth0_attr =	__ATTR(eth0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute pwm0_attr =	__ATTR(pwm0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute pwm1_attr =	__ATTR(pwm1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute pwm2_attr =	__ATTR(pwm2, 0664, pinmux_show, pinmux_store);
+static struct device_attribute pwm3_attr =	__ATTR(pwm3, 0664, pinmux_show, pinmux_store);
+static struct device_attribute fan0_attr =	__ATTR(fan0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute fan1_attr =	__ATTR(fan1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute fan2_attr =	__ATTR(fan2, 0664, pinmux_show, pinmux_store);
+static struct device_attribute fan3_attr =	__ATTR(fan3, 0664, pinmux_show, pinmux_store);
+static struct device_attribute i2c0_attr =	__ATTR(i2c0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute i2c1_attr =	__ATTR(i2c1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute i2c2_attr =	__ATTR(i2c2, 0664, pinmux_show, pinmux_store);
+static struct device_attribute i2c3_attr =	__ATTR(i2c3, 0664, pinmux_show, pinmux_store);
+static struct device_attribute uart0_attr =	__ATTR(uart0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute uart1_attr =	__ATTR(uart1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute uart2_attr =	__ATTR(uart2, 0664, pinmux_show, pinmux_store);
+static struct device_attribute uart3_attr =	__ATTR(uart3, 0664, pinmux_show, pinmux_store);
+static struct device_attribute spi0_attr =	__ATTR(spi0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute spi1_attr =	__ATTR(spi1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute jtag0_attr =	__ATTR(jtag0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute jtag1_attr =	__ATTR(jtag1, 0664, pinmux_show, pinmux_store);
+static struct device_attribute jtag2_attr =	__ATTR(jtag2, 0664, pinmux_show, pinmux_store);
+static struct device_attribute gpio0_attr =	__ATTR(gpio0, 0664, pinmux_show, pinmux_store);
+static struct device_attribute dbgi2c_attr =	__ATTR(dbgi2c, 0664, pinmux_show, pinmux_store);
+
+
+static struct attribute *pinmux_attrs[] = {
+	&lpc_attr.attr,
+	&pcie_attr.attr,
+	&spif_attr.attr,
+	&emmc_attr.attr,
+	&sdio_attr.attr,
+	&eth0_attr.attr,
+	&pwm0_attr.attr,
+	&pwm1_attr.attr,
+	&pwm2_attr.attr,
+	&pwm3_attr.attr,
+	&fan0_attr.attr,
+	&fan1_attr.attr,
+	&fan2_attr.attr,
+	&fan3_attr.attr,
+	&i2c0_attr.attr,
+	&i2c1_attr.attr,
+	&i2c2_attr.attr,
+	&i2c3_attr.attr,
+	&uart0_attr.attr,
+	&uart1_attr.attr,
+	&uart2_attr.attr,
+	&uart3_attr.attr,
+	&spi0_attr.attr,
+	&spi1_attr.attr,
+	&jtag0_attr.attr,
+	&jtag1_attr.attr,
+	&jtag2_attr.attr,
+	&gpio0_attr.attr,
+	&dbgi2c_attr.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(pinmux);
+
+static struct class  pinmux_class = {
+	.name = "pinmux",
+	.owner = THIS_MODULE,
+	.dev_groups = pinmux_groups,
+};
+
+static struct mango_soc_pinctrl_data mango_pinctrl_data = {
+	.pins = mango_pins,
+	.npins = ARRAY_SIZE(mango_pins),
+	.groups = mango_groups,
+	.groups_count = ARRAY_SIZE(mango_groups),
+	.functions = mango_funcs,
+	.functions_count = ARRAY_SIZE(mango_funcs),
+	.p_class = &pinmux_class,
+};
+
+static const struct of_device_id mango_pinctrl_of_table[] = {
+	{
+		.compatible = "sophgo, pinctrl-mango",
+		.data = &mango_pinctrl_data,
+	},
+	{}
+};
+
+static int mango_pinctrl_probe(struct platform_device *pdev)
+{
+	return sophgo_pinctrl_probe(pdev);
+}
+
+static struct platform_driver mango_pinctrl_driver = {
+	.probe = mango_pinctrl_probe,
+	.driver = {
+		.name = DRV_PINCTRL_NAME,
+		.of_match_table = of_match_ptr(mango_pinctrl_of_table),
+	},
+};
+
+static int __init mango_pinctrl_init(void)
+{
+	return platform_driver_register(&mango_pinctrl_driver);
+}
+postcore_initcall(mango_pinctrl_init);
+
diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.c b/drivers/pinctrl/sophgo/pinctrl-sophgo.c
new file mode 100644
index 000000000000..4d5738786e9a
--- /dev/null
+++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.c
@@ -0,0 +1,293 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "pinctrl-sophgo.h"
+
+
+static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
+		const char * const **groups,
+		unsigned int * const num_groups);
+
+static struct mango_soc_pinctrl_data *get_pinmux_data(struct pinctrl_dev *pctldev)
+{
+	struct mango_pinctrl *mangopctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	return mangopctrl->data;
+}
+
+static int mango_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	return data->functions_count;
+}
+
+static const char *mango_get_fname(struct pinctrl_dev *pctldev,
+		unsigned int selector)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	return data->functions[selector].name;
+}
+
+static int mango_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
+		unsigned int group)
+{
+	int p;
+	unsigned int pidx;
+	u32 offset, regval, mux_offset;
+	struct mango_pinctrl *ctrl = pinctrl_dev_get_drvdata(pctldev);
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	data->groups[group].cur_func_idx = data->functions[selector].mode;
+	for (p = 0; p < data->groups[group].num_pins; p++) {
+		pidx = data->groups[group].pins[p];
+		offset = (pidx >> 1) << 2;
+		regmap_read(ctrl->syscon_pinctl,
+			ctrl->top_pinctl_offset + offset, &regval);
+		mux_offset = ((!((pidx + 1) & 1) << 4) + 4);
+
+		regval = regval & ~(3 << mux_offset);
+		regval |= data->functions[selector].mode << mux_offset;
+		regmap_write(ctrl->syscon_pinctl,
+			ctrl->top_pinctl_offset + offset, regval);
+		regmap_read(ctrl->syscon_pinctl,
+			ctrl->top_pinctl_offset + offset, &regval);
+		dev_dbg(ctrl->dev, "%s : check new reg=0x%x val=0x%x\n",
+			data->groups[group].name,
+			ctrl->top_pinctl_offset + offset, regval);
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops mango_pinmux_ops = {
+	.get_functions_count = mango_get_functions_count,
+	.get_function_name = mango_get_fname,
+	.get_function_groups = mango_get_groups,
+	.set_mux = mango_set_mux,
+	.strict = true,
+};
+
+static int mango_pinconf_cfg_get(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *config)
+{
+	return 0;
+}
+
+static int mango_pinconf_cfg_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	return 0;
+}
+
+static int mango_pinconf_group_set(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned long *configs, unsigned int num_configs)
+{
+	return 0;
+}
+
+static const struct pinconf_ops mango_pinconf_ops = {
+	.is_generic = true,
+	.pin_config_get = mango_pinconf_cfg_get,
+	.pin_config_set = mango_pinconf_cfg_set,
+	.pin_config_group_set = mango_pinconf_group_set,
+};
+
+static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
+		const char * const **groups,
+		unsigned int * const num_groups)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	*groups = data->functions[selector].groups;
+	*num_groups = data->functions[selector].num_groups;
+
+	return 0;
+}
+
+static int mango_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	return data->groups_count;
+}
+
+static const char *mango_get_group_name(struct pinctrl_dev *pctldev,
+					   unsigned int selector)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	return data->groups[selector].name;
+}
+
+static int mango_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
+		const unsigned int **pins,
+		unsigned int *num_pins)
+{
+	struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
+
+	*pins = data->groups[selector].pins;
+	*num_pins = data->groups[selector].num_pins;
+
+	return 0;
+}
+
+static void mango_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+	unsigned int offset)
+{
+}
+
+static const struct pinctrl_ops mango_pctrl_ops = {
+	.get_groups_count = mango_get_groups_count,
+	.get_group_name = mango_get_group_name,
+	.get_group_pins = mango_get_group_pins,
+	.pin_dbg_show = mango_pin_dbg_show,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinctrl_utils_free_map,
+};
+
+static struct pinctrl_desc mango_desc = {
+	.name = "mango_pinctrl",
+	.pctlops = &mango_pctrl_ops,
+	.pmxops = &mango_pinmux_ops,
+	.confops = &mango_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+ssize_t pinmux_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct mango_pinctrl *mangopctrl;
+	int p, ret, group, selector = -1;
+	struct mango_soc_pinctrl_data *data;
+
+	mangopctrl = dev_get_drvdata(dev);
+	data = (struct mango_soc_pinctrl_data *)mangopctrl->data;
+
+	for (p = 0; p < data->functions_count; p++) {
+		if (!strncmp(attr->attr.name, data->functions[p].name,
+			 strlen(attr->attr.name))) {
+			selector = p;
+			break;
+		}
+	}
+	if (selector < 0)
+		return -ENXIO;
+
+	group = selector/2;
+	ret = snprintf(buf, 128, "%d\n", data->groups[group].cur_func_idx);
+	if (ret <= 0 || ret > 128) {
+		dev_err(dev, "snprintf failed %d\n", ret);
+		return -EFAULT;
+	}
+	return ret;
+}
+
+ssize_t pinmux_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct mango_pinctrl *mangopctrl;
+	int p, ret, group, selector = -1;
+	unsigned long user_data;
+	struct mango_soc_pinctrl_data *data;
+
+	ret = kstrtoul(buf, 0, &user_data);
+	if (ret)
+		return -EINVAL;
+
+	if (user_data != 0 && user_data != 1)
+		return -EINVAL;
+
+	mangopctrl = dev_get_drvdata(dev);
+	data = (struct mango_soc_pinctrl_data *)mangopctrl->data;
+
+	for (p = 0; p < data->functions_count; p++) {
+		if (!strncmp(attr->attr.name, data->functions[p].name,
+				strlen(attr->attr.name)) &&
+				(user_data == data->functions[p].mode)) {
+			selector = p;
+			break;
+		}
+	}
+	if (selector < 0)
+		return -ENXIO;
+
+	group = selector/2;
+	mango_set_mux(mangopctrl->pctl, selector, group);
+
+	dev_info(dev, "pinmux store set %s to func %d\n",
+			attr->attr.name, data->functions[selector].mode);
+	return size;
+}
+
+
+int sophgo_pinctrl_probe(struct platform_device *pdev)
+{
+	struct mango_pinctrl *mangopctrl;
+	struct pinctrl_desc *desc;
+	struct mango_soc_pinctrl_data *data;
+	struct device *dev = &pdev->dev;
+	struct device *pin_dev = NULL;
+	struct device_node *np = dev->of_node, *np_top;
+	static struct regmap *syscon;
+	int ret;
+
+	data = (struct mango_soc_pinctrl_data *)of_device_get_match_data(&pdev->dev);
+	if (!data)
+		return -EINVAL;
+	mangopctrl = devm_kzalloc(&pdev->dev, sizeof(*mangopctrl), GFP_KERNEL);
+	if (!mangopctrl)
+		return -ENOMEM;
+
+	mangopctrl->dev = &pdev->dev;
+
+	np_top = of_parse_phandle(np, "subctrl-syscon", 0);
+	if (!np_top) {
+		dev_err(dev, "%s can't get subctrl-syscon node\n", __func__);
+		return -EINVAL;
+	}
+	syscon = syscon_node_to_regmap(np_top);
+	if (IS_ERR(syscon)) {
+		dev_err(dev, "cannot get regmap\n");
+		return PTR_ERR(syscon);
+	}
+	mangopctrl->syscon_pinctl = syscon;
+
+	ret = device_property_read_u32(&pdev->dev,
+		"top_pinctl_offset", &mangopctrl->top_pinctl_offset);
+	if (ret < 0) {
+		dev_err(dev, "cannot get top_pinctl_offset\n");
+		return ret;
+	}
+
+	desc = &mango_desc;
+	desc->pins = data->pins;
+	desc->npins = data->npins;
+
+	mangopctrl->data = (void *)data;
+	mangopctrl->pctl = devm_pinctrl_register(&pdev->dev, desc, mangopctrl);
+	if (IS_ERR(mangopctrl->pctl)) {
+		dev_err(&pdev->dev, "could not register Sophgo pin ctrl driver\n");
+		return PTR_ERR(mangopctrl->pctl);
+	}
+
+	platform_set_drvdata(pdev, mangopctrl);
+
+	ret = class_register(data->p_class);
+	if (ret < 0) {
+		dev_err(dev, "cannot register pinmux class\n");
+		return ret;
+	}
+	pin_dev = device_create(data->p_class, &pdev->dev, MKDEV(0, 0), mangopctrl, "mango_pinmux");
+	if (IS_ERR(pin_dev))
+		return PTR_ERR(pin_dev);
+
+	return 0;
+}
+
diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h
new file mode 100644
index 000000000000..f3a30f0275b1
--- /dev/null
+++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h
@@ -0,0 +1,70 @@
+#ifndef __mango_PINCTRL_CORE_H__
+#define __mango_PINCTRL_CORE_H__
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include "../pinctrl-utils.h"
+#include "../core.h"
+
+enum FUNC_MODE {
+	FUNC_MODE0,
+	FUNC_MODE1,
+	FUNC_MODE2,
+	FUNC_MODE3,
+	FUNC_MASK,
+};
+
+struct mango_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	u32 top_pinctl_offset;
+	struct regmap *syscon_pinctl;
+	void *data;
+};
+
+struct mango_group {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned int num_pins;
+	int cur_func_idx;
+	struct mango_pmx_func *funcs;
+};
+
+struct mango_pmx_func {
+	const char *name;
+	const char * const *groups;
+	unsigned int num_groups;
+	enum FUNC_MODE mode;
+};
+
+struct mango_soc_pinmux_info {
+	const char name[16];
+	const char name_a[16];
+	const char name_r[16];
+	struct pinctrl_state *pinctrl_a;
+	struct pinctrl_state *pinctrl_r;
+	const unsigned int def_state; /* default state */
+	int (*set)(struct device *dev, unsigned int data);
+};
+
+struct mango_soc_pinctrl_data {
+	const struct pinctrl_pin_desc *pins;
+	unsigned int npins;
+	struct mango_group *groups;
+	int groups_count;
+	const struct mango_pmx_func *functions;
+	int functions_count;
+	struct class *p_class;
+};
+
+int sophgo_pinctrl_probe(struct platform_device *pdev);
+int mango_pmux_probe(struct platform_device *pdev);
+
+ssize_t pinmux_show(struct device *dev,
+			struct device_attribute *attr, char *buf);
+
+ssize_t pinmux_store(struct device *dev,
+			struct device_attribute *attr, const char *buf, size_t size);
+#endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 7bf1a29f02b8..9d6823d3b03a 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_SL28CPLD)	+= pwm-sl28cpld.o
+obj-$(CONFIG_ARCH_SOPHGO)	+= pwm-sophgo.o
 obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
 obj-$(CONFIG_PWM_SPRD)		+= pwm-sprd.o
 obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
diff --git a/drivers/pwm/pwm-sophgo.c b/drivers/pwm/pwm-sophgo.c
new file mode 100644
index 000000000000..b6297175a5b7
--- /dev/null
+++ b/drivers/pwm/pwm-sophgo.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2007 Ben Dooks
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * PWM driver for Samsung SoCs
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+
+
+#define REG_HLPERIOD		0x0
+#define REG_PERIOD			0x4
+#define REG_GROUP			0x8
+#define REG_POLARITY		0x20
+
+
+/**
+ * struct sophgo_pwm_channel - private data of PWM channel
+ * @period_ns:	current period in nanoseconds programmed to the hardware
+ * @duty_ns:	current duty time in nanoseconds programmed to the hardware
+ * @tin_ns:	time of one timer tick in nanoseconds with current timer rate
+ */
+struct sophgo_pwm_channel {
+	u32 period;
+	u32 hlperiod;
+};
+
+/**
+ * struct sophgo_pwm_chip - private data of PWM chip
+ * @chip:		generic PWM chip
+ * @variant:		local copy of hardware variant data
+ * @inverter_mask:	inverter status for all channels - one bit per channel
+ * @base:		base address of mapped PWM registers
+ * @base_clk:		base clock used to drive the timers
+ * @tclk0:		external clock 0 (can be ERR_PTR if not present)
+ * @tclk1:		external clock 1 (can be ERR_PTR if not present)
+ */
+struct sophgo_pwm_chip {
+	struct pwm_chip chip;
+	void __iomem *base;
+	struct clk *base_clk;
+	u8 polarity_mask;
+	bool no_polarity;
+};
+
+
+static inline
+struct sophgo_pwm_chip *to_sophgo_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct sophgo_pwm_chip, chip);
+}
+
+static int pwm_sophgo_request(struct pwm_chip *chip, struct pwm_device *pwm_dev)
+{
+	struct sophgo_pwm_channel *channel;
+
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (!channel)
+		return -ENOMEM;
+
+	return pwm_set_chip_data(pwm_dev, channel);
+}
+
+static void pwm_sophgo_free(struct pwm_chip *chip, struct pwm_device *pwm_dev)
+{
+	struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
+
+	pwm_set_chip_data(pwm_dev, NULL);
+	kfree(channel);
+}
+
+static int pwm_sophgo_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
+			     int duty_ns, int period_ns)
+{
+	struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
+	struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
+	u64 cycles;
+
+	cycles = clk_get_rate(our_chip->base_clk);
+	cycles *= period_ns;
+	do_div(cycles, NSEC_PER_SEC);
+
+	channel->period = cycles;
+	cycles = cycles * duty_ns;
+	do_div(cycles, period_ns);
+	channel->hlperiod = channel->period - cycles;
+
+	return 0;
+}
+
+static int pwm_sophgo_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
+{
+	struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
+	struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
+
+	writel(channel->period, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD);
+	writel(channel->hlperiod, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD);
+
+	return 0;
+}
+
+static void pwm_sophgo_disable(struct pwm_chip *chip,
+			       struct pwm_device *pwm_dev)
+{
+	struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
+
+	writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD);
+	writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD);
+}
+
+static int pwm_sophgo_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			      const struct pwm_state *state)
+{
+	int ret;
+
+	bool enabled = pwm->state.enabled;
+
+	if (state->polarity != pwm->state.polarity && pwm->state.enabled) {
+		pwm_sophgo_disable(chip, pwm);
+		enabled = false;
+	}
+
+	if (!state->enabled) {
+		if (enabled)
+			pwm_sophgo_disable(chip, pwm);
+		return 0;
+	}
+
+	ret = pwm_sophgo_config(chip, pwm, state->duty_cycle, state->period);
+	if (ret) {
+		dev_err(chip->dev, "pwm apply err\n");
+		return ret;
+	}
+	dev_dbg(chip->dev, "%s tate->enabled =%d\n", __func__, state->enabled);
+	if (state->enabled)
+		ret = pwm_sophgo_enable(chip, pwm);
+	else
+		pwm_sophgo_disable(chip, pwm);
+
+	if (ret) {
+		dev_err(chip->dev, "pwm apply failed\n");
+		return ret;
+	}
+	return ret;
+}
+
+static const struct pwm_ops pwm_sophgo_ops = {
+	.request	= pwm_sophgo_request,
+	.free		= pwm_sophgo_free,
+	.apply		= pwm_sophgo_apply,
+	.owner		= THIS_MODULE,
+};
+
+static const struct of_device_id sophgo_pwm_match[] = {
+	{ .compatible = "sophgo,sophgo-pwm" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sophgo_pwm_match);
+
+static int pwm_sophgo_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sophgo_pwm_chip *chip;
+	struct resource *res;
+	int ret;
+
+	pr_info("%s\n", __func__);
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	chip->chip.dev = &pdev->dev;
+	chip->chip.ops = &pwm_sophgo_ops;
+	chip->chip.base = -1;
+	chip->polarity_mask = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	chip->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(chip->base))
+		return PTR_ERR(chip->base);
+
+	chip->base_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(chip->base_clk)) {
+		dev_err(dev, "failed to get pwm source clk\n");
+		return PTR_ERR(chip->base_clk);
+	}
+
+	ret = clk_prepare_enable(chip->base_clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable base clock\n");
+		return ret;
+	}
+
+	//pwm-num default is 4, compatible with sg2042
+	if (of_property_read_bool(pdev->dev.of_node, "pwm-num"))
+		device_property_read_u32(&pdev->dev, "pwm-num", &chip->chip.npwm);
+	else
+		chip->chip.npwm = 4;
+
+	//no_polarity default is false(have polarity) , compatible with sg2042
+	if (of_property_read_bool(pdev->dev.of_node, "no-polarity"))
+		chip->no_polarity = true;
+	else
+		chip->no_polarity = false;
+	pr_debug("chip->chip.npwm =%d  chip->no_polarity=%d\n", chip->chip.npwm, chip->no_polarity);
+
+	platform_set_drvdata(pdev, chip);
+
+	ret = pwmchip_add(&chip->chip);
+	if (ret < 0) {
+		dev_err(dev, "failed to register PWM chip\n");
+		clk_disable_unprepare(chip->base_clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pwm_sophgo_remove(struct platform_device *pdev)
+{
+	struct sophgo_pwm_chip *chip = platform_get_drvdata(pdev);
+
+	pwmchip_remove(&chip->chip);
+
+	clk_disable_unprepare(chip->base_clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pwm_sophgo_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int pwm_sophgo_resume(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pwm_sophgo_pm_ops, pwm_sophgo_suspend,
+			 pwm_sophgo_resume);
+
+static struct platform_driver pwm_sophgo_driver = {
+	.driver		= {
+		.name	= "sophgo-pwm",
+		.pm	= &pwm_sophgo_pm_ops,
+		.of_match_table = of_match_ptr(sophgo_pwm_match),
+	},
+	.probe		= pwm_sophgo_probe,
+	.remove		= pwm_sophgo_remove,
+};
+module_platform_driver(pwm_sophgo_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("chunzhi.lin");
+MODULE_DESCRIPTION("Sophgo PWM driver");
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 3e7e5fd633a8..0b40e8506804 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -41,3 +41,4 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
 obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
+obj-$(CONFIG_ARCH_SOPHGO) += reset-sophgo.o
diff --git a/drivers/reset/reset-sophgo.c b/drivers/reset/reset-sophgo.c
new file mode 100644
index 000000000000..3c46a43e24ba
--- /dev/null
+++ b/drivers/reset/reset-sophgo.c
@@ -0,0 +1,163 @@
+/*
+ * Sophgo SoCs Reset Controller driver
+ *
+ * Copyright (c) 2018 Bitmain Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#define BITS_PER_REG	32
+
+struct bm_reset_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+	struct regmap		*syscon_rst;
+	u32			top_rst_offset;
+};
+
+static int bm_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct bm_reset_data *data = container_of(rcdev,
+						     struct bm_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_REG;
+	int offset = id % BITS_PER_REG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4),
+		&reg);
+	regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4),
+		reg & ~BIT(offset));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int bm_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct bm_reset_data *data = container_of(rcdev,
+						     struct bm_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_REG;
+	int offset = id % BITS_PER_REG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4),
+		&reg);
+	regmap_write(data->syscon_rst,  data->top_rst_offset + (bank * 4),
+		reg | BIT(offset));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static const struct reset_control_ops bm_reset_ops = {
+	.assert		= bm_reset_assert,
+	.deassert	= bm_reset_deassert,
+};
+
+static const struct of_device_id bm_reset_dt_ids[] = {
+	 { .compatible = "bitmain,reset", },
+	 { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, bm_reset_dt_ids);
+
+static int bm_reset_probe(struct platform_device *pdev)
+{
+	struct bm_reset_data *data;
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node, *np_top;
+	static struct regmap *syscon;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	np_top = of_parse_phandle(np, "subctrl-syscon", 0);
+	if (!np_top) {
+		dev_err(dev, "%s can't get subctrl-syscon node\n", __func__);
+		goto out_free_devm;
+	}
+
+	syscon = syscon_node_to_regmap(np_top);
+	if (IS_ERR(syscon)) {
+		dev_err(dev, "cannot get regmap\n");
+		goto out_free_devm;
+	}
+
+	data->syscon_rst = syscon;
+	ret = device_property_read_u32(&pdev->dev, "top_rst_offset",
+		&data->top_rst_offset);
+	if (ret < 0) {
+		dev_err(dev, "cannot get top_rst_offset\n");
+		goto out_free_devm;
+	}
+
+	ret = device_property_read_u32(&pdev->dev, "nr_resets",
+		&data->rcdev.nr_resets);
+	if (ret < 0) {
+		dev_err(dev, "cannot get nr_resets\n");
+		goto out_free_devm;
+	}
+
+	spin_lock_init(&data->lock);
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.ops = &bm_reset_ops;
+	data->rcdev.of_node = pdev->dev.of_node;
+
+	ret = devm_reset_controller_register(&pdev->dev, &data->rcdev);
+	if (!ret)
+		return 0;
+
+out_free_devm:
+	devm_kfree(&pdev->dev, data);
+	return ret;
+}
+
+static struct platform_driver bm_reset_driver = {
+	.probe	= bm_reset_probe,
+	.driver = {
+		.name		= "bm-reset",
+		.of_match_table	= bm_reset_dt_ids,
+	},
+};
+
+static int __init bm_reset_init(void)
+{
+	return platform_driver_register(&bm_reset_driver);
+}
+postcore_initcall(bm_reset_init);
+
+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>");
+MODULE_DESCRIPTION("Bitmain SoC Reset Controoler Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index bb63edb507da..509f8afb281d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1995,4 +1995,10 @@ config RTC_DRV_POLARFIRE_SOC
 	  This driver can also be built as a module, if so, the module
 	  will be called "rtc-mpfs".
 
+config RTC_DRV_ASTBMC
+	tristate "SG2042 server get rtc time from bmc via pci bus"
+	help
+	  This driver can also be built as a module, if so, the module
+	  will be called "rtc-astbmc".
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index aab22bc63432..70397a346e0d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -186,3 +186,4 @@ obj-$(CONFIG_RTC_DRV_WM8350)	+= rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_XGENE)	+= rtc-xgene.o
 obj-$(CONFIG_RTC_DRV_ZYNQMP)	+= rtc-zynqmp.o
+obj-$(CONFIG_RTC_DRV_ASTBMC)	+= rtc-astbmc.o
diff --git a/drivers/rtc/rtc-astbmc.c b/drivers/rtc/rtc-astbmc.c
new file mode 100644
index 000000000000..21863aa126fb
--- /dev/null
+++ b/drivers/rtc/rtc-astbmc.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* rtc-astbmc.c
+ *
+ * Driver for Dallas Semiconductor astbmcrtc Low Current, PCI Compatible
+ * Real Time Clock
+ *
+ * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/regmap.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/jiffies.h>
+
+/* Registers in astbmcrtc rtc */
+
+#define ASPEED_PCI_BMC_HOST2BMC_Q1		0x30000
+#define ASPEED_PCI_BMC_HOST2BMC_Q2		0x30010
+#define ASPEED_PCI_BMC_BMC2HOST_Q1		0x30020
+#define ASPEED_PCI_BMC_BMC2HOST_Q2		0x30030
+#define ASPEED_PCI_BMC_BMC2HOST_STS		0x30040
+#define	 BMC2HOST_INT_STS_DOORBELL		BIT(31)
+#define	 BMC2HOST_ENABLE_INTB			BIT(30)
+/* */
+#define	 BMC2HOST_Q1_FULL				BIT(27)
+#define	 BMC2HOST_Q1_EMPTY				BIT(26)
+#define	 BMC2HOST_Q2_FULL				BIT(25)
+#define	 BMC2HOST_Q2_EMPTY				BIT(24)
+#define	 BMC2HOST_Q1_FULL_UNMASK		BIT(23)
+#define	 BMC2HOST_Q1_EMPTY_UNMASK		BIT(22)
+#define	 BMC2HOST_Q2_FULL_UNMASK		BIT(21)
+#define	 BMC2HOST_Q2_EMPTY_UNMASK		BIT(20)
+
+#define ASPEED_PCI_BMC_HOST2BMC_STS		0x30044
+#define	 HOST2BMC_INT_STS_DOORBELL		BIT(31)
+#define	 HOST2BMC_ENABLE_INTB			BIT(30)
+/* */
+#define	 HOST2BMC_Q1_FULL				BIT(27)
+#define	 HOST2BMC_Q1_EMPTY				BIT(26)
+#define	 HOST2BMC_Q2_FULL				BIT(25)
+#define	 HOST2BMC_Q2_EMPTY				BIT(24)
+#define	 HOST2BMC_Q1_FULL_UNMASK		BIT(23)
+#define	 HOST2BMC_Q1_EMPTY_UNMASK		BIT(22)
+#define	 HOST2BMC_Q2_FULL_UNMASK		BIT(21)
+#define	 HOST2BMC_Q2_EMPTY_UNMASK		BIT(20)
+
+struct aspeed_pci_bmc_dev {
+	struct device *dev;
+	struct miscdevice miscdev;
+
+	unsigned long mem_bar_base;
+	unsigned long mem_bar_size;
+	void __iomem *mem_bar_reg;
+
+	unsigned long message_bar_base;
+	unsigned long message_bar_size;
+	void __iomem *msg_bar_reg;
+
+	struct bin_attribute	bin0;
+	struct bin_attribute	bin1;
+
+	struct kernfs_node	*kn0;
+	struct kernfs_node	*kn1;
+
+	/* Queue waiters for idle engine */
+	wait_queue_head_t tx_wait0;
+	wait_queue_head_t tx_wait1;
+	wait_queue_head_t rx_wait0;
+	wait_queue_head_t rx_wait1;
+
+	void __iomem *sio_mbox_reg;
+	int sio_mbox_irq;
+
+	u8 IntLine;
+	int legency_irq;
+};
+
+#define HOST_BMC_QUEUE_SIZE			(16 * 4)
+#define PCIE_DEVICE_SIO_ADDR		(0x2E * 4)
+#define BMC_MULTI_MSI	32
+
+#define DRIVER_NAME "ASPEED BMC DEVICE"
+
+static struct rtc_device *rtc;
+static int time64_flag = 1;
+module_param(time64_flag, int, 0644);
+
+static struct aspeed_pci_bmc_dev *file_aspeed_bmc_device(struct file *file)
+{
+	return container_of(file->private_data, struct aspeed_pci_bmc_dev,
+			miscdev);
+}
+
+static int aspeed_pci_bmc_dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = file_aspeed_bmc_device(file);
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	pgprot_t prot = vma->vm_page_prot;
+
+	if (vma->vm_pgoff + vsize > pci_bmc_dev->mem_bar_base + 0x100000)
+		return -EINVAL;
+
+	prot = pgprot_noncached(prot);
+
+	if (remap_pfn_range(vma, vma->vm_start,
+		(pci_bmc_dev->mem_bar_base >> PAGE_SHIFT) + vma->vm_pgoff,
+		vsize, prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static const struct file_operations aspeed_pci_bmc_dev_fops = {
+	.owner		= THIS_MODULE,
+	.mmap		= aspeed_pci_bmc_dev_mmap,
+};
+
+
+static irqreturn_t aspeed_pci_host_bmc_device_interrupt(int irq, void *dev_id)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id;
+	u32 bmc2host_q_sts = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
+
+	if (bmc2host_q_sts & BMC2HOST_INT_STS_DOORBELL)
+		writel(BMC2HOST_INT_STS_DOORBELL, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
+
+	if (bmc2host_q_sts & BMC2HOST_ENABLE_INTB)
+		writel(BMC2HOST_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS);
+
+	if (bmc2host_q_sts & BMC2HOST_Q1_FULL)
+		dev_info(pci_bmc_device->dev, "Q1 Full\n");
+
+	if (bmc2host_q_sts & BMC2HOST_Q2_FULL)
+		dev_info(pci_bmc_device->dev, "Q2 Full\n");
+
+
+	//check q1
+	if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL))
+		wake_up_interruptible(&pci_bmc_device->tx_wait0);
+
+	if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY))
+		wake_up_interruptible(&pci_bmc_device->rx_wait0);
+	//chech q2
+	if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL))
+		wake_up_interruptible(&pci_bmc_device->tx_wait1);
+
+	if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY))
+		wake_up_interruptible(&pci_bmc_device->rx_wait1);
+
+	return IRQ_HANDLED;
+
+}
+
+
+static int clear_r_queue1(struct device *dev, int timeout)
+{
+	u32 value;
+	unsigned long tick_end = jiffies + timeout * HZ;
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	while (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) {
+		value = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
+		writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+
+		if (time_after(jiffies, tick_end)) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+
+
+static ssize_t read_8bytes_from_queue1(struct device *dev, time64_t * time_stamp, int timeout)
+{
+	int i = 0;
+	u32 * time_buf = (u32*)time_stamp;
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	unsigned long tick_end = jiffies + timeout * HZ;
+
+	while (i < 2) {
+		if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) {
+			time_buf[i++] = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
+			writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+		}
+
+		if (time_after(jiffies, tick_end)) {
+			return 0;
+		}
+	}
+	return sizeof(time64_t);
+}
+
+static ssize_t read_queue1(struct device *dev, u32 * data)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	int ret;
+
+	ret = wait_event_interruptible(pci_bmc_device->rx_wait0,
+		!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY));
+	if (ret)
+		return -EINTR;
+
+	* data = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1);
+	writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+	return sizeof(u32);
+}
+static ssize_t write_queue1(struct device *dev, u32 data)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	int ret;
+
+	ret = wait_event_interruptible(pci_bmc_device->tx_wait0,
+		!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL));
+	if (ret)
+		return -EINTR;
+
+	writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q1);
+	//trigger to host
+	writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+
+	return sizeof(u32);
+}
+
+static ssize_t read_queue2(struct device *dev, u32 * timestamp)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	int ret;
+
+	ret = wait_event_interruptible(pci_bmc_device->rx_wait1,
+		!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY));
+	if (ret)
+		return -EINTR;
+
+	* timestamp = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q2);
+	writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+	return sizeof(u32);
+}
+static ssize_t write_queue2(struct device *dev, u32 data)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+	int ret;
+
+	ret = wait_event_interruptible(pci_bmc_device->tx_wait1,
+		!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL));
+	if (ret)
+		return -EINTR;
+
+	writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2);
+	//trigger to host
+	writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+
+
+	return sizeof(u32);
+}
+
+static ssize_t write_8bytes_to_queue2(struct device *dev, time64_t * time_stamp)
+{
+	int i = 0;
+	u32 * time_buf = (u32*)time_stamp;
+	struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev);
+
+	while (i < 2) {
+		if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) {
+			writel(time_buf[i++], pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2);
+			writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS);
+
+		}
+	}
+	return sizeof(time64_t);
+}
+
+
+
+static int astbmc_read_time(struct device *dev, struct rtc_time *dt)
+{
+	time64_t time_stamp = 0;
+	u32 tx_cmd = 0x55555555;
+
+	clear_r_queue1(dev, 5);
+
+    write_queue1(dev, tx_cmd);
+
+	read_8bytes_from_queue1(dev, &time_stamp, 5);
+
+	rtc_time64_to_tm(time_stamp, dt);
+
+	return 0;
+}
+
+static int astbmc_set_time(struct device *dev, struct rtc_time *dt)
+{
+	time64_t time_stamp = 0;
+	u32 tx_cmd = 0xaaaaaaaa;
+
+	write_queue2(dev, tx_cmd);
+
+	time_stamp = rtc_tm_to_time64(dt);
+
+	write_8bytes_to_queue2(dev, &time_stamp);
+
+	return 0;
+}
+
+static const struct rtc_class_ops astbmc_rtc_ops = {
+	.read_time = astbmc_read_time,
+	.set_time = astbmc_set_time,
+};
+
+
+//0-unenabled 1-enabled
+static int is_bmc_rtc_device_func_enable(struct device *dev)
+{
+	time64_t time_stamp = 0;
+	u32 tx_cmd = 0x55555555;
+
+	clear_r_queue1(dev, 5);
+
+    write_queue1(dev, tx_cmd);
+
+	if (read_8bytes_from_queue1(dev, &time_stamp, 5) == 0) {
+		pr_info("BMC has not enabled rtc device func!\n");
+		return 0;
+	}
+
+	pr_info("BMC has enabled rtc device func!\n");
+	return 1;
+
+}
+
+
+#define BMC_MSI_IDX_BASE	0
+static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev;
+	struct device *dev = &pdev->dev;
+	u16 config_cmd_val;
+	int nr_entries;
+	int rc = 0;
+
+	pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);
+
+	pci_bmc_dev = kzalloc(sizeof(*pci_bmc_dev), GFP_KERNEL);
+	if (!pci_bmc_dev) {
+		rc = -ENOMEM;
+		dev_err(&pdev->dev, "kmalloc() returned NULL memory.\n");
+		goto out_err;
+	}
+
+	rc = pci_enable_device(pdev);
+	if (rc != 0) {
+		dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
+		goto out_err;
+	}
+
+	/* set PCI host mastering  */
+	pci_set_master(pdev);
+
+	nr_entries = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+	if (nr_entries < 0) {
+		pci_bmc_dev->legency_irq = 1;
+		pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val);
+		config_cmd_val &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val);
+
+	} else {
+		pci_bmc_dev->legency_irq = 0;
+		pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val);
+		config_cmd_val |= PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val);
+		pdev->irq = pci_irq_vector(pdev, BMC_MSI_IDX_BASE);
+	}
+
+	pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);
+
+	init_waitqueue_head(&pci_bmc_dev->tx_wait0);
+	init_waitqueue_head(&pci_bmc_dev->tx_wait1);
+	init_waitqueue_head(&pci_bmc_dev->rx_wait0);
+	init_waitqueue_head(&pci_bmc_dev->rx_wait1);
+
+	//Get MEM bar
+	pci_bmc_dev->mem_bar_base = pci_resource_start(pdev, 0);
+	pci_bmc_dev->mem_bar_size = pci_resource_len(pdev, 0);
+
+	pr_info("BAR0 I/O Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->mem_bar_base, pci_bmc_dev->mem_bar_size);
+
+	pci_bmc_dev->mem_bar_reg = pci_ioremap_bar(pdev, 0);
+	if (!pci_bmc_dev->mem_bar_reg) {
+		rc = -ENOMEM;
+		goto out_free0;
+	}
+
+    //Get MSG BAR info
+	pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
+	pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
+
+	pr_info("MSG BAR1 Memory Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->message_bar_base, pci_bmc_dev->message_bar_size);
+
+	pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
+	if (!pci_bmc_dev->msg_bar_reg) {
+		rc = -ENOMEM;
+		goto out_free1;
+	}
+
+	/* ERRTA40: dummy read */
+	(void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
+
+
+	pci_bmc_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+	pci_bmc_dev->miscdev.name = DRIVER_NAME;
+	pci_bmc_dev->miscdev.fops = &aspeed_pci_bmc_dev_fops;
+	pci_bmc_dev->miscdev.parent = dev;
+
+	rc = misc_register(&pci_bmc_dev->miscdev);
+	if (rc) {
+		pr_err("host bmc register fail %d\n", rc);
+		goto out_free;
+	}
+
+	pci_set_drvdata(pdev, pci_bmc_dev);
+
+	rc = request_irq(pdev->irq, aspeed_pci_host_bmc_device_interrupt, IRQF_SHARED, "ASPEED BMC DEVICE", pci_bmc_dev);
+	if (rc) {
+		pr_err("host bmc device Unable to get IRQ %d\n", rc);
+		goto out_unreg;
+	}
+
+	if (!is_bmc_rtc_device_func_enable(dev))
+		return 0;
+
+    //register rtc device
+    rtc = devm_rtc_allocate_device(dev);
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
+
+	rtc->ops = &astbmc_rtc_ops;
+	rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;
+	rtc->range_max = RTC_TIMESTAMP_END_9999;
+
+	devm_rtc_register_device(rtc);
+
+	return 0;
+
+out_unreg:
+	misc_deregister(&pci_bmc_dev->miscdev);
+out_free1:
+	pci_release_region(pdev, 1);
+out_free0:
+	pci_release_region(pdev, 0);
+out_free:
+	kfree(pci_bmc_dev);
+out_err:
+	pci_disable_device(pdev);
+
+	return rc;
+
+}
+
+
+
+static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
+{
+	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
+
+	free_irq(pdev->irq, pdev);
+	misc_deregister(&pci_bmc_dev->miscdev);
+	pci_release_regions(pdev);
+	kfree(pci_bmc_dev);
+	pci_disable_device(pdev);
+}
+
+/**
+ * This table holds the list of (VendorID,DeviceID) supported by this driver
+ *
+ */
+static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
+	{ PCI_DEVICE(0x1A03, 0x2402), },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
+
+static struct pci_driver aspeed_host_bmc_dev_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= aspeed_host_bmc_dev_pci_ids,
+	.probe		= aspeed_pci_host_bmc_device_probe,
+	.remove		= aspeed_pci_host_bmc_device_remove,
+};
+
+static int __init aspeed_host_bmc_device_init(void)
+{
+	int ret;
+
+	/* register pci driver */
+	ret = pci_register_driver(&aspeed_host_bmc_dev_driver);
+	if (ret < 0) {
+		pr_err("pci-driver: can't register pci driver\n");
+		return ret;
+	}
+
+	return 0;
+
+}
+
+static void aspeed_host_bmc_device_exit(void)
+{
+	/* unregister pci driver */
+	pci_unregister_driver(&aspeed_host_bmc_dev_driver);
+}
+
+// late_initcall(aspeed_host_bmc_device_init);
+module_init(aspeed_host_bmc_device_init);
+module_exit(aspeed_host_bmc_device_exit);
+
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 69ba6508cf2c..d9fb9fa92a17 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -28,6 +28,7 @@ obj-y				+= rockchip/
 obj-$(CONFIG_SOC_SAMSUNG)	+= samsung/
 obj-$(CONFIG_SOC_SIFIVE)	+= sifive/
 obj-y				+= sunxi/
+obj-$(CONFIG_ARCH_SOPHGO)	+= sophgo/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-y				+= ti/
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
diff --git a/drivers/soc/sophgo/Makefile b/drivers/soc/sophgo/Makefile
new file mode 100644
index 000000000000..3f0210e02d50
--- /dev/null
+++ b/drivers/soc/sophgo/Makefile
@@ -0,0 +1,4 @@
+#obj-$(CONFIG_ARCH_SOPHGO)		+= top/top-mango.o
+obj-$(CONFIG_ARCH_SOPHGO)		+= top/top_intc.o
+obj-$(CONFIG_ARCH_SOPHGO)		+= umcu/mcu.o
+obj-$(CONFIG_ARCH_SOPHGO)		+= tach/sophgo-tach.o
diff --git a/drivers/soc/sophgo/tach/sophgo-tach.c b/drivers/soc/sophgo/tach/sophgo-tach.c
new file mode 100644
index 000000000000..98e0487d9b31
--- /dev/null
+++ b/drivers/soc/sophgo/tach/sophgo-tach.c
@@ -0,0 +1,330 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+
+#define DEV_NAME "sophgo-tach"
+#define MHZ 1000000
+#define USER_PORT 100
+#define USER_MSG  30
+
+struct fan_state {
+	unsigned int freq_num;
+	bool enable;
+};
+
+struct sophgo_fan_speed_device {
+	struct device *dev;
+	struct device *parent;
+	struct class *class;
+	dev_t devno;
+	u32 __iomem *regs;
+	struct delayed_work poll_queue;
+	struct fan_state fan_state;
+	struct mutex enable_lock;
+	struct mutex freqnum_lock;
+};
+
+static int fan_index;
+static struct class *sophgo_fan_speed_class;
+static struct sock *nl_fd;
+
+static int send_msg(char *pbuf, uint16_t len)
+{
+	struct sk_buff *nl_skb;
+	struct nlmsghdr *nlh;
+	int ret = 0;
+
+	//alloc a new netlink message
+	nl_skb = nlmsg_new(len, GFP_ATOMIC);
+	if (!nl_skb) {
+		pr_err("sophgo_fan_speed, netlink alloc skb error!\n");
+		return -ENOMEM;
+	}
+
+	//add a new netlink message to skb
+	nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);
+	if (nlh == NULL) {
+		pr_err("sophgo_fan_speed, nlmsg_put error!\n");
+		nlmsg_free(nl_skb);
+		return -EFAULT;
+	}
+
+	memcpy(nlmsg_data(nlh), pbuf, len);
+	ret = netlink_unicast(nl_fd, nl_skb, USER_PORT, MSG_DONTWAIT);
+
+	return ret;
+}
+
+static void recv_cb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	void *data = NULL;
+
+	if (skb->len >= nlmsg_total_size(0)) {
+		nlh = nlmsg_hdr(skb);
+		data = nlmsg_data(nlh);
+		if (data) {
+			pr_info("sophgo_fan_speed, kernel receive data: %s\n", (int8_t *)data);
+			send_msg(data, nlmsg_len(nlh));
+		}
+	}
+}
+
+struct netlink_kernel_cfg cfg = {
+	.input = recv_cb,
+};
+
+static void fan_speed_check(struct work_struct *work)
+{
+	struct sophgo_fan_speed_device *sophgo_fan = container_of(work,
+				struct sophgo_fan_speed_device, poll_queue.work);
+	int speed, ret = 0;
+	char buf[64];
+
+	speed = readl(sophgo_fan->regs + 1);
+	if (speed == 0) {
+		dev_dbg(sophgo_fan->dev, "fan stop!");
+		ret = snprintf(buf, 32, "%s fan stop!\n", dev_name(sophgo_fan->dev));
+		if (ret <= 0 || ret > 32) {
+			dev_err(sophgo_fan->dev, "%s snprintf failed\n", __func__);
+			return;
+		}
+		ret = send_msg(buf, sizeof(buf));
+		if (ret < 0)
+			dev_dbg(sophgo_fan->dev, "%s send msg failed, ret=%d\n", __func__, ret);
+	}
+	mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue,
+				round_jiffies(msecs_to_jiffies(5000)));
+}
+
+static void fan_speed_enable(bool enalbe, struct sophgo_fan_speed_device *sophgo_fan)
+{
+	if (enalbe) {
+		cancel_delayed_work(&sophgo_fan->poll_queue);
+		writel(sophgo_fan->fan_state.freq_num, sophgo_fan->regs);
+		mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue,
+					round_jiffies(msecs_to_jiffies(5000)));
+		sophgo_fan->fan_state.enable = true;
+	} else {
+		cancel_delayed_work(&sophgo_fan->poll_queue);
+		writel(0, sophgo_fan->regs);
+		sophgo_fan->fan_state.enable = false;
+	}
+}
+
+static ssize_t freq_num_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct sophgo_fan_speed_device *sophgo_fan;
+
+	sophgo_fan = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", sophgo_fan->fan_state.freq_num);
+}
+
+static ssize_t freq_num_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	int val, ret = 0;
+	struct sophgo_fan_speed_device *sophgo_fan;
+
+	sophgo_fan = dev_get_drvdata(dev);
+
+	ret = kstrtoint(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val < (MHZ/10) || val > (1000*MHZ))
+		ret = -EINVAL;
+
+	mutex_lock(&sophgo_fan->freqnum_lock);
+	sophgo_fan->fan_state.freq_num = val;
+	mutex_unlock(&sophgo_fan->freqnum_lock);
+
+	return ret ? : size;
+}
+
+static ssize_t enable_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct sophgo_fan_speed_device *sophgo_fan;
+
+	sophgo_fan = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", sophgo_fan->fan_state.enable);
+}
+
+static ssize_t enable_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	int val, ret = 0;
+	struct sophgo_fan_speed_device *sophgo_fan;
+
+	sophgo_fan = dev_get_drvdata(dev);
+
+	ret = kstrtoint(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&sophgo_fan->enable_lock);
+	switch (val) {
+	case 0:
+		fan_speed_enable(false, sophgo_fan);
+		break;
+	case 1:
+		fan_speed_enable(true, sophgo_fan);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&sophgo_fan->enable_lock);
+
+	return ret ? : size;
+}
+
+static ssize_t fan_speed_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int ret = -1;
+	struct sophgo_fan_speed_device *sophgo_fan;
+
+	sophgo_fan = dev_get_drvdata(dev);
+	ret = snprintf(buf, 32, "fan_speed:%d\n", readl(sophgo_fan->regs + 1));
+	if (ret <= 0 || ret > 32) {
+		dev_err(sophgo_fan->dev, "%s snprintf failed %d\n", __func__, ret);
+		return -EFAULT;
+	}
+	dev_dbg(sophgo_fan->dev, "%s\n", buf);
+	return ret;
+}
+
+static DEVICE_ATTR_RW(enable);
+static DEVICE_ATTR_RW(freq_num);
+static DEVICE_ATTR_RO(fan_speed);
+
+static struct attribute *fan_speed_attrs[] = {
+	&dev_attr_enable.attr,
+	&dev_attr_freq_num.attr,
+	&dev_attr_fan_speed.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(fan_speed);
+
+static int sophgo_fan_speed_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct sophgo_fan_speed_device *sophgo_fan;
+	char dev_name[32];
+	int ret;
+
+	sophgo_fan = devm_kzalloc(&pdev->dev, sizeof(*sophgo_fan), GFP_KERNEL);
+	if (sophgo_fan == NULL)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sophgo_fan->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sophgo_fan->regs))
+		return PTR_ERR(sophgo_fan->regs);
+
+	ret = snprintf(dev_name, 15, "%s-%d", DEV_NAME, fan_index++);
+	if (ret <= 0 || ret > 15) {
+		dev_err(&pdev->dev, "%s snprintf failed\n", __func__);
+		return -EINVAL;
+	}
+	ret = alloc_chrdev_region(&sophgo_fan->devno, 0, 1, dev_name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "register chrdev error\n");
+		return ret;
+	}
+	sophgo_fan->class = sophgo_fan_speed_class;
+	sophgo_fan->dev = device_create(sophgo_fan->class, sophgo_fan->parent,
+					sophgo_fan->devno, sophgo_fan, dev_name);
+	if (IS_ERR(sophgo_fan->dev)) {
+		ret = PTR_ERR(sophgo_fan->dev);
+		dev_err(&pdev->dev, "create device failed\n");
+		unregister_chrdev_region(sophgo_fan->devno, 1);
+		return ret;
+	}
+
+	//as fan source clk 100M, we advise to set freq num  100M
+	sophgo_fan->fan_state.freq_num = 100*MHZ;
+	mutex_init(&sophgo_fan->freqnum_lock);
+	mutex_init(&sophgo_fan->enable_lock);
+
+	platform_set_drvdata(pdev, sophgo_fan);
+	INIT_DELAYED_WORK(&sophgo_fan->poll_queue, fan_speed_check);
+
+	return 0;
+}
+
+static int sophgo_fan_speed_remove(struct platform_device *pdev)
+{
+	struct sophgo_fan_speed_device *sophgo_fan = platform_get_drvdata(pdev);
+
+	cancel_delayed_work(&sophgo_fan->poll_queue);
+	device_destroy(sophgo_fan->class, sophgo_fan->devno);
+	unregister_chrdev_region(sophgo_fan->devno, 1);
+	kfree(sophgo_fan);
+	sophgo_fan = NULL;
+	return 0;
+}
+
+static const struct of_device_id sophgo_fan_speed_of_match[] = {
+	{
+		.compatible = "sophgo,sophgo-tach",
+	},
+	{}
+};
+
+static struct platform_driver sophgo_fan_speed_driver = {
+	.probe = sophgo_fan_speed_probe,
+	.remove =  sophgo_fan_speed_remove,
+	.driver = {
+		.name = "sophgo,sophgo-tach",
+		.of_match_table = sophgo_fan_speed_of_match,
+	},
+};
+
+static int __init sophgo_fan_speed_init(void)
+{
+	sophgo_fan_speed_class = class_create(THIS_MODULE, DEV_NAME);
+	if (IS_ERR(sophgo_fan_speed_class)) {
+		pr_err("class create failed\n");
+		return PTR_ERR(sophgo_fan_speed_class);
+	}
+	sophgo_fan_speed_class->dev_groups = fan_speed_groups;
+
+	nl_fd = netlink_kernel_create(&init_net, USER_MSG, &cfg);
+	if (!nl_fd) {
+		pr_err("sophgo_fan_speed, cannot create netlink socket!\n");
+		return -1;
+	}
+	fan_index = 0;
+	return platform_driver_register(&sophgo_fan_speed_driver);
+}
+
+static void __exit sophgo_fan_speed_exit(void)
+{
+	class_destroy(sophgo_fan_speed_class);
+	if (nl_fd) {
+		netlink_kernel_release(nl_fd);
+		nl_fd = NULL;
+	}
+}
+
+module_init(sophgo_fan_speed_init);
+module_exit(sophgo_fan_speed_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xiao Wang");
+MODULE_DESCRIPTION("minimal module");
+MODULE_VERSION("ALPHA");
diff --git a/drivers/soc/sophgo/top/top_intc.c b/drivers/soc/sophgo/top/top_intc.c
new file mode 100644
index 000000000000..2577137fbc4f
--- /dev/null
+++ b/drivers/soc/sophgo/top/top_intc.c
@@ -0,0 +1,412 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_pci.h>
+#include <linux/msi.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+
+#define MAX_IRQ_NUMBER 32
+#define TOP_INTC_NUM 2
+/*
+ * here we assume all plic hwirq and tic hwirq should
+ * be contiguous.
+ * topc_intc hwirq is index of bitmap (both software and
+ * hardware), and starts from 0.
+ * so we use tic hwirq as index to get plic hwirq and its
+ * irq data.
+ * when used as a msi parent, tic hwirq is written to Top
+ * reg for triggering irq by a PCIe device.
+ *
+ * now we pre-requested plic interrupt, but may try request
+ * plic interrupt when needed, like gicp_irq_domain_alloc.
+ */
+struct top_intc_data {
+	struct platform_device *pdev;
+	int irq_num;
+	struct irq_domain *domain;
+	struct irq_chip *chip;
+	int for_msi;
+	int reg_bitwidth;
+
+	DECLARE_BITMAP(irq_bitmap, MAX_IRQ_NUMBER);
+	spinlock_t lock;
+
+	void __iomem *reg_sta;
+	void __iomem *reg_set;
+	void __iomem *reg_clr;
+
+	phys_addr_t reg_set_phys;
+
+	irq_hw_number_t		plic_hwirqs[MAX_IRQ_NUMBER];
+	int			plic_irqs[MAX_IRQ_NUMBER];
+	struct irq_data		*plic_irq_datas[MAX_IRQ_NUMBER];
+	int			tic_to_plic[MAX_IRQ_NUMBER]; // mapping from tic hwirq to plic hwirq
+};
+
+// workaround for using in other modules
+struct top_intc_data *tic_data[TOP_INTC_NUM];
+
+struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id)
+{
+	if (intc_id >= TOP_INTC_NUM)
+		return NULL;
+
+	if (tic_data[intc_id])
+		return tic_data[intc_id]->domain;
+	else
+		return NULL;
+}
+
+static int top_intc_domain_translate(struct irq_domain *d,
+				    struct irq_fwspec *fwspec,
+				    unsigned long *hwirq,
+				    unsigned int *type)
+{
+	struct top_intc_data *data = d->host_data;
+
+	if (fwspec->param_count != 2)
+		return -EINVAL;
+	if (fwspec->param[1] >= data->irq_num)
+		return -EINVAL;
+
+	*hwirq = fwspec->param[0];
+	*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+	pr_debug("%s hwirq %d, flag %d\n", __func__, fwspec->param[0], fwspec->param[1]);
+	return 0;
+}
+
+static int top_intc_domain_alloc(struct irq_domain *domain,
+				unsigned int virq, unsigned int nr_irqs,
+				void *args)
+{
+	unsigned long flags;
+	irq_hw_number_t hwirq;
+	int i, type, ret = -1;
+	struct top_intc_data *data = domain->host_data;
+
+	if (data->for_msi) {
+		// dynamically alloc hwirq
+		spin_lock_irqsave(&data->lock, flags);
+		ret = bitmap_find_free_region(data->irq_bitmap, data->irq_num,
+						order_base_2(nr_irqs));
+		spin_unlock_irqrestore(&data->lock, flags);
+
+		if (ret < 0) {
+			pr_err("%s failed to alloc irq %d, total %d\n", __func__, virq, nr_irqs);
+			return -ENOSPC;
+		}
+
+		hwirq = ret;
+		for (i = 0; i < nr_irqs; i++) {
+			irq_domain_set_info(domain, virq + i, hwirq + i,
+						data->chip,
+						data, handle_edge_irq,
+						NULL, NULL);
+			data->tic_to_plic[hwirq + i] = data->plic_hwirqs[hwirq + i];
+		}
+	} else {
+		// try use hwirq specified in parameter
+		ret = top_intc_domain_translate(domain, args, &hwirq, &type);
+		if (ret) {
+			pr_err("%s failed to translate virq %d, %d\n", __func__, virq, ret);
+			return ret;
+		}
+
+		// try to occupy bitmap for the given hwirq
+		spin_lock_irqsave(&data->lock, flags);
+		ret = bitmap_allocate_region(data->irq_bitmap, hwirq, order_base_2(1));
+		spin_unlock_irqrestore(&data->lock, flags);
+		if (ret < 0) {
+			pr_err("%s virq %d found hwirq %ld occupied\n", __func__, virq, hwirq);
+			return -EBUSY;
+		}
+
+		irq_domain_set_info(domain, virq, hwirq,
+					data->chip,
+					data, handle_edge_irq,
+					NULL, NULL);
+
+		// explicitly set parent
+		data->tic_to_plic[hwirq] = data->plic_hwirqs[hwirq];
+	}
+
+	pr_debug("%s hwirq %ld, irq %d, plic irq %d, total %d\n", __func__,
+		hwirq, virq, data->plic_irqs[hwirq], nr_irqs);
+	return 0;
+}
+
+static void top_intc_domain_free(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs)
+{
+	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+	struct top_intc_data *data = irq_data_get_irq_chip_data(d);
+	unsigned long flags;
+
+	pr_debug("%s hwirq %ld, irq %d, total %d\n", __func__, d->hwirq, virq, nr_irqs);
+
+	spin_lock_irqsave(&data->lock, flags);
+	bitmap_release_region(data->irq_bitmap, d->hwirq,
+				order_base_2(nr_irqs));
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static const struct irq_domain_ops top_intc_domain_ops = {
+	.translate = top_intc_domain_translate,
+	.alloc	= top_intc_domain_alloc,
+	.free	= top_intc_domain_free,
+};
+
+static void top_intc_ack_irq(struct irq_data *d)
+{
+	struct top_intc_data *data  = irq_data_get_irq_chip_data(d);
+	int reg_off, bit_off;
+	struct irq_data *plic_irq_data = data->plic_irq_datas[d->hwirq];
+
+	reg_off = d->hwirq / data->reg_bitwidth;
+	bit_off = d->hwirq - data->reg_bitwidth * reg_off;
+	writel(1 << bit_off, (unsigned int *)data->reg_clr + reg_off);
+
+	pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq,
+		plic_irq_data->domain->name, plic_irq_data->hwirq);
+	if (plic_irq_data->chip->irq_ack)
+		plic_irq_data->chip->irq_ack(plic_irq_data);
+}
+
+static void top_intc_mask_irq(struct irq_data *d)
+{
+	struct top_intc_data *data  = irq_data_get_irq_chip_data(d);
+	struct irq_data *plic_irq_data = data->plic_irq_datas[d->hwirq];
+
+	pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq,
+		plic_irq_data->domain->name, plic_irq_data->hwirq);
+	plic_irq_data->chip->irq_mask(plic_irq_data);
+}
+
+static void top_intc_unmask_irq(struct irq_data *d)
+{
+	struct top_intc_data *data  = irq_data_get_irq_chip_data(d);
+	struct irq_data *plic_irq_data = data->plic_irq_datas[d->hwirq];
+
+	pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq,
+		plic_irq_data->domain->name, plic_irq_data->hwirq);
+	plic_irq_data->chip->irq_unmask(plic_irq_data);
+}
+
+static void top_intc_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+	struct top_intc_data *data  = irq_data_get_irq_chip_data(d);
+
+	msg->address_lo = lower_32_bits(data->reg_set_phys);
+	msg->address_hi = upper_32_bits(data->reg_set_phys);
+	msg->data = 1 << d->hwirq;
+
+	pr_debug("%s msi#%d: address_hi %#x, address_lo %#x, data %#x\n", __func__,
+		(int)d->hwirq, msg->address_hi, msg->address_lo, msg->data);
+}
+
+static int top_intc_set_affinity(struct irq_data *d,
+				 const struct cpumask *mask, bool force)
+{
+	struct top_intc_data *data  = irq_data_get_irq_chip_data(d);
+	struct irq_data *plic_irq_data = data->plic_irq_datas[d->hwirq];
+
+	irq_data_update_effective_affinity(d, mask);
+	if (plic_irq_data->chip->irq_set_affinity)
+		return plic_irq_data->chip->irq_set_affinity(plic_irq_data, mask, force);
+	else
+		return -EINVAL;
+}
+
+static int top_intc_set_type(struct irq_data *d, u32 type)
+{
+	/*
+	 * dummy function, so __irq_set_trigger can continue to set
+	 * correct trigger type.
+	 */
+	return 0;
+}
+
+static struct irq_chip top_intc_irq_chip = {
+	.name = "top-intc",
+	.irq_ack = top_intc_ack_irq,
+	.irq_mask = top_intc_mask_irq,
+	.irq_unmask = top_intc_unmask_irq,
+	.irq_compose_msi_msg = top_intc_setup_msi_msg,
+	.irq_set_affinity = top_intc_set_affinity,
+	.irq_set_type = top_intc_set_type,
+};
+
+static void top_intc_irq_handler(struct irq_desc *plic_desc)
+{
+	struct irq_chip *plic_chip = irq_desc_get_chip(plic_desc);
+	struct top_intc_data *data = irq_desc_get_handler_data(plic_desc);
+	irq_hw_number_t plic_hwirq = irq_desc_get_irq_data(plic_desc)->hwirq;
+	irq_hw_number_t top_intc_hwirq;
+	int top_intc_irq, i, ret;
+
+	chained_irq_enter(plic_chip, plic_desc);
+
+	for (i = 0; i < data->irq_num; i++) {
+		if (data->tic_to_plic[i] == plic_hwirq)
+			break;
+	}
+	if (i < data->irq_num) {
+		top_intc_hwirq = i;
+		top_intc_irq = irq_find_mapping(data->domain, top_intc_hwirq);
+		pr_debug("%s plic hwirq %ld, tic hwirq %ld, tic irq %d\n", __func__,
+				plic_hwirq, top_intc_hwirq, top_intc_irq);
+		if (top_intc_irq)
+			ret = generic_handle_irq(top_intc_irq);
+		pr_debug("%s handled tic irq %d, %d\n", __func__, top_intc_irq, ret);
+	} else {
+		pr_debug("%s not found tic hwirq for plic hwirq %ld\n", __func__, plic_hwirq);
+		// workaround, ack unexpected(unregistered) interrupt
+		writel(1 << (plic_hwirq - data->plic_hwirqs[0]), data->reg_clr);
+	}
+
+	chained_irq_exit(plic_chip, plic_desc);
+}
+
+static int top_intc_probe(struct platform_device *pdev)
+{
+	struct top_intc_data *data;
+	struct resource *res;
+	struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node);
+	int ret = 0, i;
+	int intc_id = 0;
+
+	device_property_read_u32(&pdev->dev, "top-intc-id", &intc_id);
+	if (intc_id >= TOP_INTC_NUM)
+		return -EINVAL;
+
+	// alloc private data
+	data = kzalloc(sizeof(struct top_intc_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, data);
+	data->pdev = pdev;
+	spin_lock_init(&data->lock);
+
+	if (device_property_read_bool(&pdev->dev, "for-msi")) {
+		dev_info(&pdev->dev, "is a msi parent\n");
+		data->for_msi = 1;
+	}
+	if (device_property_read_u32(&pdev->dev, "reg-bitwidth", &data->reg_bitwidth))
+		data->reg_bitwidth = 32;
+
+	// get register address
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sta");
+	data->reg_sta = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->reg_sta)) {
+		dev_err(&pdev->dev, "failed map status register\n");
+		ret = PTR_ERR(data->reg_sta);
+		goto out;
+	}
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
+	data->reg_set = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->reg_set)) {
+		dev_err(&pdev->dev, "failed map set register\n");
+		ret = PTR_ERR(data->reg_set);
+		goto out;
+	}
+	data->reg_set_phys = res->start;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
+	data->reg_clr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(data->reg_clr)) {
+		dev_err(&pdev->dev, "failed map clear register\n");
+		ret = PTR_ERR(data->reg_clr);
+		goto out;
+	}
+
+	// get irq numbers
+	for (i = 0; i < ARRAY_SIZE(data->plic_hwirqs); i++) {
+		char name[8];
+		int irq;
+
+		snprintf(name, ARRAY_SIZE(name), "msi%d", i);
+		irq = platform_get_irq_byname(pdev, name);
+		if (irq < 0)
+			break;
+
+		data->plic_irqs[i] = irq;
+		data->plic_irq_datas[i] = irq_get_irq_data(irq);
+		data->plic_hwirqs[i] = data->plic_irq_datas[i]->hwirq;
+		dev_dbg(&pdev->dev, "%s: plic hwirq %ld, plic irq %d\n", name,
+				data->plic_hwirqs[i], data->plic_irqs[i]);
+	}
+	data->irq_num = i;
+	dev_dbg(&pdev->dev, "got %d plic irqs\n", data->irq_num);
+
+	// create IRQ domain
+	data->domain = irq_domain_create_linear(fwnode, data->irq_num,
+						&top_intc_domain_ops, data);
+	if (!data->domain) {
+		dev_err(&pdev->dev, "create linear irq doamin failed\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	data->chip = &top_intc_irq_chip;
+
+	/*
+	 * workaround to deal with IRQ conflict with TPU driver,
+	 * skip the firt IRQ and mark it as used.
+	 */
+	//bitmap_allocate_region(data->irq_bitmap, 0, order_base_2(1));
+	for (i = 0; i < data->irq_num; i++)
+		irq_set_chained_handler_and_data(data->plic_irqs[i],
+							top_intc_irq_handler, data);
+
+	if (data->for_msi) {
+		irq_domain_update_bus_token(data->domain, DOMAIN_BUS_NEXUS);
+		if (tic_data[intc_id])
+			dev_err(&pdev->dev, "tic_data is not empty, %s\n",
+				dev_name(&tic_data[intc_id]->pdev->dev));
+		tic_data[intc_id] = data;
+	}  else {
+		/*
+		 * populate child nodes. when test device node is a child, it will not be
+		 * automatically enumerated as a platform device.
+		 */
+		of_platform_populate(pdev->dev.of_node, NULL, NULL, NULL);
+	}
+	return ret;
+
+out:
+	if (data->reg_sta)
+		iounmap(data->reg_sta);
+	if (data->reg_set)
+		iounmap(data->reg_set);
+	if (data->reg_clr)
+		iounmap(data->reg_clr);
+	kfree(data);
+	return ret;
+}
+
+static const struct of_device_id top_intc_of_match[] = {
+	{
+		.compatible = "sophgo,top-intc",
+	},
+	{},
+};
+
+static struct platform_driver top_intc_driver = {
+	.driver = {
+		.name = "sophgo,top-intc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(top_intc_of_match),
+	},
+	.probe = top_intc_probe,
+};
+
+static int __init top_intc_init(void)
+{
+	return platform_driver_register(&top_intc_driver);
+}
+
+arch_initcall(top_intc_init);
diff --git a/drivers/soc/sophgo/umcu/mcu.c b/drivers/soc/sophgo/umcu/mcu.c
new file mode 100644
index 000000000000..5478db58bf52
--- /dev/null
+++ b/drivers/soc/sophgo/umcu/mcu.c
@@ -0,0 +1,1145 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+/* fixed MCU registers */
+#define MCU_REG_BOARD_TYPE		0x00
+#define MCU_REG_VERSION			0x01
+#define MCU_REG_SOC_TEMP		0x04
+#define MCU_REG_BOARD_TEMP		0x05
+#define MCU_REG_PWROFF_REASON1		0x06
+#define MCU_REG_PWROFF_REASON2		0x07
+
+#define MCU_REG_CRITICAL_ACTIONS	0x65
+#define MCU_REG_CRITICAL_TEMP		0x66
+#define MCU_REG_REPOWERON_TEMP		0x67
+#define MCU_REG_KEEP_DDR_POWERON	0x68
+
+#define MCU_CRITICAL_ACTION_POWEROFF	0x2
+#define MCU_CRITICAL_ACTION_REBOOT	0X1
+
+#define MANGO_BOARD_TYPE_MASK	1 << 7
+
+#ifndef assert
+#define assert(exp)	WARN_ON(!(exp))
+#endif
+
+struct mcu_features {
+	u8 id;
+	char *proj;
+	char *soc;
+	char *chip;
+
+	int board_type;
+	int mcu_ver;
+	int pcb_ver;
+	int soc_tmp;
+	int board_tmp;
+	int alert_status;
+	int alert_mask;
+	int rst_cnt;
+	int uptime;
+	int lock;
+	int power;
+	int power_tpu;
+	int brd_id;
+	int brd_ip;
+
+	int critical_action;
+	int critical_temp;
+	int repoweron_temp;
+	int keep_ddr_poweron;
+
+	char *alert_table[16];
+};
+
+struct mcu_info {
+	u8 board_type;
+	u8 mcu_ver;
+	u8 pcb_ver;
+	u8 rst_cnt;
+	int updated;
+};
+
+struct mcu_ctx {
+	const struct mcu_features *features;
+	struct i2c_client *i2c;
+	struct mcu_info info;
+	u32 channel_config[4];
+	struct hwmon_channel_info temp_info;
+	const struct hwmon_channel_info *channel_info[3];
+	struct hwmon_chip_info chip;
+	struct mutex update_lock;
+	unsigned int hwmon_update_interval; /* in milliseconds */
+};
+
+const struct mcu_features mcu_list[] = {
+	{
+		0x80, "SG2042 EVB", "SG2042", "GD32",
+		0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1,
+		-1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS,
+		MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP,
+		MCU_REG_KEEP_DDR_POWERON,
+		{
+			"SoC overheat",
+			"Power supply overheat",
+			"Board overheat",
+			"Board overheat and shutdown",
+			"SoC overheat and shutdown",
+			"Power supply failure",
+			"12V power supply failure",
+			"SoC required reboot",
+		},
+	},
+
+	{
+		0x83, "SG2042 X4", "SG2042", "GD32",
+		0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1,
+		-1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS,
+		MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP,
+		MCU_REG_KEEP_DDR_POWERON,
+		{
+			"SoC overheat",
+			"Power supply overheat",
+			"Board overheat",
+			"Board overheat and shutdown",
+			"SoC overheat and shutdown",
+			"Power supply failure",
+			"12V power supply failure",
+			"SoC required reboot",
+		},
+	},
+
+		{
+		0x90, "MILKV PIONEER", "SG2042", "GD32",
+		0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1,
+		-1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS,
+		MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP,
+		MCU_REG_KEEP_DDR_POWERON,
+		{
+			"SoC overheat",
+			"Power supply overheat",
+			"Board overheat",
+			"Board overheat and shutdown",
+			"SoC overheat and shutdown",
+			"Power supply failure",
+			"12V power supply failure",
+			"SoC required reboot",
+		},
+	},
+};
+
+static const char help[] =
+"\n"
+"sys files description\n"
+"======================\n"
+"Bitmain unified mcu device driver\n"
+"You can get/set MCU though read/write operation\n"
+"eg. You can get fixed information though command\n"
+"$cat /sys/bus/i2c/0-0017/information\n"
+"You can set alert mask though command\n"
+"$echo 0xffff /sys/bus/i2c/0-0017/alert\n"
+"\n"
+"information\n"
+"-----------\n"
+"Fixed information during SoC uptime\n"
+"Read this file will return such information\n"
+"Write this file to force SoC re-get such information from MCU\n"
+"No matter what data you write to or just invoke write with a length of 0\n"
+"File pointer will move forward after read,\n"
+"write has no effect on file pointer\n"
+"\n"
+"temperature\n"
+"-----------\n"
+"Temperature value, sensors located on SoC and on board\n"
+"Read this file will return temperature of both in celsius\n"
+"Write is forbidden\n"
+"\n"
+"uptime\n"
+"------\n"
+"Uptime (from SoC poweron) in seconds\n"
+"Read will get this value, write is forbidden\n"
+"\n"
+"alert\n"
+"-----\n"
+"Alert control and status\n"
+"Read will get current alert status\n"
+"Write corresponding bit to 1 will mask this alert\n"
+"You can use 0x/0X for hex, 0 for octal\n"
+"other leading characters will be considered as decimal\n"
+"Values larger than 0xffff is forbidden\n"
+"\n";
+
+enum {
+	MCU_I2C_TYPE_U = 0,
+	MCU_I2C_TYPE_U8,
+	MCU_I2C_TYPE_U16,
+	MCU_I2C_TYPE_U32,
+	MCU_I2C_TYPE_U64,
+	MCU_I2C_TYPE_D,
+	MCU_I2C_TYPE_S8,
+	MCU_I2C_TYPE_S16,
+	MCU_I2C_TYPE_S32,
+	MCU_I2C_TYPE_S64,
+	MCU_I2C_TYPE_MAX,
+};
+
+static const char *mcu_i2c_type_list[MCU_I2C_TYPE_MAX] = {
+	[MCU_I2C_TYPE_U]	=	"u",
+	[MCU_I2C_TYPE_U8]	=	"u8",
+	[MCU_I2C_TYPE_U16]	=	"u16",
+	[MCU_I2C_TYPE_U32]	=	"u32",
+	[MCU_I2C_TYPE_U64]	=	"u64",
+	[MCU_I2C_TYPE_D]	=	"d",
+	[MCU_I2C_TYPE_S8]	=	"s8",
+	[MCU_I2C_TYPE_S16]	=	"s16",
+	[MCU_I2C_TYPE_S32]	=	"s32",
+	[MCU_I2C_TYPE_S64]	=	"s64",
+};
+
+static int check_token(char *token)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mcu_i2c_type_list); ++i) {
+		if (strcmp(token, mcu_i2c_type_list[i]) == 0)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static inline struct device *i2c2dev(struct i2c_client *i2c)
+{
+	return &i2c->dev;
+}
+
+static int mcu_i2c_write_byte(struct i2c_client *i2c, int reg, u8 data)
+{
+	int err;
+
+	if (reg == -1)
+		return 0;
+	err = i2c_smbus_write_byte_data(i2c, reg, data);
+	dev_dbg(i2c2dev(i2c), "%d : %u\n", reg, data);
+	return err;
+}
+
+static int mcu_i2c_read_byte(struct i2c_client *i2c, int reg)
+{
+	int err;
+
+	if (reg == -1)
+		return 0;
+	err = i2c_smbus_read_byte_data(i2c, reg);
+	dev_dbg(i2c2dev(i2c), "%d : %d\n", reg, err);
+	return err;
+}
+
+static int mcu_i2c_write_block(struct i2c_client *i2c, int reg,
+			       int len, void *data)
+{
+	int err, i;
+
+	if (reg == -1)
+		return 0;
+
+	err = i2c_smbus_write_i2c_block_data(i2c, reg, len, data);
+	for (i = 0; i < len; ++i)
+		dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)[i]);
+	return err;
+}
+
+static int mcu_i2c_read_block(struct i2c_client *i2c, int reg,
+			      int len, void *data)
+{
+	int err, i;
+
+	if (reg == -1)
+		return 0;
+
+	err = i2c_smbus_read_i2c_block_data(i2c, reg, len, data);
+	for (i = 0; i < len; ++i)
+		dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)[i]);
+
+	return err;
+}
+
+static int mcu_i2c_sreadf(struct i2c_client *i2c, const char *fmt, ...)
+{
+	va_list arg;
+	const char *p = fmt;
+	const char *start, *end;
+	char token[16];
+	int tokenlen;
+	int ret = -EINVAL;
+	int idx;
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	va_start(arg, fmt);
+
+	while (*p) {
+		/* skip all % */
+		while (*p == '%')
+			++p;
+		start = p;
+		while (*p && *p != '%')
+			++p;
+		/* now *p is ether \0 or % */
+		end = p;
+		tokenlen = end - start;
+		if (tokenlen > sizeof(token) - 1) {
+			ret = -EINVAL;
+			goto end;
+		}
+		if (tokenlen == 0)
+			continue;
+		/* get this token */
+		memcpy(token, start, tokenlen);
+		token[tokenlen] = 0; /* terminat this string */
+		idx = check_token(token);
+		if (idx < 0) {
+			ret = idx;
+			goto end;
+		}
+
+		ret = mcu_i2c_read_byte(i2c, va_arg(arg, int));
+		if (ret < 0)
+			goto end;
+
+		switch (idx) {
+		case MCU_I2C_TYPE_U:
+			*va_arg(arg, unsigned int *) = ret;
+			break;
+		case MCU_I2C_TYPE_U8:
+			*va_arg(arg, u8 *) = ret;
+			break;
+		case MCU_I2C_TYPE_U16:
+			*va_arg(arg, u16 *) = ret;
+			break;
+		case MCU_I2C_TYPE_U32:
+			*va_arg(arg, u32 *) = ret;
+			break;
+		case MCU_I2C_TYPE_U64:
+			*va_arg(arg, u64 *) = ret;
+			break;
+		case MCU_I2C_TYPE_D:
+			*va_arg(arg, int *) = ret;
+			break;
+		case MCU_I2C_TYPE_S8:
+			*va_arg(arg, s8 *) = ret;
+			break;
+		case MCU_I2C_TYPE_S16:
+			*va_arg(arg, s16 *) = ret;
+			break;
+		case MCU_I2C_TYPE_S32:
+			*va_arg(arg, s32 *) = ret;
+			break;
+		case MCU_I2C_TYPE_S64:
+			*va_arg(arg, s64 *) = ret;
+			break;
+		default:
+			assert(false);
+			break;
+		}
+	}
+
+	ret = 0;
+end:
+	va_end(arg);
+	return ret;
+}
+
+/* sysfs callbacks */
+
+static inline struct i2c_client *dev2i2c(struct device *dev)
+{
+	return container_of(dev, struct i2c_client, dev);
+}
+
+static const inline struct mcu_features *dev2features(struct device *dev)
+{
+	struct i2c_client *i2c = dev2i2c(dev);
+	struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c);
+
+	return ctx->features;
+}
+
+static ssize_t help_show(struct device *dev, struct device_attribute *attr,
+		  char *buf)
+{
+	buf[0] = 0;
+	strncpy(buf, help, PAGE_SIZE);
+	return strlen(buf);
+}
+
+static int mcu_msg_append(char *base, unsigned long limit,
+		   const char *fmt, ...)
+{
+	int len = strlen(base);
+	va_list arg;
+
+	va_start(arg, fmt);
+	len += vsnprintf(base + len, limit - len, fmt, arg);
+	va_end(arg);
+	return len;
+}
+
+ssize_t info_show(struct device *dev, struct device_attribute *attr,
+		  char *buf)
+{
+	struct i2c_client *i2c = dev2i2c(dev);
+	struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c);
+	struct mcu_info *info = &ctx->info;
+	const struct mcu_features *features = ctx->features;
+	int err;
+
+	if (info->updated == 0) {
+		/* get information from mcu through i2c */
+		err = mcu_i2c_sreadf(i2c, "%u8%u8%u8%u8",
+				     features->board_type, &info->board_type,
+				     features->mcu_ver, &info->mcu_ver,
+				     features->pcb_ver, &info->pcb_ver,
+				     features->rst_cnt, &info->rst_cnt);
+		if (err)
+			return err;
+		info->updated = 1;
+	}
+
+	/* convert to json text */
+	mcu_msg_append(buf, PAGE_SIZE, "{\n");
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"model\": \"%s\",\n", features->proj);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"chip\": \"%s\",\n", features->soc);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu\": \"%s\",\n", features->chip);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"board type\": \"0x%02X\",\n", info->board_type);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu version\": \"0x%02X\",\n", info->mcu_ver);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"pcb version\": \"0x%02X\",\n", info->pcb_ver);
+	mcu_msg_append(buf, PAGE_SIZE, "\t\"reset count\": %u\n", info->rst_cnt);
+	err = mcu_msg_append(buf, PAGE_SIZE, "}\n");
+
+	return err;
+}
+
+static ssize_t info_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct i2c_client *i2c = dev2i2c(dev);
+	struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c);
+	struct mcu_info *info = &ctx->info;
+
+	info->updated = 0;
+	return count;
+}
+
+ssize_t brdid_show(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	int err = 0;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->brd_id == -1)
+		return -ENODEV;
+
+	err = mcu_i2c_read_byte(dev2i2c(dev), features->brd_id);
+	if (err < 0)
+		return err;
+
+	return sprintf(buf, "brdid:%u\n", err);
+}
+
+ssize_t brdip_show(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	u8 ip[4];
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->brd_ip == -1)
+		return -ENODEV;
+
+	memset(ip, 0, sizeof(ip));
+	err = mcu_i2c_read_block(dev2i2c(dev), features->brd_ip,
+					    sizeof(ip), ip);
+	if (err < 0)
+		return err;
+
+	return mcu_msg_append(buf, PAGE_SIZE, "brdip:%u.%u.%u.%u\n",
+		ip[0], ip[1], ip[2], ip[3]);
+}
+
+static ssize_t brdip_store(struct device *dev, struct device_attribute *attr,
+	const char *ubuf, size_t len)
+{
+	u8 ip[4];
+	char buf[32];
+	char *s, *p, *n;
+	unsigned long res;
+	int i, err;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->brd_ip == -1)
+		return -ENODEV;
+
+	memset(buf, 0, sizeof(buf));
+	len = min(sizeof(buf), len);
+	memcpy(buf, ubuf, len);
+	s = buf;
+	for (i = 0; i < 4; i++) {
+		if (i != 3) {
+			p = strchr(s, '.');
+			n = p+1;
+			*p = '\0';
+		}
+		err = kstrtoul(s, 10, &res);
+		if (err)
+			return err;
+		ip[i] = (u8)res;
+		dev_dbg(dev, "ip[%d] = %d\n", i, ip[i]);
+		s = n;
+	}
+	err = mcu_i2c_write_block(dev2i2c(dev), features->brd_ip,
+					     sizeof(ip), ip);
+	if (err < 0)
+		return err;
+
+	return len;
+}
+ssize_t uptime_show(struct device *dev, struct device_attribute *attr,
+		    char *buf)
+{
+	u8 t[2];
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->uptime,
+					    sizeof(t), t);
+	if (err < 0)
+		return err;
+
+	return mcu_msg_append(buf, PAGE_SIZE,
+			      "%u Seconds\n", t[0] | (t[1] << 8));
+}
+
+ssize_t temp_show(struct device *dev, struct device_attribute *attr,
+		  char *buf)
+{
+	s8 t[2];
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	/* get information from mcu through i2c */
+	err = mcu_i2c_sreadf(dev2i2c(dev), "%s8%s8",
+			     features->soc_tmp, t,
+			     features->board_tmp, t + 1);
+	if (err)
+		return err;
+
+	mcu_msg_append(buf, PAGE_SIZE,
+		       "SoC temperature: %d Cel\n", t[0]);
+	return mcu_msg_append(buf, PAGE_SIZE,
+			      "Board temperature: %d Cel\n", t[1]);
+}
+
+
+static const char *alert_id2name(const struct mcu_features *features, int id)
+{
+	if (features->alert_table[id])
+		return features->alert_table[id];
+	return "Unknown alert";
+}
+
+ssize_t alert_show(struct device *dev, struct device_attribute *attr,
+		   char *buf)
+{
+	int cnt = 0;
+	int i, err;
+	u8 t[4];
+	u16 mask, status;
+	const struct mcu_features *features = dev2features(dev);
+	const char *alt_msg;
+
+	if (features->alert_status == -1)
+		return 0;
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->alert_mask,
+					    sizeof(t), t);
+	/* get information from mcu through i2c */
+	if (err < 0)
+		return err;
+
+	status = t[0] | (t[1] << 8);
+	mask = t[2] | (t[3] << 8);
+	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
+			"Mask 0x%02x, Status 0x%02x\n",
+			mask, status);
+
+	if (status == 0) {
+		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
+				"Working fine\n");
+	} else {
+		for (i = 0; i < sizeof(status) * 8; ++i) {
+			if ((status >> i) & 1) {
+				alt_msg = alert_id2name(features, i);
+				cnt += snprintf(buf + cnt,
+						PAGE_SIZE - cnt,
+						"%d: %s\n",
+						i, alt_msg);
+			}
+		}
+	}
+	cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
+			"**************************************************\n");
+
+	for (i = 0; i < 16; ++i) {
+		if (features->alert_table[i] == NULL)
+			continue;
+		cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
+				"%d: %s\n", i, alert_id2name(features, i));
+	}
+
+	return cnt;
+}
+
+static ssize_t alert_store(struct device *dev, struct device_attribute *attr,
+			  const char *ubuf, size_t len)
+{
+	char buf[32];
+	u8 t[2];
+	unsigned long res;
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->alert_mask == -1)
+		return -ENODEV;
+
+	len = min(sizeof(buf) - 1, len);
+	memcpy(buf, ubuf, len);
+
+	buf[len] = 0; // zero terminated
+	err = kstrtoul(buf, 0, &res);
+	if (err)
+		return err;
+	if (res > 0xffff)
+		return -EINVAL;
+
+	t[0] = res & 0xff;
+	t[1] = (res >> 8) & 0xff;
+	err = mcu_i2c_write_block(dev2i2c(dev), features->alert_mask,
+					     sizeof(t), t);
+	if (err < 0)
+		return err;
+
+	return len;
+}
+
+ssize_t lock_show(struct device *dev, struct device_attribute *attr,
+		   char *buf)
+{
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->lock == -1)
+		return -ENODEV;
+
+	err = mcu_i2c_read_byte(dev2i2c(dev), features->lock);
+
+	if (err < 0)
+		return err;
+
+	return mcu_msg_append(buf, PAGE_SIZE,
+			      "%d", err ? 1 : 0);
+}
+
+static ssize_t lock_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t len)
+{
+	int err;
+	unsigned long res;
+	const u8 *code[] = { "CK", "LO", };
+	const u8 *p;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->lock == -1)
+		return -ENODEV;
+
+	err = kstrtoul(buf, 0, &res);
+	if (err)
+		return err;
+
+	res = res ? 1 : 0;
+
+	for (p = code[res]; *p; ++p) {
+		err = mcu_i2c_write_byte(dev2i2c(dev), features->lock, *p);
+		if (err < 0)
+			return err;
+	}
+
+	return len;
+}
+
+ssize_t power_show(struct device *dev, struct device_attribute *attr,
+		   char *buf)
+{
+	u8 t[2];
+	int err;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->power < 0)
+		return -EOPNOTSUPP;
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->power, sizeof(t), t);
+	if (err < 0)
+		return err;
+
+	err = sprintf(buf, "%umW\n", ((u16)t[0]) | (t[1] << 8));
+
+	return err;
+}
+
+static ssize_t power_tpu_store(struct device *dev, struct device_attribute *attr,
+			       const char *buf, size_t len)
+{
+	int err;
+	unsigned long res;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->power_tpu < 0)
+		return -EOPNOTSUPP;
+
+	err = kstrtoul(buf, 0, &res);
+	if (err)
+		return err;
+
+	data = res ? 1 : 0;
+
+	err = mcu_i2c_write_block(dev2i2c(dev), features->power_tpu,
+					     sizeof(data), &data);
+	return len;
+}
+
+static ssize_t power_tpu_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (features->power_tpu < 0)
+		return -EOPNOTSUPP;
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->power_tpu, sizeof(data), &data);
+	if (err < 0)
+		return err;
+
+	err = sprintf(buf, "%u\n", data);
+
+	return err;
+}
+
+static ssize_t mcu_critical_action_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t len)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+
+	if (!strcmp(buf, "reboot\n"))
+		data = MCU_CRITICAL_ACTION_REBOOT;
+	else if (!strcmp(buf, "poweroff\n"))
+		data = MCU_CRITICAL_ACTION_POWEROFF;
+	else
+		data = 0;
+
+	if (data) {
+		err = mcu_i2c_write_block(dev2i2c(dev),
+			features->critical_action, sizeof(data), &data);
+	}
+	return len;
+}
+
+static ssize_t mcu_critical_action_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->critical_action,
+				 sizeof(data), &data);
+	if (err < 0)
+		return err;
+
+	if (data == MCU_CRITICAL_ACTION_REBOOT)
+		err = sprintf(buf, "reboot\n");
+	else if (data == MCU_CRITICAL_ACTION_POWEROFF)
+		err = sprintf(buf, "poweroff\n");
+	else
+		err = sprintf(buf, "unknown critical action\n");
+
+	return err;
+}
+
+
+static ssize_t mcu_critical_temp_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t len)
+{
+	int err;
+	unsigned long res;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = kstrtoul(buf, 0, &res);
+	if (err)
+		return err;
+
+	data = res;
+
+	err = mcu_i2c_write_block(dev2i2c(dev), features->critical_temp,
+					     sizeof(data), &data);
+	return len;
+}
+
+static ssize_t mcu_critical_temp_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->critical_temp,
+				 sizeof(data), &data);
+	if (err < 0)
+		return err;
+
+	err = sprintf(buf, "%u Cel\n", data);
+
+	return err;
+}
+
+
+static ssize_t mcu_repoweron_temp_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	int err;
+	unsigned long res;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = kstrtoul(buf, 0, &res);
+	if (err)
+		return err;
+
+	data = res;
+
+	err = mcu_i2c_write_block(dev2i2c(dev), features->repoweron_temp,
+					     sizeof(data), &data);
+	return len;
+}
+
+static ssize_t mcu_repoweron_temp_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->repoweron_temp,
+				 sizeof(data), &data);
+	if (err < 0)
+		return err;
+
+	err = sprintf(buf, "%u Cel\n", data);
+
+	return err;
+}
+
+
+static ssize_t mcu_keep_ddr_poweron_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	if (!strcmp(buf, "disable\n"))
+		data = 1;
+	else if (!strcmp(buf, "enable\n"))
+		data = 0;
+	else
+		return 0;
+
+	err = mcu_i2c_write_block(dev2i2c(dev), features->keep_ddr_poweron,
+					     sizeof(data), &data);
+	return len;
+}
+
+static ssize_t mcu_keep_ddr_poweron_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	int err;
+	unsigned char data;
+	const struct mcu_features *features = dev2features(dev);
+
+	err = mcu_i2c_read_block(dev2i2c(dev), features->keep_ddr_poweron,
+				 sizeof(data), &data);
+	if (err < 0)
+		return err;
+
+	if (data == 1)
+		err = sprintf(buf, "disable\n");
+	else if (data == 0)
+		err = sprintf(buf, "enable\n");
+	else
+		err = sprintf(buf, "unknown states\n");
+
+	return err;
+}
+
+/* end of sysfs callbacks */
+
+const struct device_attribute mcu_attrs[] =  {
+	{{"help", 0444}, help_show, NULL},
+	{{"information", 0644}, info_show, info_store},
+	{{"temperature", 0444}, temp_show, NULL},
+	{{"uptime", 0444}, uptime_show, NULL},
+	{{"alert", 0644}, alert_show, alert_store},
+	{{"lock", 0644}, lock_show, lock_store},
+	{{"power-now", 0444}, power_show, NULL},
+	{{"power-tpu", 0644}, power_tpu_show, power_tpu_store},
+	{{"board-id", 0444}, brdid_show, NULL},
+	{{"board-ip", 0644}, brdip_show, brdip_store},
+	{{"critical-action", 0644}, mcu_critical_action_show,
+	  mcu_critical_action_store},
+	{{"critical-temp", 0644}, mcu_critical_temp_show,
+	  mcu_critical_temp_store},
+	{{"repoweron-temp", 0664}, mcu_repoweron_temp_show,
+	  mcu_repoweron_temp_store},
+	{{"keep-ddr-poweron", 0664}, mcu_keep_ddr_poweron_show,
+	  mcu_keep_ddr_poweron_store},
+};
+
+static umode_t mcu_chip_is_visible(const void *data, enum hwmon_sensor_types type,
+								 u32 attr, int channel)
+{
+	switch (type) {
+	case hwmon_chip:
+		return 0444;
+	case hwmon_temp:
+		return 0444;
+	default:
+		return 0;
+	}
+}
+
+static int mcu_hwmon_chip_read(struct device *dev, u32 attr, int channel, long *val)
+{
+	struct mcu_ctx *ctx = dev_get_drvdata(dev);
+
+	switch (attr) {
+	case hwmon_chip_update_interval:
+		*val = ctx->hwmon_update_interval;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mcu_hwmon_temp_read(struct device *dev, u32 attr, int channel, long *val)
+{
+	int soc_temp, board_temp;
+
+	struct mcu_ctx *ctx = dev_get_drvdata(dev);
+	struct i2c_client *i2c = ctx->i2c;
+	mutex_lock(&ctx->update_lock);
+	soc_temp = mcu_i2c_read_byte(i2c, MCU_REG_SOC_TEMP);
+	mutex_unlock(&ctx->update_lock);
+
+	mutex_lock(&ctx->update_lock);
+	board_temp = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TEMP);
+	mutex_unlock(&ctx->update_lock);
+
+	switch (attr) {
+	case hwmon_temp_input:
+		if (channel == 0)
+			*val = soc_temp * 1000;
+		else if (channel == 1)
+			*val = board_temp * 1000;
+		else
+			*val = 0;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+
+static int mcu_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+			u32 attr, int channel, long *val)
+{
+
+	switch (type) {
+	case hwmon_chip:
+		return mcu_hwmon_chip_read(dev, attr, channel, val);
+	case hwmon_temp:
+		return mcu_hwmon_temp_read(dev, attr, channel, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static const struct hwmon_ops mcu_ops = {
+	.is_visible = mcu_chip_is_visible,
+	.read = mcu_hwmon_read,
+	.read_string = NULL,
+	.write = NULL,
+};
+
+static int register_hwmon_temp_sensor(struct i2c_client *i2c,
+			 struct mcu_ctx *ctx)
+{
+	struct device *dev = &i2c->dev;
+	struct hwmon_channel_info *info;
+	struct device *hwmon_dev;
+
+	mutex_init(&ctx->update_lock);
+
+	ctx->i2c = i2c;
+	ctx->hwmon_update_interval = 1000;
+
+	ctx->chip.ops = &mcu_ops;
+	ctx->chip.info = ctx->channel_info;
+	ctx->channel_info[0] = HWMON_CHANNEL_INFO(chip,
+		 HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL);
+	ctx->channel_info[1] = &ctx->temp_info;
+
+	info = &ctx->temp_info;
+	info->type = hwmon_temp;
+	info->config = ctx->channel_config;
+
+	ctx->channel_config[0] = HWMON_T_INPUT;
+	ctx->channel_config[1] = HWMON_T_INPUT;
+	hwmon_dev = devm_hwmon_device_register_with_info(
+						 dev,
+						 dev->driver->name,
+						 ctx,
+						 &ctx->chip,
+						 NULL);
+
+	if (IS_ERR(hwmon_dev))
+		return PTR_ERR(hwmon_dev);
+
+	return 0;
+}
+
+static int sub_probe(struct i2c_client *i2c,
+		     const struct mcu_features *features)
+{
+	struct mcu_ctx *ctx;
+	int i, err;
+
+	ctx = devm_kzalloc(i2c2dev(i2c), sizeof(*ctx), GFP_KERNEL);
+	if (ctx == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(mcu_attrs); ++i) {
+		err = device_create_file(i2c2dev(i2c), mcu_attrs + i);
+		if (err)
+			return err;
+	}
+
+	ctx->features = features;
+
+	assert(features->alert_status + 2 == features->alert_mask);
+
+	if ((features->id & MANGO_BOARD_TYPE_MASK) == 0x80 ) {
+		err = register_hwmon_temp_sensor(i2c, ctx);
+		if (err)
+			dev_warn(i2c2dev(i2c), "mcu board id %u register hwmon failed\n", features->id);
+	}
+
+	i2c_set_clientdata(i2c, ctx);
+	return 0;
+}
+
+static int mcu_i2c_probe(struct i2c_client *i2c,
+			const struct i2c_device_id *ignored)
+{
+	int id;
+	int err;
+	int i;
+	uint8_t regs[3];
+
+	/* get information from mcu through i2c */
+	err = mcu_i2c_sreadf(i2c, "%u8%u8%u8",
+			     MCU_REG_VERSION, regs,
+			     MCU_REG_PWROFF_REASON1, regs + 1,
+			     MCU_REG_PWROFF_REASON2, regs + 2);
+	if (err)
+		return err;
+
+	dev_info(i2c2dev(i2c), "MCU: version 0x%x, reason 0x%x/0x%x\n",
+		regs[0], regs[1], regs[2]);
+
+	id = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TYPE);
+	if (id < 0)
+		return id;
+
+	for (i = 0; i < ARRAY_SIZE(mcu_list); ++i) {
+		if (mcu_list[i].id == id)
+			return sub_probe(i2c, mcu_list + i);
+	}
+
+	dev_warn(i2c2dev(i2c), "not registered mcu id %u\n", id);
+	return -ENODEV;
+}
+
+static void mcu_i2c_remove(struct i2c_client *i2c)
+{
+	return;
+}
+
+static const struct of_device_id mcu_i2c_dt_table[] = {
+	{ .compatible = "sophgo,sg20xx-mcu" },
+	{},
+};
+
+static const struct i2c_device_id mcu_i2c_id_table[] = {
+	{ "sg20xx-mcu", 0 },
+	{},
+};
+
+static struct i2c_driver mcu_i2c_drv = {
+	.driver = {
+		.name = "sg20xx-mcu",
+		.of_match_table = mcu_i2c_dt_table,
+	},
+	.probe = mcu_i2c_probe,
+	.remove = mcu_i2c_remove,
+	.id_table = mcu_i2c_id_table,
+};
+
+module_i2c_driver(mcu_i2c_drv);
+
+MODULE_DESCRIPTION("MCU I2C driver for bm16xx soc platform");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chao.Wei@bitmain.com>");
diff --git a/include/dt-bindings/clock/sophgo-mango-clock.h b/include/dt-bindings/clock/sophgo-mango-clock.h
new file mode 100644
index 000000000000..aaed4ad27dc1
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo-mango-clock.h
@@ -0,0 +1,165 @@
+#ifndef __SOPHGO_MANGO_CLOCK__
+#define __SOPHGO_MANGO_CLOCK__
+
+#include <dt-bindings/clock/sophgo.h>
+
+/*div clock*/
+#define DIV_CLK_MPLL_RP_CPU_NORMAL_0 0
+#define DIV_CLK_MPLL_AXI_DDR_0 1
+#define DIV_CLK_FPLL_DDR01_1 2
+#define DIV_CLK_FPLL_DDR23_1 3
+#define DIV_CLK_FPLL_RP_CPU_NORMAL_1 4
+#define DIV_CLK_FPLL_50M_A53 5
+#define DIV_CLK_FPLL_TOP_RP_CMN_DIV2 6
+#define DIV_CLK_FPLL_UART_500M 7
+#define DIV_CLK_FPLL_AHB_LPC 8
+#define DIV_CLK_FPLL_EFUSE 9
+#define DIV_CLK_FPLL_TX_ETH0 10
+#define DIV_CLK_FPLL_PTP_REF_I_ETH0 11
+#define DIV_CLK_FPLL_REF_ETH0 12
+#define DIV_CLK_FPLL_EMMC 13
+#define DIV_CLK_FPLL_SD 14
+#define DIV_CLK_FPLL_TOP_AXI0 15
+#define DIV_CLK_FPLL_TOP_AXI_HSPERI 16
+#define DIV_CLK_FPLL_AXI_DDR_1 17
+#define DIV_CLK_FPLL_DIV_TIMER1 18
+#define DIV_CLK_FPLL_DIV_TIMER2 19
+#define DIV_CLK_FPLL_DIV_TIMER3 20
+#define DIV_CLK_FPLL_DIV_TIMER4 21
+#define DIV_CLK_FPLL_DIV_TIMER5 22
+#define DIV_CLK_FPLL_DIV_TIMER6 23
+#define DIV_CLK_FPLL_DIV_TIMER7 24
+#define DIV_CLK_FPLL_DIV_TIMER8 25
+#define DIV_CLK_FPLL_100K_EMMC 26
+#define DIV_CLK_FPLL_100K_SD 27
+#define DIV_CLK_FPLL_GPIO_DB 28
+#define DIV_CLK_DPLL0_DDR01_0 29
+#define DIV_CLK_DPLL1_DDR23_0 30
+
+/* MPLL */
+#define GATE_CLK_RP_CPU_NORMAL_DIV0 31
+#define GATE_CLK_AXI_DDR_DIV0 32
+
+/* FPLL */
+#define GATE_CLK_RP_CPU_NORMAL_DIV1 33
+#define GATE_CLK_A53_50M 34
+#define GATE_CLK_TOP_RP_CMN_DIV2 35
+#define GATE_CLK_HSDMA 36
+#define GATE_CLK_EMMC_100M 37
+#define GATE_CLK_SD_100M 38
+#define GATE_CLK_TX_ETH0 39
+#define GATE_CLK_PTP_REF_I_ETH0 40
+#define GATE_CLK_REF_ETH0 41
+#define GATE_CLK_UART_500M 42
+#define GATE_CLK_EFUSE 43
+
+#define GATE_CLK_AHB_LPC 44
+#define GATE_CLK_AHB_ROM 45
+#define GATE_CLK_AHB_SF 46
+
+#define GATE_CLK_APB_UART 47
+#define GATE_CLK_APB_TIMER 48
+#define GATE_CLK_APB_EFUSE 49
+#define GATE_CLK_APB_GPIO 50
+#define GATE_CLK_APB_GPIO_INTR 51
+#define GATE_CLK_APB_SPI 52
+#define GATE_CLK_APB_I2C 53
+#define GATE_CLK_APB_WDT 54
+#define GATE_CLK_APB_PWM 55
+#define GATE_CLK_APB_RTC 56
+
+#define GATE_CLK_AXI_PCIE0 57
+#define GATE_CLK_AXI_PCIE1 58
+#define GATE_CLK_SYSDMA_AXI 59
+#define GATE_CLK_AXI_DBG_I2C 60
+#define GATE_CLK_AXI_SRAM 61
+#define GATE_CLK_AXI_ETH0 62
+#define GATE_CLK_AXI_EMMC 63
+#define GATE_CLK_AXI_SD 64
+#define GATE_CLK_TOP_AXI0 65
+#define GATE_CLK_TOP_AXI_HSPERI 66
+
+#define GATE_CLK_TIMER1 67
+#define GATE_CLK_TIMER2 68
+#define GATE_CLK_TIMER3 69
+#define GATE_CLK_TIMER4 70
+#define GATE_CLK_TIMER5 71
+#define GATE_CLK_TIMER6 72
+#define GATE_CLK_TIMER7 73
+#define GATE_CLK_TIMER8 74
+#define GATE_CLK_100K_EMMC 75
+#define GATE_CLK_100K_SD 76
+#define GATE_CLK_GPIO_DB 77
+
+#define GATE_CLK_AXI_DDR_DIV1 78
+#define GATE_CLK_DDR01_DIV1 79
+#define GATE_CLK_DDR23_DIV1 80
+/* DPLL0 */
+#define GATE_CLK_DDR01_DIV0 81
+/* DPLL1 */
+#define GATE_CLK_DDR23_DIV0 82
+
+#define GATE_CLK_DDR01 83
+#define GATE_CLK_DDR23 84
+#define GATE_CLK_RP_CPU_NORMAL 85
+#define GATE_CLK_AXI_DDR 86
+#define GATE_CLK_RXU0 87
+#define GATE_CLK_RXU1 88
+#define GATE_CLK_RXU2 89
+#define GATE_CLK_RXU3 90
+#define GATE_CLK_RXU4 91
+#define GATE_CLK_RXU5 92
+#define GATE_CLK_RXU6 93
+#define GATE_CLK_RXU7 94
+#define GATE_CLK_RXU8 95
+#define GATE_CLK_RXU9 96
+#define GATE_CLK_RXU10 97
+#define GATE_CLK_RXU11 98
+#define GATE_CLK_RXU12 99
+#define GATE_CLK_RXU13 100
+#define GATE_CLK_RXU14 101
+#define GATE_CLK_RXU15 102
+#define GATE_CLK_RXU16 103
+#define GATE_CLK_RXU17 104
+#define GATE_CLK_RXU18 105
+#define GATE_CLK_RXU19 106
+#define GATE_CLK_RXU20 107
+#define GATE_CLK_RXU21 108
+#define GATE_CLK_RXU22 109
+#define GATE_CLK_RXU23 110
+#define GATE_CLK_RXU24 111
+#define GATE_CLK_RXU25 112
+#define GATE_CLK_RXU26 113
+#define GATE_CLK_RXU27 114
+#define GATE_CLK_RXU28 115
+#define GATE_CLK_RXU29 116
+#define GATE_CLK_RXU30 117
+#define GATE_CLK_RXU31 118
+#define GATE_CLK_MP0 119
+#define GATE_CLK_MP1 120
+#define GATE_CLK_MP2 121
+#define GATE_CLK_MP3 122
+#define GATE_CLK_MP4 123
+#define GATE_CLK_MP5 124
+#define GATE_CLK_MP6 125
+#define GATE_CLK_MP7 126
+#define GATE_CLK_MP8 127
+#define GATE_CLK_MP9 128
+#define GATE_CLK_MP10 129
+#define GATE_CLK_MP11 130
+#define GATE_CLK_MP12 131
+#define GATE_CLK_MP13 132
+#define GATE_CLK_MP14 133
+#define GATE_CLK_MP15 134
+
+/* MUX */
+#define MUX_CLK_DDR01 0
+#define MUX_CLK_DDR23 1
+#define MUX_CLK_RP_CPU_NORMAL 2
+#define MUX_CLK_AXI_DDR 3
+
+#define S0_DIV_CLK_TABLE		0
+#define S1_DIV_CLK_TABLE		1
+#define S0_MUX_CLK_TABLE		2
+#define S1_MUX_CLK_TABLE		3
+#endif
diff --git a/include/dt-bindings/clock/sophgo.h b/include/dt-bindings/clock/sophgo.h
new file mode 100644
index 000000000000..5584243f9135
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo.h
@@ -0,0 +1,15 @@
+#ifndef __SOPHGO_CLK__
+#define __SOPHGO_CLK__
+
+//PLL ID
+#define MPLL_CLK	0
+#define FPLL_CLK	3
+#define DPLL0_CLK	4
+#define DPLL1_CLK	5
+
+//clock mode
+#define NORMAL_MODE	0
+#define FAST_MODE	1
+#define SAFE_MODE	2
+#define BYPASS_MODE	3
+#endif
diff --git a/include/dt-bindings/reset/sophgo-mango-resets.h b/include/dt-bindings/reset/sophgo-mango-resets.h
new file mode 100644
index 000000000000..9ff8ca4c3d67
--- /dev/null
+++ b/include/dt-bindings/reset/sophgo-mango-resets.h
@@ -0,0 +1,96 @@
+/*
+ * Sophgo SoCs Reset definitions
+ *
+ * Copyright (c) 2018 Bitmain Ltd.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_RST_MANGO_H_
+#define _DT_BINDINGS_RST_MANGO_H_
+
+#define RST_MAIN_AP                            0
+#define RST_RISCV_CPU                          1
+#define RST_RISCV_LOW_SPEED_LOGIC              2
+#define RST_RISCV_CMN                          3
+#define RST_HSDMA                              4
+#define RST_SYSDMA                             5
+#define RST_EFUSE0                             6
+#define RST_EFUSE1                             7
+#define RST_RTC                                8
+#define RST_TIMER                              9
+#define RST_WDT                                10
+#define RST_AHB_ROM0                           11
+#define RST_AHB_ROM1                           12
+#define RST_I2C0                               13
+#define RST_I2C1                               14
+#define RST_I2C2                               15
+#define RST_I2C3                               16
+#define RST_GPIO0                              17
+#define RST_GPIO1                              18
+#define RST_GPIO2                              19
+#define RST_PWM                                20
+#define RST_AXI_SRAM0                          21
+#define RST_AXI_SRAM1                          22
+#define RST_SF0                                23
+#define RST_SF1                                24
+#define RST_LPC                                25
+#define RST_ETH0                               26
+#define RST_EMMC                               27
+#define RST_SD                                 28
+#define RST_UART0                              29
+#define RST_UART1                              30
+#define RST_UART2                              31
+
+#define RST_UART3                              32
+#define RST_SPI0                               33
+#define RST_SPI1                               34
+#define RST_DBG_I2C                            35
+#define RST_PCIE0                              36
+#define RST_PCIE1                              37
+#define RST_DDR0                               38
+#define RST_DDR1                               39
+#define RST_DDR2                               40
+#define RST_DDR3                               41
+#define RST_FAU0                               42
+#define RST_FAU1                               43
+#define RST_FAU2                               44
+#define RST_RXU0                               45
+#define RST_RXU1                               46
+#define RST_RXU2                               47
+#define RST_RXU3                               48
+#define RST_RXU4                               49
+#define RST_RXU5                               50
+#define RST_RXU6                               51
+#define RST_RXU7                               52
+#define RST_RXU8                               53
+#define RST_RXU9                               54
+#define RST_RXU10                              55
+#define RST_RXU11                              56
+#define RST_RXU12                              57
+#define RST_RXU13                              58
+#define RST_RXU14                              59
+#define RST_RXU15                              60
+#define RST_RXU16                              61
+#define RST_RXU17                              62
+#define RST_RXU18                              63
+#define RST_RXU19                              64
+#define RST_RXU20                              65
+#define RST_RXU21                              66
+#define RST_RXU22                              67
+#define RST_RXU23                              68
+#define RST_RXU24                              69
+#define RST_RXU25                              70
+#define RST_RXU26                              71
+#define RST_RXU27                              72
+#define RST_RXU28                              73
+#define RST_RXU29                              74
+#define RST_RXU30                              75
+#define RST_RXU31                              76
+
+#define RST_MAX_NUM  (RST_RXU31+1)
+
+#endif
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index c7b056af9ef0..9302cfb973be 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -439,6 +439,7 @@ typedef struct elf64_shdr {
 #define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers */
 #define NT_MIPS_FP_MODE	0x801		/* MIPS floating-point mode */
 #define NT_MIPS_MSA	0x802		/* MIPS SIMD registers */
+#define NT_RISCV_VECTOR 	0x900	/* RISC-V vector registers */
 #define NT_LOONGARCH_CPUCFG	0xa00	/* LoongArch CPU config registers */
 #define NT_LOONGARCH_CSR	0xa01	/* LoongArch control and status registers */
 #define NT_LOONGARCH_LSX	0xa02	/* LoongArch Loongson SIMD Extension registers */
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 79c012fbb49c..9d3034d76e97 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -53,6 +53,7 @@ note_buf_t __percpu *crash_notes;
 
 /* Flag to indicate we are going to kexec a new kernel */
 bool kexec_in_progress = false;
+EXPORT_SYMBOL(kexec_in_progress);
 
 
 /* Location of the reserved area for the crash kernel */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2558ab9033be..f0132242117b 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -8307,6 +8307,9 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
 	if (kthread_is_per_cpu(p))
 		return 0;
 
+	if (is_migration_disabled(p))
+		return 0;
+
 	if (!cpumask_test_cpu(env->dst_cpu, p->cpus_ptr)) {
 		int cpu;
 
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index 475ecceda768..fcd2f4af11da 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -78,7 +78,7 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
 	if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
 		    !tick_device_is_functional(dev)) {
 
-		pr_info("Clockevents: could not switch to one-shot mode:");
+		pr_debug("Clockevents: could not switch to one-shot mode:");
 		if (!dev) {
 			pr_cont(" no tick device\n");
 		} else {
diff --git a/mm/memblock.c b/mm/memblock.c
index 511d4783dcf1..9fdea6904201 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1693,6 +1693,28 @@ static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit)
 	return max_addr;
 }
 
+#ifdef CONFIG_HIGHMEM
+phys_addr_t __init_memblock find_max_low_addr(phys_addr_t limit)
+{
+	phys_addr_t max_low_addr = PHYS_ADDR_MAX;
+	phys_addr_t max_low_addr_limit;
+	struct memblock_region *r;
+
+	max_low_addr_limit = memblock_start_of_DRAM() + limit;
+
+	for_each_mem_region(r) {
+		if ((r->base+r->size) <= max_low_addr_limit)
+			max_low_addr = r->base + r->size;
+		else if (r->base < max_low_addr_limit)
+			max_low_addr = max_low_addr_limit;
+		else
+			continue;
+	}
+
+	return max_low_addr;
+}
+#endif
+
 void __init memblock_enforce_memory_limit(phys_addr_t limit)
 {
 	phys_addr_t max_addr;
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 08f0587d15ea..0ff707bc1896 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -46,12 +46,12 @@ if IS_BUILTIN(CONFIG_COMMON_CLK):
     LX_GDBPARSED(CLK_GET_RATE_NOCACHE)
 
 /* linux/fs.h */
-LX_VALUE(SB_RDONLY)
-LX_VALUE(SB_SYNCHRONOUS)
-LX_VALUE(SB_MANDLOCK)
-LX_VALUE(SB_DIRSYNC)
-LX_VALUE(SB_NOATIME)
-LX_VALUE(SB_NODIRATIME)
+LX_GDBPARSED(SB_RDONLY)
+LX_GDBPARSED(SB_SYNCHRONOUS)
+LX_GDBPARSED(SB_MANDLOCK)
+LX_GDBPARSED(SB_DIRSYNC)
+LX_GDBPARSED(SB_NOATIME)
+LX_GDBPARSED(SB_NODIRATIME)
 
 /* linux/htimer.h */
 LX_GDBPARSED(hrtimer_resolution)
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 67cd420dcf89..de2a21eb25e3 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -60,8 +60,8 @@ deploy_kernel_headers () {
 
 	(
 		cd $srctree
-		find . arch/$SRCARCH -maxdepth 1 -name Makefile\*
-		find include scripts -type f -o -type l
+		find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl
+		find arch/*/include include scripts -type f -o -type l
 		find arch/$SRCARCH -name Kbuild.platforms -o -name Platform
 		find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f
 	) > debian/hdrsrcfiles
@@ -86,6 +86,8 @@ deploy_kernel_headers () {
 
 	# copy .config manually to be where it's expected to be
 	cp $KCONFIG_CONFIG $destdir/.config
+	cp System.map $destdir/
+	cp certs/*.pem $destdir/certs/
 
 	mkdir -p $pdir/lib/modules/$version/
 	ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index a26f2a2d44cf..71df5aeabd08 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -295,8 +295,7 @@ enum {
 
 /* quirks for ATI/AMD HDMI */
 #define AZX_DCAPS_PRESET_ATI_HDMI \
-	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB|\
-	 AZX_DCAPS_NO_MSI64)
+	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB)
 
 /* quirks for ATI HDMI with snoop off */
 #define AZX_DCAPS_PRESET_ATI_HDMI_NS \
@@ -310,7 +309,7 @@ enum {
 
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
-	(AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
+	(AZX_DCAPS_CORBRP_SELF_CLEAR |\
 	 AZX_DCAPS_SNOOP_TYPE(NVIDIA))
 
 #define AZX_DCAPS_PRESET_CTHDA \
diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c
index 6cd0be7c1bb4..d960880dd903 100644
--- a/tools/lib/perf/cpumap.c
+++ b/tools/lib/perf/cpumap.c
@@ -351,8 +351,8 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
 					 struct perf_cpu_map *other)
 {
 	struct perf_cpu *tmp_cpus;
-	int tmp_len;
-	int i, j, k;
+	unsigned int tmp_len;
+	unsigned int i, j, k;
 	struct perf_cpu_map *merged;
 
 	if (perf_cpu_map__is_subset(orig, other))
@@ -369,7 +369,7 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
 
 	/* Standard merge algorithm from wikipedia */
 	i = j = k = 0;
-	while (i < orig->nr && j < other->nr) {
+	while (i < (unsigned int)orig->nr && j < (unsigned int)other->nr) {
 		if (orig->map[i].cpu <= other->map[j].cpu) {
 			if (orig->map[i].cpu == other->map[j].cpu)
 				j++;
@@ -378,10 +378,10 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
 			tmp_cpus[k++] = other->map[j++];
 	}
 
-	while (i < orig->nr)
+	while (i < (unsigned int)orig->nr)
 		tmp_cpus[k++] = orig->map[i++];
 
-	while (j < other->nr)
+	while (j < (unsigned int)other->nr)
 		tmp_cpus[k++] = other->map[j++];
 	assert(k <= tmp_len);
 
diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
index 7d3050134ae0..603dbb5ae4dc 100644
--- a/tools/perf/arch/riscv/util/Build
+++ b/tools/perf/arch/riscv/util/Build
@@ -1,4 +1,5 @@
 perf-y += perf_regs.o
+perf-y += header.o
 
 perf-$(CONFIG_DWARF) += dwarf-regs.o
 perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/riscv/util/header.c b/tools/perf/arch/riscv/util/header.c
new file mode 100644
index 000000000000..4a41856938a8
--- /dev/null
+++ b/tools/perf/arch/riscv/util/header.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of get_cpuid().
+ *
+ * Author: Nikita Shubin <n.shubin@yadro.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <api/fs/fs.h>
+#include <errno.h>
+#include "../../util/debug.h"
+#include "../../util/header.h"
+
+#define CPUINFO_MVEN	"mvendorid"
+#define CPUINFO_MARCH	"marchid"
+#define CPUINFO_MIMP	"mimpid"
+#define CPUINFO		"/proc/cpuinfo"
+
+static char *_get_field(const char *line)
+{
+	char *line2, *nl;
+
+	line2 = strrchr(line, ' ');
+	if (!line2)
+		return NULL;
+
+	line2++;
+	nl = strrchr(line, '\n');
+	if (!nl)
+		return NULL;
+
+	return strndup(line2, nl - line2);
+}
+
+static char *_get_cpuid(void)
+{
+	char *line = NULL;
+	char *mvendorid = NULL;
+	char *marchid = NULL;
+	char *mimpid = NULL;
+	char *cpuid = NULL;
+	int read;
+	unsigned long line_sz;
+	FILE *cpuinfo;
+
+	cpuinfo = fopen(CPUINFO, "r");
+	if (cpuinfo == NULL)
+		return cpuid;
+
+	while ((read = getline(&line, &line_sz, cpuinfo)) != -1) {
+		if (!strncmp(line, CPUINFO_MVEN, strlen(CPUINFO_MVEN))) {
+			mvendorid = _get_field(line);
+			if (!mvendorid)
+				goto free;
+		} else if (!strncmp(line, CPUINFO_MARCH, strlen(CPUINFO_MARCH))) {
+			marchid = _get_field(line);
+			if (!marchid)
+				goto free;
+		} else if (!strncmp(line, CPUINFO_MIMP, strlen(CPUINFO_MIMP))) {
+			mimpid = _get_field(line);
+			if (!mimpid)
+				goto free;
+
+			break;
+		}
+	}
+
+	if (!mvendorid || !marchid || !mimpid)
+		goto free;
+
+	if (asprintf(&cpuid, "%s-%s-%s", mvendorid, marchid, mimpid) < 0)
+		cpuid = NULL;
+
+free:
+	fclose(cpuinfo);
+	free(mvendorid);
+	free(marchid);
+	free(mimpid);
+
+	return cpuid;
+}
+
+int get_cpuid(char *buffer, size_t sz)
+{
+	char *cpuid = _get_cpuid();
+	int ret = 0;
+
+	if (sz < strlen(cpuid)) {
+		ret = -EINVAL;
+		goto free;
+	}
+
+	scnprintf(buffer, sz, "%s", cpuid);
+free:
+	free(cpuid);
+	return ret;
+}
+
+char *
+get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
+{
+	return _get_cpuid();
+}
