diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt
index 631d27cd89d6..a7d558a2b9b2 100644
--- a/Documentation/devicetree/bindings/clock/sun8i-de2.txt
+++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt
@@ -4,22 +4,28 @@ Allwinner Display Engine 2.0 Clock Control Binding
 Required properties :
 - compatible: must contain one of the following compatibles:
 		- "allwinner,sun8i-a83t-de2-clk"
+		- "allwinner,sun8i-h3-de2-clk"
 		- "allwinner,sun8i-v3s-de2-clk"
+		- "allwinner,sun50i-a64-de2-clk"
 		- "allwinner,sun50i-h5-de2-clk"
 
 - reg: Must contain the registers base address and length
 - clocks: phandle to the clocks feeding the display engine subsystem.
 	  Three are needed:
-  - "mod": the display engine module clock
+  - "mod": the display engine module clock (on A83T it's the DE PLL)
   - "bus": the bus clock for the whole display engine subsystem
 - clock-names: Must contain the clock names described just above
 - resets: phandle to the reset control for the display engine subsystem.
 - #clock-cells : must contain 1
 - #reset-cells : must contain 1
 
+Additional required properties for "allwinner,sun50i-a64-de2-clk" :
+- allwinner,sram: See Documentation/devicetree/bindings/sram/sunxi-sram.txt,
+		  should be the SRAM C section on A64 SoC.
+
 Example:
 de2_clocks: clock@1000000 {
-	compatible = "allwinner,sun8i-a83t-de2-clk";
+	compatible = "allwinner,sun8i-h3-de2-clk";
 	reg = <0x01000000 0x100000>;
 	clocks = <&ccu CLK_BUS_DE>,
 		 <&ccu CLK_DE>;
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 92441086caba..84739924bc77 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -87,18 +87,19 @@ Required properties:
    * allwinner,sun6i-a31-tcon
    * allwinner,sun6i-a31s-tcon
    * allwinner,sun8i-a33-tcon
+   * allwinner,sun8i-h3-tcon
    * allwinner,sun8i-v3s-tcon
+   * allwinner,sun50i-a64-tcon0
+   * allwinner,sun50i-a64-tcon1
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
  - clocks: phandles to the clocks feeding the TCON. Three are needed:
    - 'ahb': the interface clocks
-   - 'tcon-ch0': The clock driving the TCON channel 0
  - resets: phandles to the reset controllers driving the encoder
    - "lcd": the reset line for the TCON channel 0
 
  - clock-names: the clock names mentioned above
  - reset-names: the reset names mentioned above
- - clock-output-names: Name of the pixel clock created
 
 - ports: A ports node with endpoint definitions as defined in
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
@@ -112,7 +113,25 @@ Required properties:
   channel the endpoint is associated to. If that property is not
   present, the endpoint number will be used as the channel number.
 
-On SoCs other than the A33 and V3s, there is one more clock required:
+For the following compatibles:
+   * allwinner,sun5i-a13-tcon
+   * allwinner,sun6i-a31-tcon
+   * allwinner,sun6i-a31s-tcon
+   * allwinner,sun8i-a33-tcon
+   * allwinner,sun8i-v3s-tcon
+   * allwinner,snu50i-a64-tcon0
+there is one more clock and one more property required:
+ - clocks:
+   - 'tcon-ch0': The clock driving the TCON channel 0
+ - clock-output-names: Name of the pixel clock created
+
+For the following compatibles:
+   * allwinner,sun5i-a13-tcon
+   * allwinner,sun6i-a31-tcon
+   * allwinner,sun6i-a31s-tcon
+   * allwinner,sun8i-h3-tcon
+   * allwinner,sun50i-a64-tcon1
+there is one more clock required:
    - 'tcon-ch1': The clock driving the TCON channel 1
 
 DRC
@@ -207,6 +226,10 @@ supported.
 Required properties:
   - compatible: value must be one of:
     * allwinner,sun8i-v3s-de2-mixer
+    * allwinner,sun8i-h3-de2-mixer0
+    * allwinner,sun8i-h3-de2-mixer1
+    * allwinner,sun50i-a64-de2-mixer0
+    * allwinner,sun50i-a64-de2-mixer1
   - reg: base address and size of the memory-mapped region.
   - clocks: phandles to the clocks feeding the mixer
     * bus: the mixer interface clock
@@ -218,7 +241,6 @@ Required properties:
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
   first port should be the input endpoints, the second one the output
 
-
 Display Engine Pipeline
 -----------------------
 
@@ -233,7 +255,9 @@ Required properties:
     * allwinner,sun6i-a31-display-engine
     * allwinner,sun6i-a31s-display-engine
     * allwinner,sun8i-a33-display-engine
+    * allwinner,sun8i-h3-display-engine
     * allwinner,sun8i-v3s-display-engine
+    * allwinner,sun50i-a64-display-engine
 
   - allwinner,pipelines: list of phandle to the display engine
     frontends (DE 1.0) or mixers (DE 2.0) available.
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
index cbc7847dbf6c..0f00abd40a50 100644
--- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -11,6 +11,7 @@ Required properties:
   * allwinner,sun8i-a33-usb-phy
   * allwinner,sun8i-a83t-usb-phy
   * allwinner,sun8i-h3-usb-phy
+  * allwinner,sun8i-r40-usb-phy
   * allwinner,sun8i-v3s-usb-phy
   * allwinner,sun50i-a64-usb-phy
 - reg : a list of offset + length pairs
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index fc5da6080759..597dcd4143e5 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
 - compatible: should be one of the following:
    - "allwinner,sun4i-a10-i2s"
    - "allwinner,sun6i-a31-i2s"
+   - "allwinner,sun8i-a83t-i2s"
    - "allwinner,sun8i-h3-i2s"
 - reg: physical base address of the controller and length of memory mapped
   region.
@@ -23,6 +24,7 @@ Required properties:
 
 Required properties for the following compatibles:
 	- "allwinner,sun6i-a31-i2s"
+	- "allwinner,sun8i-a83t-i2s"
 	- "allwinner,sun8i-h3-i2s"
 - resets: phandle to the reset line for this codec
 
diff --git a/MAINTAINERS b/MAINTAINERS
index e2dd302345c2..cd6452088f64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13924,6 +13924,7 @@ M:	Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/usb/lan78xx.*
+F:	include/dt-bindings/net/microchip-lan78xx.h
 
 USB MASS STORAGE DRIVER
 M:	Alan Stern <stern@rowland.harvard.edu>
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index eff87a344566..841dbbb1aa35 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -75,6 +75,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
 	bcm2835-rpi-a-plus.dtb \
 	bcm2836-rpi-2-b.dtb \
 	bcm2837-rpi-3-b.dtb \
+	bcm2837-rpi-3-b-plus.dtb \
 	bcm2835-rpi-zero.dtb \
 	bcm2835-rpi-zero-w.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += \
@@ -891,6 +892,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
 	sun7i-a20-olinuxino-lime2.dtb \
 	sun7i-a20-olinuxino-lime2-emmc.dtb \
 	sun7i-a20-olinuxino-micro.dtb \
+	sun7i-a20-olinuxino-micro-emmc.dtb \
 	sun7i-a20-orangepi.dtb \
 	sun7i-a20-orangepi-mini.dtb \
 	sun7i-a20-pcduino3.dtb \
@@ -916,13 +918,20 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-a83t-allwinner-h8homlet-v2.dtb \
 	sun8i-a83t-bananapi-m3.dtb \
 	sun8i-a83t-cubietruck-plus.dtb \
+	sun8i-h2-plus-bananapi-m2-zero.dtb \
+	sun8i-h2-plus-ipfire-nano.dtb \
+	sun8i-h2-plus-nanopi-duo.dtb \
+	sun8i-h2-plus-orangepi-r1.dtb \
 	sun8i-h2-plus-orangepi-zero.dtb \
+	sun8i-h2-plus-sunvell-r69.dtb \
 	sun8i-h3-bananapi-m2-plus.dtb \
 	sun8i-h3-beelink-x2.dtb \
+	sun8i-h3-libretech-tritium.dtb \
 	sun8i-h3-nanopi-m1.dtb	\
 	sun8i-h3-nanopi-m1-plus.dtb \
 	sun8i-h3-nanopi-neo.dtb \
 	sun8i-h3-nanopi-neo-air.dtb \
+	sun8i-h3-nanopi-r1.dtb \
 	sun8i-h3-orangepi-2.dtb \
 	sun8i-h3-orangepi-lite.dtb \
 	sun8i-h3-orangepi-one.dtb \
@@ -930,8 +939,10 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-h3-orangepi-pc-plus.dtb \
 	sun8i-h3-orangepi-plus.dtb \
 	sun8i-h3-orangepi-plus2e.dtb \
+	sun8i-h3-orangepi-zeroplus2.dtb \
 	sun8i-r16-bananapi-m2m.dtb \
 	sun8i-r16-parrot.dtb \
+	sun8i-r40-bananapi-m2-ultra.dtb \
 	sun8i-v3s-licheepi-zero.dtb \
 	sun8i-v3s-licheepi-zero-dock.dtb
 dtb-$(CONFIG_MACH_SUN9I) += \
diff --git a/arch/arm/boot/dts/armada-388-clearfog-base.dts b/arch/arm/boot/dts/armada-388-clearfog-base.dts
index 22ed07fc2979..39c4f989aaa6 100644
--- a/arch/arm/boot/dts/armada-388-clearfog-base.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog-base.dts
@@ -1,109 +1,965 @@
-/*
- * Device Tree file for SolidRun Clearfog Base revision A1 rev 2.0 (88F6828)
- *
- *  Copyright (C) 2015 Russell King
- *
- * This board is in development; the contents of this file work with
- * the A1 rev 2.0 of the board, which does not represent final
- * production board.  Things will change, don't expect this file to
- * remain compatible info the future.
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- *  a) This file is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     version 2 as published by the Free Software Foundation.
- *
- *     This file is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- *  b) Permission is hereby granted, free of charge, to any person
- *     obtaining a copy of this software and associated documentation
- *     files (the "Software"), to deal in the Software without
- *     restriction, including without limitation the rights to use,
- *     copy, modify, merge, publish, distribute, sublicense, and/or
- *     sell copies of the Software, and to permit persons to whom the
- *     Software is furnished to do so, subject to the following
- *     conditions:
- *
- *     The above copyright notice and this permission notice shall be
- *     included in all copies or substantial portions of the Software.
- *
- *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *     OTHER DEALINGS IN THE SOFTWARE.
- */
-
 /dts-v1/;
-#include "armada-388-clearfog.dtsi"
 
 / {
+	#address-cells = < 0x01 >;
+	#size-cells = < 0x01 >;
 	model = "SolidRun Clearfog Base A1";
-	compatible = "solidrun,clearfog-base-a1",
-		"solidrun,clearfog-a1", "marvell,armada388",
-		"marvell,armada385", "marvell,armada380";
+	compatible = "solidrun,clearfog-base-a1\0solidrun,clearfog-a1\0marvell,armada388\0marvell,armada385\0marvell,armada380";
 
-	gpio-keys {
-		compatible = "gpio-keys";
-		pinctrl-0 = <&rear_button_pins>;
-		pinctrl-names = "default";
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
 
-		button_0 {
-			/* The rear SW3 button */
-			label = "Rear Button";
-			gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
-			linux,can-disable;
-			linux,code = <BTN_0>;
+	aliases {
+		gpio0 = "/soc/internal-regs/gpio@18100";
+		gpio1 = "/soc/internal-regs/gpio@18140";
+		serial0 = "/soc/internal-regs/serial@12000";
+		serial1 = "/soc/internal-regs/serial@12100";
+		ethernet1 = "/soc/internal-regs/ethernet@70000";
+		ethernet2 = "/soc/internal-regs/ethernet@30000";
+		ethernet3 = "/soc/internal-regs/ethernet@34000";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = < 0x00 0x10000000 >;
+	};
+
+	pmu {
+		compatible = "arm,cortex-a9-pmu";
+		interrupts-extended = < 0x01 0x03 >;
+	};
+
+	soc {
+		compatible = "marvell,armada380-mbus\0simple-bus";
+		#address-cells = < 0x02 >;
+		#size-cells = < 0x01 >;
+		controller = < 0x02 >;
+		interrupt-parent = < 0x03 >;
+		pcie-mem-aperture = < 0xe0000000 0x8000000 >;
+		pcie-io-aperture = < 0xe8000000 0x100000 >;
+		ranges = < 0xf0010000 0x00 0xf1000000 0x100000 0x11d0000 0x00 0xfff00000 0x100000 0x9190000 0x00 0xf1100000 0x10000 0x9150000 0x00 0xf1110000 0x10000 0xc040000 0x00 0xf1200000 0x100000 >;
+
+		bootrom {
+			compatible = "marvell,bootrom";
+			reg = < 0x11d0000 0x00 0x200000 >;
+		};
+
+		devbus-bootcs {
+			compatible = "marvell,mvebu-devbus";
+			reg = < 0xf0010000 0x10400 0x08 >;
+			ranges = < 0x00 0x12f0000 0x00 0xffffffff >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		devbus-cs0 {
+			compatible = "marvell,mvebu-devbus";
+			reg = < 0xf0010000 0x10408 0x08 >;
+			ranges = < 0x00 0x13e0000 0x00 0xffffffff >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		devbus-cs1 {
+			compatible = "marvell,mvebu-devbus";
+			reg = < 0xf0010000 0x10410 0x08 >;
+			ranges = < 0x00 0x13d0000 0x00 0xffffffff >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		devbus-cs2 {
+			compatible = "marvell,mvebu-devbus";
+			reg = < 0xf0010000 0x10418 0x08 >;
+			ranges = < 0x00 0x13b0000 0x00 0xffffffff >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		devbus-cs3 {
+			compatible = "marvell,mvebu-devbus";
+			reg = < 0xf0010000 0x10420 0x08 >;
+			ranges = < 0x00 0x1370000 0x00 0xffffffff >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		internal-regs {
+			compatible = "simple-bus";
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			ranges = < 0x00 0xf0010000 0x00 0x100000 >;
+
+			cache-controller@8000 {
+				compatible = "arm,pl310-cache";
+				reg = < 0x8000 0x1000 >;
+				cache-unified;
+				cache-level = < 0x02 >;
+				arm,double-linefill-incr = < 0x00 >;
+				arm,double-linefill-wrap = < 0x00 >;
+				arm,double-linefill = < 0x00 >;
+				prefetch-data = < 0x01 >;
+			};
+
+			scu@c000 {
+				compatible = "arm,cortex-a9-scu";
+				reg = < 0xc000 0x58 >;
+			};
+
+			timer@c600 {
+				compatible = "arm,cortex-a9-twd-timer";
+				reg = < 0xc600 0x20 >;
+				interrupts = < 0x01 0x0d 0x301 >;
+				clocks = < 0x04 0x02 >;
+			};
+
+			interrupt-controller@d000 {
+				compatible = "arm,cortex-a9-gic";
+				#interrupt-cells = < 0x03 >;
+				#size-cells = < 0x00 >;
+				interrupt-controller;
+				reg = < 0xd000 0x1000 0xc100 0x100 >;
+				linux,phandle = < 0x03 >;
+				phandle = < 0x03 >;
+			};
+
+			i2c@11000 {
+				compatible = "marvell,mv78230-a0-i2c\0marvell,mv64xxx-i2c";
+				reg = < 0x11000 0x20 >;
+				#address-cells = < 0x01 >;
+				#size-cells = < 0x00 >;
+				interrupts = < 0x00 0x02 0x04 >;
+				timeout-ms = < 0x3e8 >;
+				clocks = < 0x04 0x00 >;
+				status = "okay";
+				clock-frequency = < 0x61a80 >;
+				pinctrl-0 = < 0x05 >;
+				pinctrl-names = "default";
+
+				gpio-expander@20 {
+					compatible = "nxp,pca9555";
+					gpio-controller;
+					#gpio-cells = < 0x02 >;
+					reg = < 0x20 >;
+					linux,phandle = < 0x1d >;
+					phandle = < 0x1d >;
+
+					pcie1_0_clkreq {
+						gpio-hog;
+						gpios = < 0x00 0x01 >;
+						input;
+						line-name = "pcie1.0-clkreq";
+					};
+
+					pcie1_0_w_disable {
+						gpio-hog;
+						gpios = < 0x03 0x01 >;
+						output-low;
+						line-name = "pcie1.0-w-disable";
+					};
+
+					usb3_ilimit {
+						gpio-hog;
+						gpios = < 0x05 0x01 >;
+						input;
+						line-name = "usb3-current-limit";
+					};
+
+					usb3_power {
+						gpio-hog;
+						gpios = < 0x06 0x00 >;
+						output-high;
+						line-name = "usb3-power";
+					};
+
+					m2_devslp {
+						gpio-hog;
+						gpios = < 0x0b 0x00 >;
+						output-low;
+						line-name = "m.2 devslp";
+					};
+				};
+
+				mcp3021@4c {
+					compatible = "microchip,mcp3021";
+					reg = < 0x4c >;
+				};
+			};
+
+			i2c@11100 {
+				compatible = "marvell,mv78230-a0-i2c\0marvell,mv64xxx-i2c";
+				reg = < 0x11100 0x20 >;
+				#address-cells = < 0x01 >;
+				#size-cells = < 0x00 >;
+				interrupts = < 0x00 0x03 0x04 >;
+				timeout-ms = < 0x3e8 >;
+				clocks = < 0x04 0x00 >;
+				status = "okay";
+				clock-frequency = < 0x186a0 >;
+				pinctrl-0 = < 0x06 >;
+				pinctrl-names = "default";
+				linux,phandle = < 0x1f >;
+				phandle = < 0x1f >;
+			};
+
+			serial@12000 {
+				compatible = "snps,dw-apb-uart";
+				reg = < 0x12000 0x100 >;
+				reg-shift = < 0x02 >;
+				interrupts = < 0x00 0x0c 0x04 >;
+				reg-io-width = < 0x01 >;
+				clocks = < 0x04 0x00 >;
+				status = "okay";
+				pinctrl-0 = < 0x07 >;
+				pinctrl-names = "default";
+			};
+
+			serial@12100 {
+				compatible = "snps,dw-apb-uart";
+				reg = < 0x12100 0x100 >;
+				reg-shift = < 0x02 >;
+				interrupts = < 0x00 0x0d 0x04 >;
+				reg-io-width = < 0x01 >;
+				clocks = < 0x04 0x00 >;
+				status = "okay";
+				pinctrl-0 = < 0x08 >;
+				pinctrl-names = "default";
+			};
+
+			pinctrl@18000 {
+				reg = < 0x18000 0x20 >;
+				compatible = "marvell,mv88f6828-pinctrl";
+
+				ge-rgmii-pins-0 {
+					marvell,pins = "mpp6\0mpp7\0mpp8\0mpp9\0mpp10\0mpp11\0mpp12\0mpp13\0mpp14\0mpp15\0mpp16\0mpp17";
+					marvell,function = "ge0";
+					linux,phandle = < 0x0b >;
+					phandle = < 0x0b >;
+				};
+
+				ge-rgmii-pins-1 {
+					marvell,pins = "mpp21\0mpp27\0mpp28\0mpp29\0mpp30\0mpp31\0mpp32\0mpp37\0mpp38\0mpp39\0mpp40\0mpp41";
+					marvell,function = "ge1";
+				};
+
+				i2c-pins-0 {
+					marvell,pins = "mpp2\0mpp3";
+					marvell,function = "i2c0";
+					linux,phandle = < 0x05 >;
+					phandle = < 0x05 >;
+				};
+
+				mdio-pins {
+					marvell,pins = "mpp4\0mpp5";
+					marvell,function = "ge";
+					linux,phandle = < 0x10 >;
+					phandle = < 0x10 >;
+				};
+
+				ref-clk-pins-0 {
+					marvell,pins = "mpp45";
+					marvell,function = "ref";
+				};
+
+				ref-clk-pins-1 {
+					marvell,pins = "mpp46";
+					marvell,function = "ref";
+				};
+
+				spi-pins-0 {
+					marvell,pins = "mpp22\0mpp23\0mpp24\0mpp25";
+					marvell,function = "spi0";
+				};
+
+				spi-pins-1 {
+					marvell,pins = "mpp56\0mpp57\0mpp58\0mpp59";
+					marvell,function = "spi1";
+					linux,phandle = < 0x1b >;
+					phandle = < 0x1b >;
+				};
+
+				nand-pins {
+					marvell,pins = "mpp22\0mpp34\0mpp23\0mpp33\0mpp38\0mpp28\0mpp40\0mpp42\0mpp35\0mpp36\0mpp25\0mpp30\0mpp32";
+					marvell,function = "dev";
+				};
+
+				uart-pins-0 {
+					marvell,pins = "mpp0\0mpp1";
+					marvell,function = "ua0";
+					linux,phandle = < 0x07 >;
+					phandle = < 0x07 >;
+				};
+
+				uart-pins-1 {
+					marvell,pins = "mpp19\0mpp20";
+					marvell,function = "ua1";
+				};
+
+				sdhci-pins {
+					marvell,pins = "mpp48\0mpp49\0mpp50\0mpp52\0mpp53\0mpp54\0mpp55\0mpp57\0mpp58\0mpp59";
+					marvell,function = "sd0";
+				};
+
+				sata-pins-0 {
+					marvell,pins = "mpp20";
+					marvell,function = "sata0";
+				};
+
+				sata-pins-1 {
+					marvell,pins = "mpp19";
+					marvell,function = "sata1";
+				};
+
+				sata-pins-2 {
+					marvell,pins = "mpp47";
+					marvell,function = "sata2";
+				};
+
+				sata-pins-3 {
+					marvell,pins = "mpp44";
+					marvell,function = "sata3";
+				};
+
+				microsom-phy-clk-pins {
+					marvell,pins = "mpp45";
+					marvell,function = "ref";
+					linux,phandle = < 0x11 >;
+					phandle = < 0x11 >;
+				};
+
+				microsom-sdhci-pins {
+					marvell,pins = "mpp21\0mpp28\0mpp37\0mpp38\0mpp39\0mpp40";
+					marvell,function = "sd0";
+					linux,phandle = < 0x19 >;
+					phandle = < 0x19 >;
+				};
+
+				i2c1-pins {
+					marvell,pins = "mpp26\0mpp27";
+					marvell,function = "i2c1";
+					linux,phandle = < 0x06 >;
+					phandle = < 0x06 >;
+				};
+
+				clearfog-sdhci-cd-pins {
+					marvell,pins = "mpp20";
+					marvell,function = "gpio";
+				};
+
+				mikro-pins {
+					marvell,pins = "mpp22\0mpp29";
+					marvell,function = "gpio";
+				};
+
+				mikro-spi-pins {
+					marvell,pins = "mpp43";
+					marvell,function = "spi1";
+					linux,phandle = < 0x1c >;
+					phandle = < 0x1c >;
+				};
+
+				mikro-uart-pins {
+					marvell,pins = "mpp24\0mpp25";
+					marvell,function = "ua1";
+					linux,phandle = < 0x08 >;
+					phandle = < 0x08 >;
+				};
+
+				clearfog-phy-pins {
+					marvell,pins = "mpp19";
+					marvell,function = "gpio";
+					linux,phandle = < 0x12 >;
+					phandle = < 0x12 >;
+				};
+
+				rear-button-pins {
+					marvell,pins = "mpp44";
+					marvell,function = "gpio";
+					linux,phandle = < 0x20 >;
+					phandle = < 0x20 >;
+				};
+			};
+
+			gpio@18100 {
+				compatible = "marvell,armada-370-gpio\0marvell,orion-gpio";
+				reg = < 0x18100 0x40 0x181c0 0x08 >;
+				reg-names = "gpio\0pwm";
+				ngpios = < 0x20 >;
+				gpio-controller;
+				#gpio-cells = < 0x02 >;
+				#pwm-cells = < 0x02 >;
+				interrupt-controller;
+				#interrupt-cells = < 0x02 >;
+				interrupts = < 0x00 0x35 0x04 0x00 0x36 0x04 0x00 0x37 0x04 0x00 0x38 0x04 >;
+				clocks = < 0x04 0x00 >;
+				linux,phandle = < 0x18 >;
+				phandle = < 0x18 >;
+
+				phy1_reset {
+					gpio-hog;
+					gpios = < 0x13 0x01 >;
+					output-low;
+					line-name = "phy1-reset";
+				};
+			};
+
+			gpio@18140 {
+				compatible = "marvell,armada-370-gpio\0marvell,orion-gpio";
+				reg = < 0x18140 0x40 0x181c8 0x08 >;
+				reg-names = "gpio\0pwm";
+				ngpios = < 0x1c >;
+				gpio-controller;
+				#gpio-cells = < 0x02 >;
+				#pwm-cells = < 0x02 >;
+				interrupt-controller;
+				#interrupt-cells = < 0x02 >;
+				interrupts = < 0x00 0x3a 0x04 0x00 0x3b 0x04 0x00 0x3c 0x04 0x00 0x3d 0x04 >;
+				clocks = < 0x04 0x00 >;
+				linux,phandle = < 0x21 >;
+				phandle = < 0x21 >;
+			};
+
+			system-controller@18200 {
+				compatible = "marvell,armada-380-system-controller\0marvell,armada-370-xp-system-controller";
+				reg = < 0x18200 0x100 >;
+			};
+
+			clock-gating-control@18220 {
+				compatible = "marvell,armada-380-gating-clock";
+				reg = < 0x18220 0x04 >;
+				clocks = < 0x04 0x00 >;
+				#clock-cells = < 0x01 >;
+				linux,phandle = < 0x0a >;
+				phandle = < 0x0a >;
+			};
+
+			mvebu-sar@18600 {
+				compatible = "marvell,armada-380-core-clock";
+				reg = < 0x18600 0x04 >;
+				#clock-cells = < 0x01 >;
+				linux,phandle = < 0x04 >;
+				phandle = < 0x04 >;
+			};
+
+			clock-complex@18700 {
+				compatible = "marvell,armada-380-cpu-clock\0marvell,armada-xp-cpu-clock";
+				reg = < 0x18700 0xa0 0x1c054 0x40 0xe4260 0x08 >;
+				clocks = < 0x04 0x01 >;
+				#clock-cells = < 0x01 >;
+				linux,phandle = < 0x1e >;
+				phandle = < 0x1e >;
+			};
+
+			mbus-controller@20000 {
+				compatible = "marvell,mbus-controller";
+				reg = < 0x20000 0x100 0x20180 0x20 0x20250 0x08 >;
+				linux,phandle = < 0x02 >;
+				phandle = < 0x02 >;
+			};
+
+			interrupt-controller@20a00 {
+				compatible = "marvell,mpic";
+				reg = < 0x20a00 0x2d0 0x21070 0x58 >;
+				#interrupt-cells = < 0x01 >;
+				#size-cells = < 0x01 >;
+				interrupt-controller;
+				msi-controller;
+				interrupts = < 0x01 0x0f 0x04 >;
+				linux,phandle = < 0x01 >;
+				phandle = < 0x01 >;
+			};
+
+			timer@20300 {
+				compatible = "marvell,armada-380-timer\0marvell,armada-xp-timer";
+				reg = < 0x20300 0x30 0x21040 0x30 >;
+				interrupts-extended = < 0x03 0x00 0x08 0x04 0x03 0x00 0x09 0x04 0x03 0x00 0x0a 0x04 0x03 0x00 0x0b 0x04 0x01 0x05 0x01 0x06 >;
+				clocks = < 0x04 0x02 0x09 >;
+				clock-names = "nbclk\0fixed";
+			};
+
+			watchdog@20300 {
+				compatible = "marvell,armada-380-wdt";
+				reg = < 0x20300 0x34 0x20704 0x04 0x18260 0x04 >;
+				clocks = < 0x04 0x02 0x09 >;
+				clock-names = "nbclk\0fixed";
+			};
+
+			cpurst@20800 {
+				compatible = "marvell,armada-370-cpu-reset";
+				reg = < 0x20800 0x10 >;
+			};
+
+			mpcore-soc-ctrl@20d20 {
+				compatible = "marvell,armada-380-mpcore-soc-ctrl";
+				reg = < 0x20d20 0x6c >;
+			};
+
+			coherency-fabric@21010 {
+				compatible = "marvell,armada-380-coherency-fabric";
+				reg = < 0x21010 0x1c >;
+			};
+
+			pmsu@22000 {
+				compatible = "marvell,armada-380-pmsu";
+				reg = < 0x22000 0x1000 >;
+			};
+
+			ethernet@70000 {
+				compatible = "marvell,armada-370-neta";
+				reg = < 0x70000 0x4000 >;
+				interrupts-extended = < 0x01 0x08 >;
+				clocks = < 0x0a 0x04 >;
+				tx-csum-limit = < 0x2648 >;
+				status = "okay";
+				pinctrl-0 = < 0x0b >;
+				pinctrl-names = "default";
+				phy = < 0x0c >;
+				phy-mode = "rgmii-id";
+				buffer-manager = < 0x0d >;
+				bm,pool-long = < 0x00 >;
+				bm,pool-short = < 0x01 >;
+			};
+
+			ethernet@30000 {
+				compatible = "marvell,armada-370-neta";
+				reg = < 0x30000 0x4000 >;
+				interrupts-extended = < 0x01 0x0a >;
+				clocks = < 0x0a 0x03 >;
+				status = "okay";
+				bm,pool-long = < 0x02 >;
+				bm,pool-short = < 0x01 >;
+				buffer-manager = < 0x0d >;
+				phy-mode = "sgmii";
+				phy = < 0x0e >;
+			};
+
+			ethernet@34000 {
+				compatible = "marvell,armada-370-neta";
+				reg = < 0x34000 0x4000 >;
+				interrupts-extended = < 0x01 0x0c >;
+				clocks = < 0x0a 0x02 >;
+				status = "okay";
+				bm,pool-long = < 0x03 >;
+				bm,pool-short = < 0x01 >;
+				buffer-manager = < 0x0d >;
+				managed = "in-band-status";
+				phy-mode = "sgmii";
+				sfp = < 0x0f >;
+			};
+
+			usb@58000 {
+				compatible = "marvell,orion-ehci";
+				reg = < 0x58000 0x500 >;
+				interrupts = < 0x00 0x12 0x04 >;
+				clocks = < 0x0a 0x12 >;
+				status = "okay";
+			};
+
+			xor@60800 {
+				compatible = "marvell,armada-380-xor\0marvell,orion-xor";
+				reg = < 0x60800 0x100 0x60a00 0x100 >;
+				clocks = < 0x0a 0x16 >;
+				status = "okay";
+
+				xor00 {
+					interrupts = < 0x00 0x16 0x04 >;
+					dmacap,memcpy;
+					dmacap,xor;
+				};
+
+				xor01 {
+					interrupts = < 0x00 0x17 0x04 >;
+					dmacap,memcpy;
+					dmacap,xor;
+					dmacap,memset;
+				};
+			};
+
+			xor@60900 {
+				compatible = "marvell,armada-380-xor\0marvell,orion-xor";
+				reg = < 0x60900 0x100 0x60b00 0x100 >;
+				clocks = < 0x0a 0x1c >;
+				status = "okay";
+
+				xor10 {
+					interrupts = < 0x00 0x41 0x04 >;
+					dmacap,memcpy;
+					dmacap,xor;
+				};
+
+				xor11 {
+					interrupts = < 0x00 0x42 0x04 >;
+					dmacap,memcpy;
+					dmacap,xor;
+					dmacap,memset;
+				};
+			};
+
+			mdio@72004 {
+				#address-cells = < 0x01 >;
+				#size-cells = < 0x00 >;
+				compatible = "marvell,orion-mdio";
+				reg = < 0x72004 0x04 >;
+				clocks = < 0x0a 0x04 >;
+				pinctrl-0 = < 0x10 0x11 0x12 >;
+				pinctrl-names = "default";
+
+				ethernet-phy@0 {
+					marvell,reg-init = < 0x03 0x10 0x00 0x101e >;
+					reg = < 0x00 >;
+					linux,phandle = < 0x0c >;
+					phandle = < 0x0c >;
+				};
+
+				ethernet-phy@1 {
+					marvell,reg-init = < 0x03 0x10 0x00 0x101e >;
+					reg = < 0x01 >;
+					linux,phandle = < 0x0e >;
+					phandle = < 0x0e >;
+				};
+			};
+
+			crypto@90000 {
+				compatible = "marvell,armada-38x-crypto";
+				reg = < 0x90000 0x10000 >;
+				reg-names = "regs";
+				interrupts = < 0x00 0x13 0x04 0x00 0x14 0x04 >;
+				clocks = < 0x0a 0x17 0x0a 0x15 0x0a 0x0e 0x0a 0x10 >;
+				clock-names = "cesa0\0cesa1\0cesaz0\0cesaz1";
+				marvell,crypto-srams = < 0x13 0x14 >;
+				marvell,crypto-sram-size = < 0x800 >;
+			};
+
+			rtc@a3800 {
+				compatible = "marvell,armada-380-rtc";
+				reg = < 0xa3800 0x20 0x184a0 0x0c >;
+				reg-names = "rtc\0rtc-soc";
+				interrupts = < 0x00 0x15 0x04 >;
+				status = "okay";
+			};
+
+			sata@a8000 {
+				compatible = "marvell,armada-380-ahci";
+				reg = < 0xa8000 0x2000 >;
+				interrupts = < 0x00 0x1a 0x04 >;
+				clocks = < 0x0a 0x0f >;
+				status = "okay";
+			};
+
+			bm@c8000 {
+				compatible = "marvell,armada-380-neta-bm";
+				reg = < 0xc8000 0xac >;
+				clocks = < 0x0a 0x0d >;
+				internal-mem = < 0x15 >;
+				status = "okay";
+				linux,phandle = < 0x0d >;
+				phandle = < 0x0d >;
+			};
+
+			sata@e0000 {
+				compatible = "marvell,armada-380-ahci";
+				reg = < 0xe0000 0x2000 >;
+				interrupts = < 0x00 0x1c 0x04 >;
+				clocks = < 0x0a 0x1e >;
+				status = "okay";
+			};
+
+			clock@e4250 {
+				compatible = "marvell,armada-380-corediv-clock";
+				reg = < 0xe4250 0x0c >;
+				#clock-cells = < 0x01 >;
+				clocks = < 0x16 >;
+				clock-output-names = "nand";
+				linux,phandle = < 0x17 >;
+				phandle = < 0x17 >;
+			};
+
+			thermal@e8078 {
+				compatible = "marvell,armada380-thermal";
+				reg = < 0xe4078 0x04 0xe4074 0x04 >;
+				status = "okay";
+			};
+
+			flash@d0000 {
+				compatible = "marvell,armada370-nand";
+				reg = < 0xd0000 0x54 >;
+				#address-cells = < 0x01 >;
+				#size-cells = < 0x01 >;
+				interrupts = < 0x00 0x54 0x04 >;
+				clocks = < 0x17 0x00 >;
+				status = "disabled";
+			};
+
+			sdhci@d8000 {
+				compatible = "marvell,armada-380-sdhci";
+				reg-names = "sdhci\0mbus\0conf-sdio3";
+				reg = < 0xd8000 0x1000 0xdc000 0x100 0x18454 0x04 >;
+				interrupts = < 0x00 0x19 0x04 >;
+				clocks = < 0x0a 0x11 >;
+				mrvl,clk-delay-cycles = < 0x1f >;
+				status = "okay";
+				bus-width = < 0x04 >;
+				cd-gpios = < 0x18 0x14 0x01 >;
+				no-1-8-v;
+				pinctrl-0 = < 0x19 >;
+				pinctrl-names = "default";
+				vmmc = < 0x1a >;
+				wp-inverted;
+				non-removable;
+			};
+
+			usb3@f0000 {
+				compatible = "marvell,armada-380-xhci";
+				reg = < 0xf0000 0x4000 0xf4000 0x4000 >;
+				interrupts = < 0x00 0x10 0x04 >;
+				clocks = < 0x0a 0x09 >;
+				status = "disabled";
+			};
+
+			usb3@f8000 {
+				compatible = "marvell,armada-380-xhci";
+				reg = < 0xf8000 0x4000 0xfc000 0x4000 >;
+				interrupts = < 0x00 0x11 0x04 >;
+				clocks = < 0x0a 0x0a >;
+				status = "okay";
+			};
+		};
+
+		sa-sram0 {
+			compatible = "mmio-sram";
+			reg = < 0x9190000 0x00 0x800 >;
+			clocks = < 0x0a 0x17 >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			ranges = < 0x00 0x9190000 0x00 0x800 >;
+			linux,phandle = < 0x13 >;
+			phandle = < 0x13 >;
+		};
+
+		sa-sram1 {
+			compatible = "mmio-sram";
+			reg = < 0x9150000 0x00 0x800 >;
+			clocks = < 0x0a 0x15 >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			ranges = < 0x00 0x9150000 0x00 0x800 >;
+			linux,phandle = < 0x14 >;
+			phandle = < 0x14 >;
+		};
+
+		bm-bppi {
+			compatible = "mmio-sram";
+			reg = < 0xc040000 0x00 0x100000 >;
+			ranges = < 0x00 0xc040000 0x00 0x100000 >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x01 >;
+			clocks = < 0x0a 0x0d >;
+			no-memory-wc;
+			status = "okay";
+			linux,phandle = < 0x15 >;
+			phandle = < 0x15 >;
+		};
+
+		spi@10600 {
+			compatible = "marvell,armada-380-spi\0marvell,orion-spi";
+			reg = < 0xf0010000 0x10600 0x50 >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x00 >;
+			cell-index = < 0x00 >;
+			interrupts = < 0x00 0x01 0x04 >;
+			clocks = < 0x04 0x00 >;
+			status = "disabled";
+		};
+
+		spi@10680 {
+			compatible = "marvell,armada-380-spi\0marvell,orion-spi";
+			reg = < 0xf0010000 0x10680 0x50 >;
+			#address-cells = < 0x01 >;
+			#size-cells = < 0x00 >;
+			cell-index = < 0x01 >;
+			interrupts = < 0x00 0x3f 0x04 >;
+			clocks = < 0x04 0x00 >;
+			status = "okay";
+			pinctrl-0 = < 0x1b 0x1c >;
+			pinctrl-names = "default";
+
+			spi-flash@0 {
+				#address-cells = < 0x01 >;
+				#size-cells = < 0x01 >;
+				compatible = "w25q32\0jedec,spi-nor";
+				reg = < 0x00 >;
+				spi-max-frequency = < 0x2dc6c0 >;
+				status = "disabled";
+			};
+		};
+
+		pcie {
+			compatible = "marvell,armada-370-pcie";
+			status = "okay";
+			device_type = "pci";
+			#address-cells = < 0x03 >;
+			#size-cells = < 0x02 >;
+			msi-parent = < 0x01 >;
+			bus-range = < 0x00 0xff >;
+			ranges = < 0x82000000 0x00 0x80000 0xf0010000 0x80000 0x00 0x2000 0x82000000 0x00 0x40000 0xf0010000 0x40000 0x00 0x2000 0x82000000 0x00 0x44000 0xf0010000 0x44000 0x00 0x2000 0x82000000 0x00 0x48000 0xf0010000 0x48000 0x00 0x2000 0x82000000 0x01 0x00 0x8e80000 0x00 0x01 0x00 0x81000000 0x01 0x00 0x8e00000 0x00 0x01 0x00 0x82000000 0x02 0x00 0x4e80000 0x00 0x01 0x00 0x81000000 0x02 0x00 0x4e00000 0x00 0x01 0x00 0x82000000 0x03 0x00 0x4d80000 0x00 0x01 0x00 0x81000000 0x03 0x00 0x4d00000 0x00 0x01 0x00 0x82000000 0x04 0x00 0x4b80000 0x00 0x01 0x00 0x81000000 0x04 0x00 0x4b00000 0x00 0x01 0x00 >;
+
+			pcie@1,0 {
+				device_type = "pci";
+				assigned-addresses = < 0x82000800 0x00 0x80000 0x00 0x2000 >;
+				reg = < 0x800 0x00 0x00 0x00 0x00 >;
+				#address-cells = < 0x03 >;
+				#size-cells = < 0x02 >;
+				#interrupt-cells = < 0x01 >;
+				ranges = < 0x82000000 0x00 0x00 0x82000000 0x01 0x00 0x01 0x00 0x81000000 0x00 0x00 0x81000000 0x01 0x00 0x01 0x00 >;
+				bus-range = < 0x00 0xff >;
+				interrupt-map-mask = < 0x00 0x00 0x00 0x00 >;
+				interrupt-map = < 0x00 0x00 0x00 0x00 0x03 0x00 0x1d 0x04 >;
+				marvell,pcie-port = < 0x00 >;
+				marvell,pcie-lane = < 0x00 >;
+				clocks = < 0x0a 0x08 >;
+				status = "disabled";
+			};
+
+			pcie@2,0 {
+				device_type = "pci";
+				assigned-addresses = < 0x82000800 0x00 0x40000 0x00 0x2000 >;
+				reg = < 0x1000 0x00 0x00 0x00 0x00 >;
+				#address-cells = < 0x03 >;
+				#size-cells = < 0x02 >;
+				#interrupt-cells = < 0x01 >;
+				ranges = < 0x82000000 0x00 0x00 0x82000000 0x02 0x00 0x01 0x00 0x81000000 0x00 0x00 0x81000000 0x02 0x00 0x01 0x00 >;
+				bus-range = < 0x00 0xff >;
+				interrupt-map-mask = < 0x00 0x00 0x00 0x00 >;
+				interrupt-map = < 0x00 0x00 0x00 0x00 0x03 0x00 0x21 0x04 >;
+				marvell,pcie-port = < 0x01 >;
+				marvell,pcie-lane = < 0x00 >;
+				clocks = < 0x0a 0x05 >;
+				status = "okay";
+				reset-gpios = < 0x1d 0x01 0x01 >;
+			};
+
+			pcie@3,0 {
+				device_type = "pci";
+				assigned-addresses = < 0x82000800 0x00 0x44000 0x00 0x2000 >;
+				reg = < 0x1800 0x00 0x00 0x00 0x00 >;
+				#address-cells = < 0x03 >;
+				#size-cells = < 0x02 >;
+				#interrupt-cells = < 0x01 >;
+				ranges = < 0x82000000 0x00 0x00 0x82000000 0x03 0x00 0x01 0x00 0x81000000 0x00 0x00 0x81000000 0x03 0x00 0x01 0x00 >;
+				bus-range = < 0x00 0xff >;
+				interrupt-map-mask = < 0x00 0x00 0x00 0x00 >;
+				interrupt-map = < 0x00 0x00 0x00 0x00 0x03 0x00 0x46 0x04 >;
+				marvell,pcie-port = < 0x02 >;
+				marvell,pcie-lane = < 0x00 >;
+				clocks = < 0x0a 0x06 >;
+				status = "disabled";
+			};
+
+			pcie@4,0 {
+				device_type = "pci";
+				assigned-addresses = < 0x82000800 0x00 0x48000 0x00 0x2000 >;
+				reg = < 0x2000 0x00 0x00 0x00 0x00 >;
+				#address-cells = < 0x03 >;
+				#size-cells = < 0x02 >;
+				#interrupt-cells = < 0x01 >;
+				ranges = < 0x82000000 0x00 0x00 0x82000000 0x04 0x00 0x01 0x00 0x81000000 0x00 0x00 0x81000000 0x04 0x00 0x01 0x00 >;
+				bus-range = < 0x00 0xff >;
+				interrupt-map-mask = < 0x00 0x00 0x00 0x00 >;
+				interrupt-map = < 0x00 0x00 0x00 0x00 0x03 0x00 0x47 0x04 >;
+				marvell,pcie-port = < 0x03 >;
+				marvell,pcie-lane = < 0x00 >;
+				clocks = < 0x0a 0x07 >;
+				status = "disabled";
+			};
 		};
 	};
-};
 
-&eth1 {
-	phy = <&phy1>;
-};
+	clocks {
+
+		mainpll {
+			compatible = "fixed-clock";
+			#clock-cells = < 0x00 >;
+			clock-frequency = < 0x3b9aca00 >;
+			linux,phandle = < 0x16 >;
+			phandle = < 0x16 >;
+		};
 
-&gpio0 {
-	phy1_reset {
-		gpio-hog;
-		gpios = <19 GPIO_ACTIVE_LOW>;
-		output-low;
-		line-name = "phy1-reset";
+		oscillator {
+			compatible = "fixed-clock";
+			#clock-cells = < 0x00 >;
+			clock-frequency = < 0x17d7840 >;
+			linux,phandle = < 0x09 >;
+			phandle = < 0x09 >;
+		};
 	};
-};
 
-&mdio {
-	pinctrl-0 = <&mdio_pins &microsom_phy_clk_pins &clearfog_phy_pins>;
-	phy1: ethernet-phy@1 {
-		/*
-		 * Annoyingly, the marvell phy driver configures the LED
-		 * register, rather than preserving reset-loaded setting.
-		 * We undo that rubbish here.
-		 */
-		marvell,reg-init = <3 16 0 0x101e>;
-		reg = <1>;
+	cpus {
+		#address-cells = < 0x01 >;
+		#size-cells = < 0x00 >;
+		enable-method = "marvell,armada-380-smp";
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = < 0x00 >;
+			clocks = < 0x1e 0x00 >;
+			clock-latency = < 0xf4240 >;
+			clock-names = "cpu0";
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = < 0x01 >;
+			clocks = < 0x1e 0x00 >;
+			clock-latency = < 0xf4240 >;
+			clock-names = "cpu1";
+		};
+	};
+
+	regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "3P3V";
+		regulator-min-microvolt = < 0x325aa0 >;
+		regulator-max-microvolt = < 0x325aa0 >;
+		regulator-always-on;
+		linux,phandle = < 0x1a >;
+		phandle = < 0x1a >;
 	};
-};
 
-&pinctrl {
-	/* phy1 reset */
-	clearfog_phy_pins: clearfog-phy-pins {
-		marvell,pins = "mpp19";
-		marvell,function = "gpio";
+	sfp {
+		compatible = "sff,sfp";
+		i2c-bus = < 0x1f >;
+		los-gpio = < 0x1d 0x0c 0x00 >;
+		mod-def0-gpio = < 0x1d 0x0f 0x01 >;
+		tx-disable-gpio = < 0x1d 0x0e 0x00 >;
+		tx-fault-gpio = < 0x1d 0x0d 0x00 >;
+		maximum-power-milliwatt = < 0x7d0 >;
+		linux,phandle = < 0x0f >;
+		phandle = < 0x0f >;
 	};
-	rear_button_pins: rear-button-pins {
-		marvell,pins = "mpp44";
-		marvell,function = "gpio";
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = < 0x20 >;
+		pinctrl-names = "default";
+
+		button_0 {
+			label = "Rear Button";
+			gpios = < 0x21 0x0c 0x01 >;
+			linux,can-disable;
+			linux,code = < 0x100 >;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/axp803.dtsi b/arch/arm/boot/dts/axp803.dtsi
new file mode 100644
index 000000000000..f0e53a7fffbd
--- /dev/null
+++ b/arch/arm/boot/dts/axp803.dtsi
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2017 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * AXP803 Integrated Power Management Chip
+ * http://files.pine64.org/doc/datasheet/pine64/AXP803_Datasheet_V1.0.pdf
+ */
+
+&axp803 {
+	interrupt-controller;
+	#interrupt-cells = <1>;
+
+	regulators {
+		/* Default work frequency for buck regulators */
+		x-powers,dcdc-freq = <3000>;
+
+		reg_dcdc1: dcdc1 {
+			regulator-name = "dcdc1";
+		};
+
+		reg_dcdc2: dcdc2 {
+			regulator-name = "dcdc2";
+		};
+
+		reg_dcdc3: dcdc3 {
+			regulator-name = "dcdc3";
+		};
+
+		reg_dcdc4: dcdc4 {
+			regulator-name = "dcdc4";
+		};
+
+		reg_dcdc5: dcdc5 {
+			regulator-name = "dcdc5";
+		};
+
+		reg_dcdc6: dcdc6 {
+			regulator-name = "dcdc6";
+		};
+
+		reg_dc1sw: dc1sw {
+			regulator-name = "dc1sw";
+		};
+
+		reg_aldo1: aldo1 {
+			regulator-name = "aldo1";
+		};
+
+		reg_aldo2: aldo2 {
+			regulator-name = "aldo2";
+		};
+
+		reg_aldo3: aldo3 {
+			regulator-name = "aldo3";
+		};
+
+		reg_dldo1: dldo1 {
+			regulator-name = "dldo1";
+		};
+
+		reg_dldo2: dldo2 {
+			regulator-name = "dldo2";
+		};
+
+		reg_dldo3: dldo3 {
+			regulator-name = "dldo3";
+		};
+
+		reg_dldo4: dldo4 {
+			regulator-name = "dldo4";
+		};
+
+		reg_eldo1: eldo1 {
+			regulator-name = "eldo1";
+		};
+
+		reg_eldo2: eldo2 {
+			regulator-name = "eldo2";
+		};
+
+		reg_eldo3: eldo3 {
+			regulator-name = "eldo3";
+		};
+
+		reg_fldo1: fldo1 {
+			regulator-name = "fldo1";
+		};
+
+		reg_fldo2: fldo2 {
+			regulator-name = "fldo2";
+		};
+
+		reg_ldo_io0: ldo_io0 {
+			regulator-name = "ldo_io0";
+			status = "disabled";
+		};
+
+		reg_ldo_io1: ldo_io1 {
+			regulator-name = "ldo_io1";
+			status = "disabled";
+		};
+
+		reg_rtc_ldo: rtc_ldo {
+			/* RTC_LDO is a fixed, always-on regulator */
+			regulator-always-on;
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			regulator-name = "rtc_ldo";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/axp81x.dtsi b/arch/arm/boot/dts/axp81x.dtsi
new file mode 100644
index 000000000000..73b761f850c5
--- /dev/null
+++ b/arch/arm/boot/dts/axp81x.dtsi
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* AXP813/818 Integrated Power Management Chip */
+
+&axp81x {
+	interrupt-controller;
+	#interrupt-cells = <1>;
+
+	regulators {
+		/* Default work frequency for buck regulators */
+		x-powers,dcdc-freq = <3000>;
+
+		reg_dcdc1: dcdc1 {
+		};
+
+		reg_dcdc2: dcdc2 {
+		};
+
+		reg_dcdc3: dcdc3 {
+		};
+
+		reg_dcdc4: dcdc4 {
+		};
+
+		reg_dcdc5: dcdc5 {
+		};
+
+		reg_dcdc6: dcdc6 {
+		};
+
+		reg_dcdc7: dcdc7 {
+		};
+
+		reg_aldo1: aldo1 {
+		};
+
+		reg_aldo2: aldo2 {
+		};
+
+		reg_aldo3: aldo3 {
+		};
+
+		reg_dldo1: dldo1 {
+		};
+
+		reg_dldo2: dldo2 {
+		};
+
+		reg_dldo3: dldo3 {
+		};
+
+		reg_dldo4: dldo4 {
+		};
+
+		reg_eldo1: eldo1 {
+		};
+
+		reg_eldo2: eldo2 {
+		};
+
+		reg_eldo3: eldo3 {
+		};
+
+		reg_fldo1: fldo1 {
+		};
+
+		reg_fldo2: fldo2 {
+		};
+
+		reg_fldo3: fldo3 {
+		};
+
+		reg_ldo_io0: ldo-io0 {
+			/* Disable by default to avoid conflicts with GPIO */
+			status = "disabled";
+		};
+
+		reg_ldo_io1: ldo-io1 {
+			/* Disable by default to avoid conflicts with GPIO */
+			status = "disabled";
+		};
+
+		reg_rtc_ldo: rtc-ldo {
+			/* RTC_LDO is a fixed, always-on regulator */
+			regulator-always-on;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+		};
+
+		reg_sw: sw {
+		};
+
+		reg_drivevbus: drivevbus {
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
new file mode 100644
index 000000000000..86959a1bfe22
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+#include "bcm2837.dtsi"
+#include "bcm2835-rpi.dtsi"
+#include "bcm283x-rpi-lan7515.dtsi"
+#include "bcm283x-rpi-usb-host.dtsi"
+
+/ {
+	compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837";
+	model = "Raspberry Pi 3 Model B+";
+
+	chosen {
+		/* 8250 auxiliary UART instead of pl011 */
+		stdout-path = "serial1:115200n8";
+	};
+
+	memory {
+		reg = <0 0x40000000>;
+	};
+
+	leds {
+		act {
+			gpios = <&gpio 29 0>;
+		};
+	};
+};
+
+/* uart0 communicates with the BT module */
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_gpio32 &gpclk2_gpio43>;
+	status = "okay";
+};
+
+/* uart1 is mapped to the pin header */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_gpio14>;
+	status = "okay";
+};
+
+/* SDHCI is used to control the SDIO for wireless */
+&sdhci {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_gpio34>;
+	status = "okay";
+	bus-width = <4>;
+	non-removable;
+};
+
+/* SDHOST is used to drive the SD card */
+&sdhost {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdhost_gpio48>;
+	status = "okay";
+	bus-width = <4>;
+};
diff --git a/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
new file mode 100644
index 000000000000..4d19b9b63af9
--- /dev/null
+++ b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi
@@ -0,0 +1,38 @@
+/ {
+	aliases {
+		ethernet0 = &ethernet;
+	};
+};
+
+&usb {
+	usb1@1 {
+		compatible = "usb424,2514";
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		usb1_1@1 {
+			compatible = "usb424,2514";
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ethernet: usbether@1 {
+				compatible = "usb424,7800";
+				reg = <1>;
+				microchip,eee-enabled;
+				microchip,tx-lpi-timer = <600>;
+				mdio {
+					#address-cells = <0x1>;
+					#size-cells = <0x0>;
+					eth_phy: ethernet-phy@1 {
+						reg = <1>;
+						microchip,led-modes = <1 6>;
+							/* led0: 1 LAN78XX_LINK_1000_ACTIVITY
+							   led1: 6 LAN78XX_LINK_10_100_ACTIVITY 
+						        */
+					};
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 404ce7694899..988493bb4159 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -72,7 +72,7 @@
 		green {
 			label = "cubieboard:green:usr";
 			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>; /* LED2 */
-			linux,default-trigger = "heartbeat";
+			linux,default-trigger = "mmc0";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index 462412ee903c..3924d4937f82 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -85,6 +85,7 @@
 		912000  1350000
 		864000  1300000
 		624000  1250000
+		240000	1150000
 		>;
 	cooling-max-level = <2>;
 };
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index 88a1c2363c6c..72c7ab89edda 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -71,6 +71,7 @@
 		green {
 			label = "bananapi:green:usr";
 			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
index e7af1b7c33d5..8411eee439e8 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -68,11 +68,13 @@
 		blue {
 			label = "bananapro:blue:usr";
 			gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
 		};
 
 		green {
 			label = "bananapro:green:usr";
 			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 852a0aa24dce..fc7abc3fc825 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -55,6 +55,7 @@
 
 	aliases {
 		serial0 = &uart0;
+		serial2 = &uart2;
 	};
 
 	chosen {
@@ -84,6 +85,7 @@
 		green {
 			label = "cubietruck:green:usr";
 			gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
 		};
 	};
 
@@ -326,6 +328,12 @@
 	status = "okay";
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins_a>;
+	status = "okay";
+};
+
 &usb_otg {
 	dr_mode = "otg";
 	status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
index 004b6ddac813..d8cfd9faaa1b 100644
--- a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
@@ -69,6 +69,7 @@
 		green {
 			label = "lamobo_r1:green:usr";
 			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
 		};
 	};
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro-emmc.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro-emmc.dts
new file mode 100644
index 000000000000..9ee2800848b8
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro-emmc.dts
@@ -0,0 +1,80 @@
+ /*
+ * Copyright 2017 Olimex Ltd.
+ * Stefan Mavrodiev <stefan@olimex.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sun7i-a20-olinuxino-micro.dts"
+
+/ {
+	model = "Olimex A20-OLinuXino-MICRO-eMMC";
+	compatible = "olimex,a20-olinuxino-micro-emmc", "allwinner,sun7i-a20";
+
+	mmc2_pwrseq: pwrseq {
+		pinctrl-0 = <&mmc2_pins_nrst>;
+		pinctrl-names = "default";
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&pio 2 16 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&pio {
+	mmc2_pins_nrst: mmc2-rst-pin {
+		pins = "PC16";
+		function = "gpio_out";
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	non-removable;
+	mmc-pwrseq = <&mmc2_pwrseq>;
+	status = "okay";
+
+	emmc: emmc@0 {
+		reg = <0>;
+		compatible = "mmc-card";
+		broken-hpi;
+	};
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index 0b7403e4d687..cb1b081938a5 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -102,7 +102,7 @@
 
 &gmac {
 	pinctrl-names = "default";
-	pinctrl-0 = <&gmac_pins_mii_a>;
+	pinctrl-0 = <&gmac_pins_mii_a>,<&gmac_txerr>;
 	phy = <&phy1>;
 	phy-mode = "mii";
 	status = "okay";
@@ -229,6 +229,11 @@
 };
 
 &pio {
+	gmac_txerr: gmac_txerr@0 {
+		pins = "PA17";
+		function = "gmac";
+	};
+
 	mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
 		pins = "PH11";
 		function = "gpio_in";
diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 2bafd7e99ef7..01a1f29cc8c1 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -44,7 +44,6 @@
 
 /dts-v1/;
 #include "sun8i-a83t.dtsi"
-#include "sunxi-common-regulators.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
 
@@ -53,12 +52,41 @@
 	compatible = "sinovoip,bpi-m3", "allwinner,sun8i-a83t";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	reg_vcc3v3: vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usb1_vbus: reg-usb1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb1-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		enable-active-high;
+		gpio = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		clocks = <&ac100_rtc 1>;
+		clock-names = "ext_clock";
+		/* The WiFi low power clock must be 32768 Hz */
+		assigned-clocks = <&ac100_rtc 1>;
+		assigned-clock-rates = <32768>;
+		/* enables internal regulator and de-asserts reset */
+		reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 WL-PMU-EN */
+	};
 };
 
 &ehci0 {
@@ -68,6 +96,24 @@
 	/* TODO GL830 USB-to-SATA bridge downstream w/ GPIO power controls */
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_sw>;
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii";
+	allwinner,rx-delay-ps = <700>;
+	allwinner,tx-delay-ps = <700>;
+	status = "okay";
+};
+
+&mdio {
+	rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
@@ -78,6 +124,23 @@
 	status = "okay";
 };
 
+&mmc1 {
+	vmmc-supply = <&reg_dldo1>;
+	vqmmc-supply = <&reg_dldo1>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&r_pio>;
+		interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "host-wake";
+	};
+};
+
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_8bit_emmc_pins>;
@@ -96,6 +159,10 @@
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		eldoin-supply = <&reg_dcdc1>;
+		fldoin-supply = <&reg_dcdc5>;
+		swin-supply = <&reg_dcdc1>;
+		x-powers,drive-vbus-en;
 	};
 
 	ac100: codec@e89 {
@@ -123,17 +190,126 @@
 	};
 };
 
-&reg_usb1_vbus {
-	gpio = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
+#include "axp81x.dtsi"
+
+&reg_aldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vcc-1v8";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "dram-pll";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_dcdc1 {
+	/* schematics says 3.1V but FEX file says 3.3V */
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-3v3";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpua";
+};
+
+&reg_dcdc3 {
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpub";
+};
+
+&reg_dcdc4 {
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_dcdc6 {
+	regulator-always-on;
+	regulator-min-microvolt = <900000>;
+	regulator-max-microvolt = <900000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dldo1 {
+	/*
+	 * This powers both the WiFi/BT module's main power, I/O supply,
+	 * and external pull-ups on all the data lines. It should be set
+	 * to the same voltage as the I/O supply (DCDC1 in this case) to
+	 * avoid any leakage or mismatch.
+	 */
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
+
+&reg_dldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "vcc-pd";
+};
+
+&reg_drivevbus {
+	regulator-name = "usb0-vbus";
 	status = "okay";
 };
 
-&reg_vcc3v0 {
-	status = "disabled";
+&reg_fldo1 {
+	regulator-min-microvolt = <1080000>;
+	regulator-max-microvolt = <1320000>;
+	regulator-name = "vdd12-hsic";
+};
+
+&reg_fldo2 {
+	/*
+	 * Despite the embedded CPUs core not being used in any way,
+	 * this must remain on or the system will hang.
+	 */
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpus";
+};
+
+&reg_rtc_ldo {
+	regulator-name = "vcc-rtc";
 };
 
-&reg_vcc5v0 {
-	status = "disabled";
+&reg_sw {
+	/*
+	 * The PHY requires 20ms after all voltages
+	 * are applied until core logic is ready and
+	 * 30ms after the reset pin is de-asserted.
+	 * Set a 100ms delay to account for PMIC
+	 * ramp time and board traces.
+	 */
+	regulator-enable-ramp-delay = <100000>;
+	regulator-name = "vcc-ephy";
 };
 
 &uart0 {
diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
index 1fed3231f5c1..a8e99787045c 100644
--- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
@@ -44,7 +44,6 @@
 
 /dts-v1/;
 #include "sun8i-a83t.dtsi"
-#include "sunxi-common-regulators.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
 
@@ -53,6 +52,7 @@
 	compatible = "cubietech,cubietruck-plus", "allwinner,sun8i-a83t";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -95,6 +95,26 @@
 		refclk-frequency = <19200000>;
 	};
 
+	reg_usb1_vbus: reg-usb1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb1-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		enable-active-high;
+		gpio = <&pio 3 29 GPIO_ACTIVE_HIGH>; /* PD29 */
+	};
+
+	reg_usb2_vbus: reg-usb2-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb2-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		enable-active-high;
+		gpio = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+	};
+
 	sound {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "On-board SPDIF";
@@ -112,6 +132,17 @@
 		#sound-dai-cells = <0>;
 		compatible = "linux,spdif-dit";
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		clocks = <&ac100_rtc 1>;
+		clock-names = "ext_clock";
+		/* The WiFi low power clock must be 32768 Hz */
+		assigned-clocks = <&ac100_rtc 1>;
+		assigned-clock-rates = <32768>;
+		/* enables internal regulator and de-asserts reset */
+		reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 WL-PMU-EN */
+	};
 };
 
 &ehci0 {
@@ -124,20 +155,45 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_dldo4>;
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&mdio {
+	rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
-	vmmc-supply = <&reg_vcc3v3>;
+	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <4>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
 	cd-inverted;
 	status = "okay";
 };
 
+&mmc1 {
+	vmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_sw>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_8bit_emmc_pins>;
-	vmmc-supply = <&reg_vcc3v3>;
+	vmmc-supply = <&reg_dcdc1>;
 	bus-width = <8>;
 	non-removable;
 	cap-mmc-hw-reset;
@@ -152,6 +208,9 @@
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		eldoin-supply = <&reg_dcdc1>;
+		swin-supply = <&reg_dcdc1>;
+		x-powers,drive-vbus-en;
 	};
 
 	ac100: codec@e89 {
@@ -179,22 +238,143 @@
 	};
 };
 
-&reg_usb1_vbus {
-	gpio = <&pio 3 29 GPIO_ACTIVE_HIGH>; /* PD29 */
-	status = "okay";
+#include "axp81x.dtsi"
+
+&reg_aldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vcc-1v8";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "dram-pll";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_dcdc1 {
+	/*
+	 * The schematics say this should be 3.3V, but the FEX file says
+	 * it should be 3V. The latter makes sense, as the WiFi module's
+	 * I/O is indirectly powered from DCDC1, through SW. It is rated
+	 * at 2.98V maximum.
+	 */
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-3v";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpua";
+};
+
+&reg_dcdc3 {
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpub";
+};
+
+&reg_dcdc4 {
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1500000>;
+	regulator-max-microvolt = <1500000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_dcdc6 {
+	regulator-always-on;
+	regulator-min-microvolt = <900000>;
+	regulator-max-microvolt = <900000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dldo2 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "dp-pwr";
 };
 
-&reg_usb2_vbus {
-	gpio = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+&reg_dldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "ephy-io";
+};
+
+&reg_dldo4 {
+	/*
+	 * The PHY requires 20ms after all voltages are applied until core
+	 * logic is ready and 30ms after the reset pin is de-asserted.
+	 * Set a 100ms delay to account for PMIC ramp time and board traces.
+	 */
+	regulator-enable-ramp-delay = <100000>;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "ephy";
+};
+
+&reg_drivevbus {
+	regulator-name = "usb0-vbus";
 	status = "okay";
 };
 
-&reg_vcc3v0 {
-	status = "disabled";
+&reg_eldo1 {
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "dp-bridge-1";
+};
+
+&reg_eldo2 {
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "dp-bridge-2";
+};
+
+&reg_fldo1 {
+	/* TODO should be handled by USB PHY */
+	regulator-always-on;
+	regulator-min-microvolt = <1080000>;
+	regulator-max-microvolt = <1320000>;
+	regulator-name = "vdd12-hsic";
+};
+
+&reg_fldo2 {
+	/*
+	 * Despite the embedded CPUs core not being used in any way,
+	 * this must remain on or the system will hang.
+	 */
+	regulator-always-on;
+	regulator-min-microvolt = <700000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpus";
+};
+
+&reg_rtc_ldo {
+	regulator-name = "vcc-rtc";
 };
 
-&reg_vcc5v0 {
-	status = "disabled";
+&reg_sw {
+	regulator-name = "vcc-wifi-io";
 };
 
 &spdif {
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index f996bd343e50..952923a102f3 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -54,12 +54,6 @@
 	#address-cells = <1>;
 	#size-cells = <1>;
 
-	aliases {
-	};
-
-	chosen {
-	};
-
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -218,6 +212,8 @@
 			resets = <&ccu RST_BUS_MMC1>;
 			reset-names = "ahb";
 			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&mmc1_pins>;
 			status = "disabled";
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -242,7 +238,7 @@
 			#size-cells = <0>;
 		};
 
-		usb_otg: usb@01c19000 {
+		usb_otg: usb@1c19000 {
 			compatible = "allwinner,sun8i-a83t-musb",
 				     "allwinner,sun8i-a33-musb";
 			reg = <0x01c19000 0x0400>;
@@ -340,6 +336,39 @@
 			#interrupt-cells = <3>;
 			#gpio-cells = <3>;
 
+			emac_rgmii_pins: emac-rgmii-pins {
+				pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
+				       "PD11", "PD12", "PD13", "PD14", "PD18",
+				       "PD19", "PD21", "PD22", "PD23";
+				function = "gmac";
+				/*
+				 * data lines in RGMII mode use DDR mode
+				 * and need a higher signal drive strength
+				 */
+				drive-strength = <40>;
+			};
+
+			i2c0_pins: i2c0-pins {
+				pins = "PH0", "PH1";
+				function = "i2c0";
+			};
+
+			i2c1_pins: i2c1-pins {
+				pins = "PH2", "PH3";
+				function = "i2c1";
+			};
+
+			i2c2_ph_pins: i2c2-ph-pins {
+				pins = "PH4", "PH5";
+				function = "i2c2";
+			};
+
+			i2s1_pins: i2s1-pins {
+				/* I2S1 does not have external MCLK pin */
+				pins = "PG10", "PG11", "PG12", "PG13";
+				function = "i2s1";
+			};
+
 			mmc0_pins: mmc0-pins {
 				pins = "PF0", "PF1", "PF2",
 				       "PF3", "PF4", "PF5";
@@ -348,6 +377,14 @@
 				bias-pull-up;
 			};
 
+			mmc1_pins: mmc1-pins {
+				pins = "PG0", "PG1", "PG2",
+				       "PG3", "PG4", "PG5";
+				function = "mmc1";
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
 			mmc2_8bit_emmc_pins: mmc2-8bit-emmc-pins {
 				pins = "PC5", "PC6", "PC8", "PC9",
 				       "PC10", "PC11", "PC12", "PC13",
@@ -371,6 +408,16 @@
 				pins = "PF2", "PF4";
 				function = "uart0";
 			};
+
+			uart1_pins: uart1-pins {
+				pins = "PG6", "PG7";
+				function = "uart1";
+			};
+
+			uart1_rts_cts_pins: uart1-rts-cts-pins {
+				pins = "PG8", "PG9";
+				function = "uart1";
+			};
 		};
 
 		timer@1c20c00 {
@@ -404,7 +451,48 @@
 			status = "disabled";
 		};
 
-		uart0: serial@01c28000 {
+		i2s0: i2s@1c22000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22000 0x400>;
+			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 3>, <&dma 3>;
+			resets = <&ccu RST_BUS_I2S0>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		i2s1: i2s@1c22400 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22400 0x400>;
+			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 4>, <&dma 4>;
+			resets = <&ccu RST_BUS_I2S1>;
+			dma-names = "rx", "tx";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2s1_pins>;
+			status = "disabled";
+		};
+
+		i2s2: i2s@1c22800 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22800 0x400>;
+			interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 27>;
+			resets = <&ccu RST_BUS_I2S2>;
+			dma-names = "tx";
+			status = "disabled";
+		};
+
+		uart0: serial@1c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
 			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
@@ -415,6 +503,78 @@
 			status = "disabled";
 		};
 
+		i2c0: i2c@1c2ac00 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2ac00 0x400>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C0>;
+			resets = <&ccu RST_BUS_I2C0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c1: i2c@1c2b000 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b000 0x400>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C1>;
+			resets = <&ccu RST_BUS_I2C1>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c2: i2c@1c2b400 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b400 0x400>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C2>;
+			resets = <&ccu RST_BUS_I2C2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		emac: ethernet@1c30000 {
+			compatible = "allwinner,sun8i-a83t-emac";
+			syscon = <&syscon>;
+			reg = <0x01c30000 0x104>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			resets = <&ccu 13>;
+			reset-names = "stmmaceth";
+			clocks = <&ccu 27>;
+			clock-names = "stmmaceth";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			mdio: mdio {
+				compatible = "snps,dwmac-mdio";
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		uart1: serial@1c28400 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28400 0x400>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART1>;
+			resets = <&ccu RST_BUS_UART1>;
+			status = "disabled";
+		};
+
 		gic: interrupt-controller@1c81000 {
 			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
 			reg = <0x01c81000 0x1000>,
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
new file mode 100644
index 000000000000..1cdbd9a3ef57
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun8i-h3-bananapi-m2-plus.dts, which is:
+ *   Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Banana Pi BPI-M2-Zero";
+	compatible = "sinovoip,bpi-m2-zero", "allwinner,sun8i-h2-plus";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+
+		pwr_led {
+			label = "bananapi-m2-zero:red:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+			default-state = "on";
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+
+		sw4 {
+			label = "power";
+			linux,code = <BTN_0>;
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	/*
+	 * On the production batch of this board the card detect GPIO is
+	 * high active (card inserted), although on the early samples it's
+	 * low active.
+	 */
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: wifi@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+	/*
+	 * There're two micro-USB connectors, one is power-only and another is
+	 * OTG. The Vbus of these two connectors are connected together, so
+	 * the external USB device will be powered just by the power input
+	 * from the power-only USB port.
+	 */
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-ipfire-nano.dts b/arch/arm/boot/dts/sun8i-h2-plus-ipfire-nano.dts
new file mode 100644
index 000000000000..52d25fb549a6
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-ipfire-nano.dts
@@ -0,0 +1,272 @@
+/*
+ *   Copyright (C) 2018 Arne Fitzenreiter <arne_f@ipfire.org>
+ *  
+ *   based on sun8i-h2-plus-nanopi-duo
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "IPFire Nano";
+	compatible = "ipfire,nano", "allwinner,sun8i-h3";
+
+	aliases {
+		ethernet0 = &emac;
+		ethernet1 = &usbr8152;
+		ethernet2 = &xr819;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&leds_npi>, <&leds_r_npi>;
+
+		status {
+			label = "ipfire:blue:status";
+			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+		};
+
+		pwr {
+			label = "ipfire:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	r_gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "k1";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sw_r_npi>;
+
+		k1@0 {
+			label = "k1";
+			linux,code = <KEY_POWER>;
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	reg_vcc_wifi: reg_vcc_wifi {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-name = "vcc-wifi";
+		gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>;	// PL7 WIFI_POWER_EN
+	        startup-delay-us = <70000>;
+        	enable-active-high;
+	};
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; 		// 50=4ms check
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; 	// PL6 check
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default"; 
+		pinctrl-0 = <&wifi_en_npi>; 
+		reset-gpios = <&pio 6 13 GPIO_ACTIVE_LOW>;  // PG13 WL_RESTN 
+		post-power-on-delay-ms = <50>;
+	};
+
+	// lower the cma shared mem pool from 64 to 8MB
+	// we use no mali
+	reserved-memory {
+		cma: linux,cma {
+			size = <0x800000>;
+		};
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&mmc0 {
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	status = "okay";
+	vmmc-supply = <&reg_vcc3v3>;
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vqmmc-supply = <&reg_vcc_wifi>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "disabled";
+
+	xr819: sdio_wifi@1 {
+		reg = <1>;
+		compatible = "xradio,xr819";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_wake>;
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc1_pins_a {
+	bias-pull-up;
+};
+
+&pio {
+	leds_npi: led_pins@0 {
+		pins = "PA10";
+		function = "gpio_out";
+	};
+	wifi_en_npi: wifi_en_pin {
+		pins = "PG13";
+		function = "gpio_out";
+	};
+	wifi_wake: wifi_wake@0 {
+		pins = "PG10";
+		function = "irq";
+		pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&r_pio {
+	leds_r_npi: led_pins@0 {
+		pins = "PL10";
+		function = "gpio_out";
+	};
+
+	sw_r_npi: key_pins@0 {
+		pins = "PL3";
+		function = "gpio_in";
+	};
+};
+
+
+&ehci0 {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	usbr8152: usbether@1 {
+		compatible = "usb0bda,8152";
+		reg = <1>;
+	};
+};
+
+&ohci2 {
+	status = "disabled";
+};
+
+&ehci3 {
+	status = "okay";
+
+};
+
+&ohci3 {
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/*
+	 * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only
+	 * power up the board; when it's used as OTG port, this VBUS is
+	 * always off even if the board is powered via GPIO pins.
+	 */
+	status = "okay";
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+};
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-nanopi-duo.dts b/arch/arm/boot/dts/sun8i-h2-plus-nanopi-duo.dts
new file mode 100644
index 000000000000..71888b56f1d3
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-nanopi-duo.dts
@@ -0,0 +1,236 @@
+/*
+ * adapted by <github.com/karabek>, based on
+ *   Copyright (C) 2016 James Pettigrew <james@innovum.com.au>
+ *   Copyright (C) 2016 Milo Kim <woogyom.kim@gmail.com>
+ *
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "FriendlyARM NanoPi DUO";
+	compatible = "friendlyarm,nanopi-duo", "allwinner,sun8i-h3";
+
+	aliases {
+		ethernet1 = &xr819;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&leds_npi>, <&leds_r_npi>;
+
+		status {
+			label = "nanopi:blue:status";
+			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		pwr {
+			label = "nanopi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	r_gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "k1";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sw_r_npi>;
+
+		k1@0 {
+			label = "k1";
+			linux,code = <KEY_POWER>;
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	reg_vcc_wifi: reg_vcc_wifi {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-name = "vcc-wifi";
+		gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>;	// PL7 WIFI_POWER_EN
+	        startup-delay-us = <70000>;
+        	enable-active-high;
+	};
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; 		// 50=4ms check
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; 	// PL6 check
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default"; 
+		pinctrl-0 = <&wifi_en_npi>; 
+		reset-gpios = <&pio 6 13 GPIO_ACTIVE_LOW>;  // PG13 WL_RESTN 
+		post-power-on-delay-ms = <50>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&mmc0 {
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	status = "okay";
+	vmmc-supply = <&reg_vcc3v3>;
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vqmmc-supply = <&reg_vcc_wifi>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	xr819: sdio_wifi@1 {
+		reg = <1>;
+		compatible = "xradio,xr819";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_wake>;
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc1_pins_a {
+	bias-pull-up;
+};
+
+&pio {
+	leds_npi: led_pins@0 {
+		pins = "PA10";
+		function = "gpio_out";
+	};
+	wifi_en_npi: wifi_en_pin {
+		pins = "PG13";
+		function = "gpio_out";
+	};
+	wifi_wake: wifi_wake@0 {
+		pins = "PG10";
+		function = "irq";
+		pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&r_pio {
+	leds_r_npi: led_pins@0 {
+		pins = "PL10";
+		function = "gpio_out";
+	};
+
+	sw_r_npi: key_pins@0 {
+		pins = "PL3";
+		function = "gpio_in";
+	};
+};
+
+
+&ehci0 {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/*
+	 * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only
+	 * power up the board; when it's used as OTG port, this VBUS is
+	 * always off even if the board is powered via GPIO pins.
+	 */
+	status = "okay";
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+};
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts
new file mode 100644
index 000000000000..b1b8b3b16025
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2018 Arne Fitzenreiter <arne_f@ipfire.org>
+ *
+ * Based on sun8i-h2-plus-orangepi-zero.dts, which is:
+ *   Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "Xunlong Orange Pi R1";
+	compatible = "xunlong,orangepi-r1", "allwinner,sun8i-h2-plus";
+
+	aliases {
+		serial0 = &uart0;
+		/* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
+		ethernet0 = &emac;
+		ethernet2 = &rtl8189etv;  //fix this rtl8189etv
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr_led {
+			label = "orangepi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led {
+			label = "orangepi:red:status";
+			gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+		};
+	};
+
+	reg_vcc_wifi: reg_vcc_wifi {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-name = "vcc-wifi";
+		enable-active-high;
+		gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; /* 4ms */
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>;
+		post-power-on-delay-ms = <200>;
+	};
+
+	// lower the cma shared mem pool from 64 to 8MB
+	// we use no mali
+	reserved-memory {
+		cma: linux,cma {
+			size = <0x800000>;
+		};
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc_wifi>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	/*
+	 * Explicitly define the sdio device, so that we can add an ethernet
+	 * alias for it (which e.g. makes u-boot set a mac-address).
+	 */
+	rtl8189etv: sdio_wifi@1 {
+		reg = <1>;
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc1_pins_a {
+	bias-pull-up;
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
+&ohci3 {
+	status = "okay";
+};
+
+&reg_vcc_wifi {
+	regulator-always-on;
+};
+
+
+&spi0 {
+	/* Disable SPI NOR by default: it optional on Orange Pi Zero boards */
+	status = "disabled";
+
+	flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+		reg = <0>;
+		spi-max-frequency = <40000000>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/*
+	 * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only
+	 * power up the board; when it's used as OTG port, this VBUS is
+	 * always off even if the board is powered via GPIO pins.
+	 */
+	status = "okay";
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+};
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
index b1502df7b509..c3fabfdbc2c3 100644
--- a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
@@ -49,6 +49,7 @@
 
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Xunlong Orange Pi Zero";
@@ -56,6 +57,8 @@
 
 	aliases {
 		serial0 = &uart0;
+		/* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
+		ethernet0 = &emac;
 		ethernet1 = &xr819;
 	};
 
@@ -69,12 +72,14 @@
 		pwr_led {
 			label = "orangepi:green:pwr";
 			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
-			default-state = "on";
+			linux,default-trigger = "heartbeat";
 		};
 
 		status_led {
 			label = "orangepi:red:status";
 			gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+
 		};
 	};
 
@@ -87,11 +92,41 @@
 		gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>;
 	};
 
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; /* 4ms */
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+
 	wifi_pwrseq: wifi_pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>;
 		post-power-on-delay-ms = <200>;
 	};
+
+	// lower the cma shared mem pool from 64 to 8MB
+	// we use no mali
+	reserved-memory {
+		cma: linux,cma {
+			size = <0x800000>;
+		};
+	};
+
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
 };
 
 &ehci0 {
@@ -102,6 +137,21 @@
 	status = "okay";
 };
 
+&ehci2 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>;
@@ -127,6 +177,10 @@
 	 */
 	xr819: sdio_wifi@1 {
 		reg = <1>;
+		compatible = "xradio,xr819";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "host-wake";
 	};
 };
 
@@ -142,6 +196,14 @@
 	status = "okay";
 };
 
+&ohci2 {
+	status = "okay";
+};
+
+&ohci3 {
+	status = "okay";
+};
+
 &spi0 {
 	/* Disable SPI NOR by default: it optional on Orange Pi Zero boards */
 	status = "disabled";
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-sunvell-r69.dts b/arch/arm/boot/dts/sun8i-h2-plus-sunvell-r69.dts
new file mode 100644
index 000000000000..3dd5c81e815e
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h2-plus-sunvell-r69.dts
@@ -0,0 +1,221 @@
+/*
+ * Based original Sunvell R69 FEX file (2017 <github.com/karabek>)
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "Sunvell R69";
+	compatible = "sunvell,sunvell-r69", "allwinner,sun8i-h2-plus";
+
+	aliases {
+		serial0 = &uart0;
+		ethernet0 = &emac;
+		ethernet1 = &xr819;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr_led {
+			label = "sunvell-r69:blue:pwr";
+			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led {
+			label = "sunvell-r69:red:status";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	reg_vcc_wifi: reg_vcc_wifi {
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-name = "vcc-wifi";
+		gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>;
+	        startup-delay-us = <70000>;
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 0 GPIO_ACTIVE_LOW>;
+		post-power-on-delay-ms = <200>;
+	};
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc_wifi>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	/*
+	 * Explicitly define the sdio device, so that we can add an ethernet
+	 * alias for it (which e.g. makes u-boot set a mac-address).
+	 */
+	xr819: sdio_wifi@1 {
+		reg = <1>;
+		compatible = "xradio,xr819";
+		interrupt-parent = <&pio>;
+		interrupts = <0 11 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc1_pins_a {
+	bias-pull-up;
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "host";		/* host -or- peripheral */
+	status = "okay";
+};
+
+&usbphy {
+	/* USB VBUS is always on */
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
index a337af1de322..0deb904c5842 100644
--- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
@@ -43,7 +43,6 @@
 /dts-v1/;
 #include "sun8i-h3.dtsi"
 #include "sunxi-common-regulators.dtsi"
-
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 
@@ -52,6 +51,7 @@
 	compatible = "sinovoip,bpi-m2-plus", "allwinner,sun8i-h3";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 		serial1 = &uart1;
 	};
@@ -60,6 +60,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -114,12 +125,30 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0>;
+	};
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -159,6 +188,40 @@
 	status = "okay";
 };
 
+&codec {
+	allwinner,audio-routing =
+		"Line Out", "LINEOUT",
+		"MIC1", "Mic",
+		"Mic",  "MBIAS";
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &ohci0 {
 	status = "okay";
 };
@@ -171,6 +234,10 @@
 	status = "okay";
 };
 
+&r_i2c {
+	status = "okay";
+};
+
 &r_pio {
 	pwr_led_bpi_m2p: led_pins@0 {
 		pins = "PL10";
diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
index 21b38c386f1b..f139e8c36ad4 100644
--- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2017 Marcus Cooper <codekipper@gmail.com>
+ * Copyright (C) 2018 Armbian
  *
  * This file is dual-licensed: you can use it either under the terms
  * of the GPL or the X11 license, at your option. Note that this dual
@@ -52,18 +53,27 @@
 	compatible = "roofull,beelink-x2", "allwinner,sun8i-h3";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
-		/* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
-		ethernet1 = &sdiowifi;
 	};
 
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
-
 		blue {
 			label = "beelink-x2:blue:pwr";
 			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
@@ -75,7 +85,6 @@
 			gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
 		};
 	};
-
 	wifi_pwrseq: wifi_pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
@@ -86,7 +95,6 @@
 	sound_spdif {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "On-board SPDIF";
-
 		simple-audio-card,cpu {
 			sound-dai = <&spdif>;
 		};
@@ -102,6 +110,19 @@
 	};
 };
 
+&codec {
+	allwinner,audio-routing =
+		"Line Out", "LINEOUT",
+		"MIC1", "Mic",
+		"Mic",  "MBIAS";
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -110,12 +131,45 @@
 	status = "okay";
 };
 
+&ehci2 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -168,6 +222,14 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &spdif {
 	pinctrl-names = "default";
 	pinctrl-0 = <&spdif_tx_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-libretech-tritium.dts b/arch/arm/boot/dts/sun8i-h3-libretech-tritium.dts
new file mode 100644
index 000000000000..3be4d3a72a81
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-libretech-tritium.dts
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2017 Armbian
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Libre Computer Board ALL-H3-CC H3";
+	compatible = "libretech,all-h3-cc-h3", "allwinner,sun8i-h3";
+
+	aliases {
+		ethernet0 = &emac;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+	leds {
+		compatible = "gpio-leds";
+
+		pwr_led {
+			label = "librecomputer:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+			default-state = "on";
+		};
+
+		status_led {
+			label = "librecomputer:blue:status";
+			gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* PA7 */
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		power {
+			label = "power";
+			linux,code = <KEY_POWER>;
+			gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
+		};
+	};
+
+	reg_vcc1v2: vcc1v2 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc1v2";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&reg_vcc5v0>;
+		gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
+		enable-active-high;
+	};
+
+	reg_vcc3v3: vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&reg_vcc5v0>;
+	};
+
+	/* This represents the board's 5V input */
+	reg_vcc5v0: vcc5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_vcc_dram: vcc-dram {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc-dram";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&reg_vcc5v0>;
+		gpio = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */
+		enable-active-high;
+	};
+
+	reg_vcc_io: vcc-io {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc-io";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&reg_vcc3v3>;
+		gpio = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL5 */
+	};
+
+	reg_vdd_cpux: vdd-cpux {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-cpux";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&reg_vcc5v0>;
+		gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
+		enable-active-high;
+	};
+};
+
+&codec {
+	allwinner,audio-routing =
+		"Line Out", "LINEOUT",
+		"MIC1", "Mic",
+		"Mic",  "MBIAS";
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&ir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ir_pins_a>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc_io>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	cd-inverted;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
+&ohci3 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbphy {
+	/* VBUS on USB ports are always on */
+	usb0_vbus-supply = <&reg_vcc5v0>;
+	usb1_vbus-supply = <&reg_vcc5v0>;
+	usb2_vbus-supply = <&reg_vcc5v0>;
+	usb3_vbus-supply = <&reg_vcc5v0>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
index 8ddd1b2cc097..b9c61ea01bfe 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts
@@ -43,8 +43,164 @@
 #include "sun8i-h3-nanopi.dtsi"
 
 / {
-	model = "FriendlyArm NanoPi M1 Plus";
+	model = "FriendlyElec NanoPi M1 Plus";
 	compatible = "friendlyarm,nanopi-m1-plus", "allwinner,sun8i-h3";
+
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+        compatible = "mmc-pwrseq-simple";
+        pinctrl-names = "default";
+        pinctrl-0 = <&wifi_en_npi>;
+        reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+        post-power-on-delay-ms = <200>;
+    };
+
+    reg_gmac_3v3: gmac-3v3 {
+        compatible = "regulator-fixed";
+        pinctrl-names = "default";
+        pinctrl-0 = <&gmac_power_pin_nanopi>;
+        regulator-name = "gmac-3v3";
+        regulator-min-microvolt = <3300000>;
+        regulator-max-microvolt = <3300000>;
+        startup-delay-us = <100000>;
+        enable-active-high;
+        gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+    };
+
+    rfkill_bt {
+        compatible = "rfkill-gpio";
+        pinctrl-names = "default";
+        pinctrl-0 = <&bt_pwr_pin>;
+        reset-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+        clocks = <&osc32k>;
+        clock-frequency = <32768>;
+        rfkill-name = "sunxi-bt";
+        rfkill-type = "bluetooth";
+    };
+
+};
+
+&pio {
+    gmac_power_pin_nanopi: gmac_power_pin@0 {
+        pins = "PD6";
+        function = "gpio_out";
+    };
+    bt_pwr_pin: bt_pwr_pin@0 {
+        pins = "PG13";
+        function = "gpio_out";
+    };
+};
+
+&r_pio {
+    wifi_en_npi: wifi_en_pin {
+        pins = "PL7";
+        function = "gpio_out";
+    };
+};
+
+&external_mdio {
+    ext_rgmii_phy: ethernet-phy@1 {
+        reg = <0>;
+    };
+};
+
+&emac {
+    pinctrl-names = "default";
+    pinctrl-0 = <&emac_rgmii_pins>;
+    phy-supply = <&reg_gmac_3v3>;
+    phy-handle = <&ext_rgmii_phy>;
+    phy-mode = "rgmii";
+
+    allwinner,leds-active-low;
+    status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: bcrmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&mmc2_8bit_pins>;
+    vmmc-supply = <&reg_vcc3v3>;
+    bus-width = <8>;
+    non-removable;
+    cap-mmc-hw-reset;
+    status = "okay";
+};
+
+&mmc2_8bit_pins {
+    /* Increase drive strength for DDR modes */
+    drive-strength = <40>;
+    /* eMMC is missing pull-ups */
+    bias-pull-up;
+};
+
+&codec {
+	allwinner,audio-routing =
+		"Line Out", "LINEOUT",
+		"MIC1", "Mic",
+		"Mic",  "MBIAS";
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
 };
 
 &ehci1 {
@@ -55,6 +211,10 @@
 	status = "okay";
 };
 
+&ohci0 {
+	status = "okay";
+};
+
 &ohci1 {
 	status = "okay";
 };
@@ -62,3 +222,13 @@
 &ohci2 {
 	status = "okay";
 };
+
+&r_i2c {
+	status = "okay";
+};
+
+&uart3 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&uart3_pins>, <&uart3_rts_cts_pins>;
+    status = "okay";
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
index ec63d104b404..9dff001eb05f 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
@@ -45,6 +45,66 @@
 / {
 	model = "FriendlyArm NanoPi M1";
 	compatible = "friendlyarm,nanopi-m1", "allwinner,sun8i-h3";
+
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&codec {
+	allwinner,audio-routing =
+		"Line Out", "LINEOUT",
+		"MIC1", "Mic",
+		"Mic",  "MBIAS";
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
 };
 
 &ehci1 {
@@ -55,6 +115,14 @@
 	status = "okay";
 };
 
+&ehci3 {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
 &ohci1 {
 	status = "okay";
 };
@@ -62,3 +130,11 @@
 &ohci2 {
 	status = "okay";
 };
+
+&ohci3 {
+	status = "okay";
+};
+
+&r_i2c {
+	status = "okay";
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
index 03ff6f8b93ff..0525673bb067 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo-air.dts
@@ -47,7 +47,7 @@
 #include <dt-bindings/gpio/gpio.h>
 
 / {
-	model = "FriendlyARM NanoPi NEO Air";
+	model = "FriendlyElec NanoPi NEO Air";
 	compatible = "friendlyarm,nanopi-neo-air", "allwinner,sun8i-h3";
 
 	aliases {
@@ -58,6 +58,13 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_neoair>;
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -70,8 +77,37 @@
 		status {
 			label = "nanopi:blue:status";
 			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */
+			linux,default-trigger = "heartbeat";
 		};
 	};
+
+	reg_mp2134dj: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>;		// 50=4ms check
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;	// PL6 check
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_mp2134dj>;
+};
+
+&r_pio {
+	wifi_en_neoair: wifi_en_pin@0 {
+		allwinner,pins = "PL7";
+		allwinner,function = "gpio_out";
+	};
 };
 
 &mmc0 {
@@ -84,12 +120,61 @@
 	status = "okay";
 };
 
+&ehci0 {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: bcrmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&mmc2_8bit_pins>;
+    vmmc-supply = <&reg_vcc3v3>;
+    bus-width = <8>;
+    non-removable;
+    cap-mmc-hw-reset;
+    status = "okay";
+};
+
+&mmc2_8bit_pins {
+    /* Increase drive strength for DDR modes */
+    drive-strength = <40>;
+    /* eMMC is missing pull-ups */
+    bias-pull-up;
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
 	status = "okay";
 };
 
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
 &usbphy {
 	/* USB VBUS is always on */
 	status = "okay";
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
index 8d2cc6e9a03f..1b95e157304f 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts
@@ -45,4 +45,32 @@
 / {
 	model = "FriendlyARM NanoPi NEO";
 	compatible = "friendlyarm,nanopi-neo", "allwinner,sun8i-h3";
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; 		// 50=4ms check
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;	// PL6 check
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
 };
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-r1.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-r1.dts
new file mode 100644
index 000000000000..856e534a9236
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-r1.dts
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 Jagan Teki <jteki@openedev.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sun8i-h3-nanopi.dtsi"
+
+/ {
+	model = "FriendlyElec NanoPi-R1";
+	compatible = "friendlyarm,nanopi-r1", "allwinner,sun8i-h3";
+
+	aliases {
+		ethernet0 = &emac;
+		ethernet1 = &usbr8152;
+		ethernet2 = &brcmf;
+		serial0 = &uart1;
+		serial1 = &uart0;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_npi>;
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+		post-power-on-delay-ms = <200>;
+	};
+
+	reg_gmac_3v3: gmac-3v3 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gmac_power_pin_nanopi>;
+		regulator-name = "gmac-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		enable-active-high;
+		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+	};
+
+	rfkill_bt {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_pwr_pin>;
+		reset-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+		clocks = <&osc32k>;
+		clock-frequency = <32768>;
+		rfkill-name = "sunxi-bt";
+		rfkill-type = "bluetooth";
+	};
+
+	leds {
+		/delete-node/ status;
+		/delete-node/ pwr;
+		led1 {
+			label = "nanopi-r1:red:status";
+			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led2 {
+			label = "nanopi-r1:green:wan";
+			gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+			linux,default-trigger = "netdev";
+		};
+
+		led3 {
+			label = "nanopi-r1:green:lan";
+			gpios = <&pio 0 9 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+			linux,default-trigger = "netdev";
+		};
+	};
+
+	reg_mp2143dj: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>;		// 50=4ms check
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;	// PL6 check
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_mp2143dj>;
+};
+
+&pio {
+	gmac_power_pin_nanopi: gmac_power_pin@0 {
+		pins = "PD6";
+		function = "gpio_out";
+	};
+	bt_pwr_pin: bt_pwr_pin@0 {
+		pins = "PG13";
+		function = "gpio_out";
+	};
+};
+
+&r_pio {
+	wifi_en_npi: wifi_en_pin {
+		pins = "PL7";
+		function = "gpio_out";
+	};
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+	};
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	usbr8152: usbether@1 {
+		compatible = "usb0bda,8152";
+		reg = <1>;
+    };
+};
+
+&ohci1 {
+	status = "disabled";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: bcrmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&pio>;
+		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 / EINT10 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&mmc2_8bit_pins {
+	/* Increase drive strength for DDR modes */
+	drive-strength = <40>;
+	/* eMMC is missing pull-ups */
+	bias-pull-up;
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
index c6decee41a27..f772a028ddfd 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi.dtsi
@@ -65,13 +65,13 @@
 		status {
 			label = "nanopi:blue:status";
 			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "heartbeat";
+			linux,default-trigger = "mmc0";
 		};
 
 		pwr {
 			label = "nanopi:green:pwr";
 			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
-			default-state = "on";
+			linux,default-trigger = "heartbeat";
 		};
 	};
 
@@ -87,6 +87,22 @@
 			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
 		};
 	};
+
+	// lower the cma shared mem pool from 64 to 8MB
+	// we use no mali
+	reserved-memory {
+		cma: linux,cma {
+			size = <0x800000>;
+		};
+	};
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
 };
 
 &ehci3 {
@@ -103,6 +119,14 @@
 	vmmc-supply = <&reg_vcc3v3>;
 };
 
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
 &ohci3 {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
index 8ff71b1bb45b..ace9c229b4d0 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
@@ -54,6 +54,7 @@
 	aliases {
 		serial0 = &uart0;
 		/* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
+		ethernet0 = &emac;
 		ethernet1 = &rtl8189;
 	};
 
@@ -61,6 +62,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -113,16 +125,49 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8106a>;
+};
+
 &ehci1 {
 	status = "okay";
 };
 
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -158,6 +203,20 @@
 	};
 };
 
+&r_i2c {
+	status = "okay";
+
+	reg_sy8106a: regulator@65 {
+		compatible = "silergy,sy8106a";
+		reg = <0x65>;
+		regulator-name = "vdd-cpux";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1400000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
 &r_pio {
 	leds_r_opc: led_pins@0 {
 		pins = "PL10";
@@ -180,6 +239,14 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
index 9b47a0def740..e63b8afc988e 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
@@ -61,6 +61,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -89,6 +100,31 @@
 			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
 		};
 	};
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; /* 4ms */
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&de {
+	status = "okay";
 };
 
 &ehci1 {
@@ -99,12 +135,30 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -159,6 +213,14 @@
 	};
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index 5fea430e0eb1..62d114b9a492 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -52,6 +52,7 @@
 	compatible = "xunlong,orangepi-one", "allwinner,sun8i-h3";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -59,6 +60,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -87,6 +99,31 @@
 			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
 		};
 	};
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; /* 4ms */
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&de {
+	status = "okay";
 };
 
 &ehci0 {
@@ -97,6 +134,31 @@
 	status = "okay";
 };
 
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -139,6 +201,14 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
index 8b93f5c781a7..948df1868c99 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc-plus.dts
@@ -51,12 +51,23 @@
 		/* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */
 		ethernet1 = &rtl8189ftv;
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 WIFI_EN */
+	};
+};
+
+&emac {
+	/* LEDs changed to active high on the plus */
+	/delete-property/ allwinner,leds-active-low;
 };
 
 &mmc1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc1_pins_a>;
 	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
 	bus-width = <4>;
 	non-removable;
 	status = "okay";
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index 1a044b17d6c6..8fe9a2f8749c 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -52,6 +52,7 @@
 	compatible = "xunlong,orangepi-pc", "allwinner,sun8i-h3";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -59,6 +60,17 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -97,6 +109,14 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&reg_sy8106a>;
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -113,12 +133,37 @@
 	status = "okay";
 };
 
+&emac {
+	phy-handle = <&int_mii_phy>;
+	phy-mode = "mii";
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -152,6 +197,20 @@
 	};
 };
 
+&r_i2c {
+	status = "okay";
+
+	reg_sy8106a: regulator@65 {
+		compatible = "silergy,sy8106a";
+		reg = <0x65>;
+		regulator-name = "vdd-cpux";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1400000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
 &r_pio {
 	leds_r_opc: led_pins@0 {
 		pins = "PL10";
@@ -169,6 +228,14 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
index 828ae7a526d9..3002c025e187 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
@@ -47,6 +47,10 @@
 	model = "Xunlong Orange Pi Plus / Plus 2";
 	compatible = "xunlong,orangepi-plus", "allwinner,sun8i-h3";
 
+	aliases {
+		ethernet0 = &emac;
+	};
+
 	reg_gmac_3v3: gmac-3v3 {
 		compatible = "regulator-fixed";
 		regulator-name = "gmac-3v3";
@@ -74,6 +78,24 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+
+	allwinner,leds-active-low;
+	status = "okay";
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0>;
+	};
+};
+
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_8bit_pins>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
index 97920b12a944..6dbf7b2e0c13 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
@@ -61,3 +61,19 @@
 		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
 	};
 };
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-zeroplus2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-zeroplus2.dts
new file mode 100644
index 000000000000..ed7ed31a293e
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-zeroplus2.dts
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) Armbian
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Xunlong Orange Pi Zero Plus 2";
+	compatible = "xunlong,orangepi-zeroplus", "allwinner,sun8i-h3";
+
+	aliases {
+		ethernet1 = &brcmf;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr_led {
+			label = "orangepi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		status_led {
+			label = "orangepi:red:status";
+			gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	/delete-node/ reg_vcc_wifi;
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pio 0 9 GPIO_ACTIVE_LOW>;
+		post-power-on-delay-ms = <50>;
+	};
+
+	reg_usb1_vbus: usb1-vbus {
+		/delete-property/ gpio;
+		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&i2s2 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	vqmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	/delete-node/ sdio_wifi@1;
+
+	brcmf: bcrmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&r_pio>;
+		interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 / EINT7 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&pio {
+    bt_pwr_pin: bt_pwr_pin@0 {
+        pins = "PA10";
+        function = "gpio_out";
+    };
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&spi0 {
+	/* Disable SPI NOR by default: it optional on Orange Pi Zero boards */
+	status = "disabled";
+
+	flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+		reg = <0>;
+		spi-max-frequency = <40000000>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/*
+	 * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only
+	 * power up the board; when it's used as OTG port, this VBUS is
+	 * always off even if the board is powered via GPIO pins.
+	 */
+	status = "okay";
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+};
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index b36f9f423c39..51a848a1d2f0 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -41,34 +41,242 @@
  */
 
 #include "sunxi-h3-h5.dtsi"
+#include <dt-bindings/thermal/thermal.h>
 
 / {
+	cpu_opp_table: opp_table {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp@240000000 {
+			opp-hz = /bits/ 64 <240000000>;
+			opp-microvolt = <980000 980000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@480000000 {
+			opp-hz = /bits/ 64 <480000000>;
+			opp-microvolt = <980000 980000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@648000000 {
+			opp-hz = /bits/ 64 <648000000>;
+			opp-microvolt = <1000000 1000000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@816000000 {
+			opp-hz = /bits/ 64 <816000000>;
+			opp-microvolt = <1020000 1020000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@912000000 {
+			opp-hz = /bits/ 64 <912000000>;
+			opp-microvolt = <1040000 1040000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@960000000 {
+			opp-hz = /bits/ 64 <960000000>;
+			opp-microvolt = <1080000 1080000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1008000000 {
+			opp-hz = /bits/ 64 <1008000000>;
+			opp-microvolt = <1140000 1140000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1104000000 {
+			opp-hz = /bits/ 64 <1104000000>;
+			opp-microvolt = <1180000 1180000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1200000000 {
+			opp-hz = /bits/ 64 <1200000000>;
+			opp-microvolt = <1240000 1240000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1296000000 {
+			opp-hz = /bits/ 64 <1296000000>;
+			opp-microvolt = <1320000 1320000 1320000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		cpu@0 {
+		cpu0: cpu@0 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&ccu CLK_CPUX>;
+			clock-names = "cpu";
+			operating-points-v2 = <&cpu_opp_table>;
+			cpu-supply = <&reg_cpu_fallback>;
+			#cooling-cells = <2>;
 		};
 
 		cpu@1 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <1>;
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu@2 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <2>;
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu@3 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <3>;
+			operating-points-v2 = <&cpu_opp_table>;
+		};
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&ths>;
+	};
+
+	soc {
+		ths: thermal-sensor@1c25000 {
+			compatible = "allwinner,sun8i-h3-ths";
+			reg = <0x01c25000 0x100>;
+			clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_THS>;
+			#thermal-sensor-cells = <0>;
+			#io-channel-cells = <0>;
+		};
+	};
+
+	thermal-zones {
+		cpu-thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&ths>;
+
+			trips {
+				cpu_warm: cpu_warm {
+					temperature = <65000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot_pre: cpu_hot_pre {
+					temperature = <70000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot: cpu_hot {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot_pre: cpu_very_hot_pre {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot: cpu_very_hot {
+					temperature = <90000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				cpu_warm_limit_cpu {
+					trip = <&cpu_warm>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT 2>;
+				};
+
+				cpu_hot_pre_limit_cpu {
+					trip = <&cpu_hot_pre>;
+					cooling-device = <&cpu0 2 3>;
+				};
+
+				cpu_hot_limit_cpu {
+					trip = <&cpu_hot>;
+					cooling-device = <&cpu0 3 4>;
+				};
+
+				cpu_very_hot_pre_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 5 6>;
+				};
+
+				cpu_very_hot_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	soc {
+		mali: gpu@1c40000 {
+			compatible = "allwinner,sun8i-h3-mali",
+				     "allwinner,sun7i-a20-mali", "arm,mali-400";
+			reg = <0x01c40000 0x10000>;
+			interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "gp",
+					  "gpmmu",
+					  "pp0",
+					  "ppmmu0",
+					  "pp1",
+					  "ppmmu1",
+					  "pmu";
+			clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
+			clock-names = "bus", "core";
+			resets = <&ccu RST_BUS_GPU>;
+			memory-region = <&cma>;
+
+			assigned-clocks = <&ccu CLK_GPU>;
+			assigned-clock-rates = <384000000>;
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		cma: linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x4000000>;
+			alignment = <0x2000>;
+			linux,cma-default;
 		};
 	};
 
@@ -79,12 +287,27 @@
 			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
 			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
 	};
+
+	reg_cpu_fallback: reg_cpu_fallback  {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-cpux-dummy";
+		regulator-min-microvolt = <1200000>;
+		regulator-max-microvolt = <1200000>;
+	};
 };
 
 &ccu {
 	compatible = "allwinner,sun8i-h3-ccu";
 };
 
+&display_clocks {
+	compatible = "allwinner,sun8i-a83t-de2-clk";
+};
+
+&mixer1 {
+	resets = <&display_clocks RST_WB>;
+};
+
 &mmc0 {
 	compatible = "allwinner,sun7i-a20-mmc";
 	clocks = <&ccu CLK_BUS_MMC0>,
diff --git a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
new file mode 100644
index 000000000000..5587d724ca07
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-r40.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Banana Pi BPI-M2-Ultra";
+	compatible = "sinovoip,bpi-m2-ultra", "allwinner,sun8i-r40";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr-led {
+			label = "bananapi:red:pwr";
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		user-led-green {
+			label = "bananapi:green:user";
+			gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>;
+		};
+
+		user-led-blue {
+			label = "bananapi:blue:user";
+			gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	reg_vcc5v0: vcc5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>; /* PH23 */
+		enable-active-high;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&pio 6 10 GPIO_ACTIVE_LOW>; /* PG10 WIFI_EN */
+	};
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	axp22x: pmic@34 {
+		compatible = "x-powers,axp221";
+		reg = <0x34>;
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+#include "axp22x.dtsi"
+
+&ahci {
+	vdd1v2-supply = <&reg_eldo3>;
+	vdd2v5-supply = <&reg_dldo4>;
+	status = "okay";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avcc";
+};
+
+&reg_dldo4 {
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "vdd-2v5-sata";
+};
+
+&reg_eldo3 {
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "vdd-1v2-sata";
+};
+
+&reg_dcdc1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1500000>;
+	regulator-max-microvolt = <1500000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_dldo1 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi-io";
+};
+
+&reg_dldo2 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
+
+&mmc0 {
+	vmmc-supply = <&reg_dcdc1>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pg_pins>;
+	vmmc-supply = <&reg_dldo2>;
+	vqmmc-supply = <&reg_dldo1>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+&mmc2 {
+	vmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pb_pins>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_vcc5v0>;
+	usb2_vbus-supply = <&reg_vcc5v0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
new file mode 100644
index 000000000000..ef4df3bb7434
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2017 Chen-Yu Tsai <wens@csie.org>
+ * Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-r40-ccu.h>
+#include <dt-bindings/reset/sun8i-r40-ccu.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&gic>;
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		osc24M: osc24M {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			clock-output-names = "osc24M";
+		};
+
+		osc32k: osc32k {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <32768>;
+			clock-output-names = "osc32k";
+		};
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <0>;
+		};
+
+		cpu@1 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <1>;
+		};
+
+		cpu@2 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <2>;
+		};
+
+		cpu@3 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <3>;
+		};
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		nmi_intc: interrupt-controller@1c00030 {
+			compatible = "allwinner,sun7i-a20-sc-nmi";
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			reg = <0x01c00030 0x0c>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		mmc0: mmc@1c0f000 {
+			compatible = "allwinner,sun8i-r40-mmc",
+				     "allwinner,sun50i-a64-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+			clock-names = "ahb", "mmc";
+			resets = <&ccu RST_BUS_MMC0>;
+			reset-names = "ahb";
+			pinctrl-0 = <&mmc0_pins>;
+			pinctrl-names = "default";
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc1: mmc@1c10000 {
+			compatible = "allwinner,sun8i-r40-mmc",
+				     "allwinner,sun50i-a64-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+			clock-names = "ahb", "mmc";
+			resets = <&ccu RST_BUS_MMC1>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc2: mmc@1c11000 {
+			compatible = "allwinner,sun8i-r40-emmc",
+				     "allwinner,sun50i-a64-emmc";
+			reg = <0x01c11000 0x1000>;
+			clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+			clock-names = "ahb", "mmc";
+			resets = <&ccu RST_BUS_MMC2>;
+			reset-names = "ahb";
+			pinctrl-0 = <&mmc2_pins>;
+			pinctrl-names = "default";
+			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc3: mmc@1c12000 {
+			compatible = "allwinner,sun8i-r40-mmc",
+				     "allwinner,sun50i-a64-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&ccu CLK_BUS_MMC3>, <&ccu CLK_MMC3>;
+			clock-names = "ahb", "mmc";
+			resets = <&ccu RST_BUS_MMC3>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		usbphy: phy@1c13400 {
+			compatible = "allwinner,sun8i-r40-usb-phy";
+			reg = <0x01c13400 0x14>,
+			      <0x01c14800 0x4>,
+			      <0x01c19800 0x4>,
+			      <0x01c1c800 0x4>;
+			reg-names = "phy_ctrl",
+				    "pmu0",
+				    "pmu1",
+				    "pmu2";
+			clocks = <&ccu CLK_USB_PHY0>,
+				 <&ccu CLK_USB_PHY1>,
+				 <&ccu CLK_USB_PHY2>;
+			clock-names = "usb0_phy",
+				      "usb1_phy",
+				      "usb2_phy";
+			resets = <&ccu RST_USB_PHY0>,
+				 <&ccu RST_USB_PHY1>,
+				 <&ccu RST_USB_PHY2>;
+			reset-names = "usb0_reset",
+				      "usb1_reset",
+				      "usb2_reset";
+			status = "disabled";
+			#phy-cells = <1>;
+		};
+
+		ehci1: usb@1c19000 {
+			compatible = "allwinner,sun8i-r40-ehci", "generic-ehci";
+			reg = <0x01c19000 0x100>;
+			interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_EHCI1>;
+			resets = <&ccu RST_BUS_EHCI1>;
+			phys = <&usbphy 1>;
+			phy-names = "usb";
+			status = "okay";
+		};
+
+		ohci1: usb@1c19400 {
+			compatible = "allwinner,sun8i-r40-ohci", "generic-ohci";
+			reg = <0x01c19400 0x100>;
+			interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_OHCI1>,
+				 <&ccu CLK_USB_OHCI1>;
+			resets = <&ccu RST_BUS_OHCI1>;
+			phys = <&usbphy 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		ehci2: usb@1c1c000 {
+			compatible = "allwinner,sun8i-r40-ehci", "generic-ehci";
+			reg = <0x01c1c000 0x100>;
+			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_EHCI2>;
+			resets = <&ccu RST_BUS_EHCI2>;
+			phys = <&usbphy 2>;
+			phy-names = "usb";
+			status = "okay";
+		};
+
+		ohci2: usb@1c1c400 {
+			compatible = "allwinner,sun8i-r40-ohci", "generic-ohci";
+			reg = <0x01c1c400 0x100>;
+			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_OHCI2>,
+				 <&ccu CLK_USB_OHCI2>;
+			resets = <&ccu RST_BUS_OHCI2>;
+			phys = <&usbphy 2>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		ahci: sata@1c18000 {
+			compatible = "allwinner,sun8i-r40-ahci", "allwinner,sun4i-a10-ahci";
+			reg = <0x01c18000 0x1000>;
+			interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_SATA>, <&ccu CLK_BUS_SATA>;
+			resets = <&ccu RST_BUS_SATA>;
+			status = "enabled";
+		};
+
+		ccu: clock@1c20000 {
+			compatible = "allwinner,sun8i-r40-ccu";
+			reg = <0x01c20000 0x400>;
+			clocks = <&osc24M>, <&osc32k>;
+			clock-names = "hosc", "losc";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		pio: pinctrl@1c20800 {
+			compatible = "allwinner,sun8i-r40-pinctrl";
+			reg = <0x01c20800 0x400>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
+			gpio-controller;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			#gpio-cells = <3>;
+
+			i2c0_pins: i2c0-pins {
+				pins = "PB0", "PB1";
+				function = "i2c0";
+			};
+
+			mmc0_pins: mmc0-pins {
+				pins = "PF0", "PF1", "PF2",
+				       "PF3", "PF4", "PF5";
+				function = "mmc0";
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
+			mmc1_pg_pins: mmc1-pg-pins {
+				pins = "PG0", "PG1", "PG2",
+				       "PG3", "PG4", "PG5";
+				function = "mmc1";
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
+			mmc2_pins: mmc2-pins {
+				pins = "PC5", "PC6", "PC7", "PC8", "PC9",
+				       "PC10", "PC11", "PC12", "PC13", "PC14",
+				       "PC15", "PC24";
+				function = "mmc2";
+				drive-strength = <30>;
+				bias-pull-up;
+			};
+
+			uart0_pb_pins: uart0-pb-pins {
+				pins = "PB22", "PB23";
+				function = "uart0";
+			};
+		};
+
+		wdt: watchdog@1c20c90 {
+			compatible = "allwinner,sun4i-a10-wdt";
+			reg = <0x01c20c90 0x10>;
+		};
+
+		uart0: serial@1c28000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28000 0x400>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART0>;
+			resets = <&ccu RST_BUS_UART0>;
+			status = "disabled";
+		};
+
+		uart1: serial@1c28400 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28400 0x400>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART1>;
+			resets = <&ccu RST_BUS_UART1>;
+			status = "disabled";
+		};
+
+		uart2: serial@1c28800 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28800 0x400>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART2>;
+			resets = <&ccu RST_BUS_UART2>;
+			status = "disabled";
+		};
+
+		uart3: serial@1c28c00 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28c00 0x400>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART3>;
+			resets = <&ccu RST_BUS_UART3>;
+			status = "disabled";
+		};
+
+		uart4: serial@1c29000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c29000 0x400>;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART4>;
+			resets = <&ccu RST_BUS_UART4>;
+			status = "disabled";
+		};
+
+		uart5: serial@1c29400 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c29400 0x400>;
+			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART5>;
+			resets = <&ccu RST_BUS_UART5>;
+			status = "disabled";
+		};
+
+		uart6: serial@1c29800 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c29800 0x400>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART6>;
+			resets = <&ccu RST_BUS_UART6>;
+			status = "disabled";
+		};
+
+		uart7: serial@1c29c00 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c29c00 0x400>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&ccu CLK_BUS_UART7>;
+			resets = <&ccu RST_BUS_UART7>;
+			status = "disabled";
+		};
+
+		i2c0: i2c@1c2ac00 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2ac00 0x400>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C0>;
+			resets = <&ccu RST_BUS_I2C0>;
+			pinctrl-0 = <&i2c0_pins>;
+			pinctrl-names = "default";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c1: i2c@1c2b000 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b000 0x400>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C1>;
+			resets = <&ccu RST_BUS_I2C1>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c2: i2c@1c2b400 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b400 0x400>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C2>;
+			resets = <&ccu RST_BUS_I2C2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c3: i2c@1c2b800 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b800 0x400>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C3>;
+			resets = <&ccu RST_BUS_I2C3>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c4: i2c@1c2c000 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2c000 0x400>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C4>;
+			resets = <&ccu RST_BUS_I2C4>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		gic: interrupt-controller@1c81000 {
+			compatible = "arm,gic-400";
+			reg = <0x01c81000 0x1000>,
+			      <0x01c82000 0x1000>,
+			      <0x01c84000 0x2000>,
+			      <0x01c86000 0x2000>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		};
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+	};
+};
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 03f37081fc64..0f0a56ec0a54 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -1,4 +1,4 @@
-/*
+	/*
  * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
  *
  * This file is dual-licensed: you can use it either under the terms
@@ -40,9 +40,11 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun8i-h3-ccu.h>
 #include <dt-bindings/clock/sun8i-r-ccu.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/sun8i-de2.h>
 #include <dt-bindings/reset/sun8i-h3-ccu.h>
 #include <dt-bindings/reset/sun8i-r-ccu.h>
 
@@ -51,6 +53,22 @@
 	#address-cells = <1>;
 	#size-cells = <1>;
 
+	sound_hdmi: sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,name = "allwinner,hdmi";
+		simple-audio-card,mclk-fs = <256>;
+		status = "disabled";
+
+		simple-audio-card,codec {
+			sound-dai = <&hdmi>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s2>;
+		};
+	};
+
 	clocks {
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -79,12 +97,135 @@
 		};
 	};
 
+	de: display-engine {
+		compatible = "allwinner,sun8i-h3-display-engine";
+		allwinner,pipelines = <&mixer0>,
+				      <&mixer1>;
+		status = "disabled";
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
 
+		display_clocks: clock@1000000 {
+			/* compatible is in per SoC .dtsi file */
+			reg = <0x01000000 0x100000>;
+			clocks = <&ccu CLK_BUS_DE>,
+				 <&ccu CLK_DE>;
+			clock-names = "bus",
+				      "mod";
+			resets = <&ccu RST_BUS_DE>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			assigned-clocks = <&ccu CLK_DE>;
+			assigned-clock-parents = <&ccu CLK_PLL_DE>;
+			assigned-clock-rates = <432000000>;
+		};
+
+		hdmi: hdmi@1ee0000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-h3-dw-hdmi";
+			reg = <0x01ee0000 0x10000>,
+			      <0x01ef0000 0x10000>;
+			reg-io-width = <1>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI>,
+				 <&ccu CLK_HDMI_DDC>;
+			clock-names = "iahb", "isfr", "ddc";
+			resets = <&ccu RST_BUS_HDMI0>, <&ccu RST_BUS_HDMI1>;
+			reset-names = "hdmi", "ddc";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				hdmi_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					hdmi_in_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_out_hdmi>;
+					};
+				};
+
+				hdmi_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+			};
+		};
+
+		mixer0: mixer@1100000 {
+			compatible = "allwinner,sun8i-h3-de2-mixer0";
+			reg = <0x01100000 0x100000>;
+			clocks = <&display_clocks CLK_BUS_MIXER0>,
+				 <&display_clocks CLK_MIXER0>;
+			clock-names = "bus",
+				      "mod";
+			resets = <&display_clocks RST_MIXER0>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					mixer0_out_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_mixer0>;
+					};
+
+					mixer0_out_tcon1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&tcon1_in_mixer0>;
+					};
+				};
+			};
+		};
+
+		mixer1: mixer@1200000 {
+			compatible = "allwinner,sun8i-h3-de2-mixer1";
+			reg = <0x01200000 0x100000>;
+			clocks = <&display_clocks CLK_BUS_MIXER1>,
+				 <&display_clocks CLK_MIXER1>;
+			clock-names = "bus",
+				      "mod";
+			/* resets is in per SoC .dtsi file */
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer1_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					mixer1_out_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_mixer1>;
+					};
+
+					mixer1_out_tcon1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&tcon1_in_mixer1>;
+					};
+				};
+			};
+		};
+
 		syscon: syscon@1c00000 {
 			compatible = "allwinner,sun8i-h3-system-controller",
 				"syscon";
@@ -100,6 +241,91 @@
 			#dma-cells = <1>;
 		};
 
+		tcon0: lcd-controller@1c0c000 {
+			compatible = "allwinner,sun8i-h3-tcon";
+			reg = <0x01c0c000 0x1000>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON0>,
+				 <&ccu CLK_TCON0>;
+			clock-names = "ahb",
+				      "tcon-ch1";
+			resets = <&ccu RST_BUS_TCON0>;
+			reset-names = "lcd";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon0_in_mixer0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&mixer0_out_tcon0>;
+					};
+
+					tcon0_in_mixer1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&mixer1_out_tcon0>;
+					};
+				};
+
+				tcon0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					tcon0_out_hdmi: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&hdmi_in_tcon0>;
+					};
+				};
+			};
+		};
+
+		tcon1: lcd-controller@1c0d000 {
+			compatible = "allwinner,sun8i-h3-tcon";
+			reg = <0x01c0d000 0x1000>;
+			interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON1>,
+				 <&ccu CLK_TVE>;
+			clock-names = "ahb",
+				      "tcon-ch1";
+			resets = <&ccu RST_BUS_TCON1>;
+			reset-names = "lcd";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon1_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon1_in_mixer0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&mixer0_out_tcon1>;
+					};
+
+					tcon1_in_mixer1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&mixer1_out_tcon1>;
+					};
+				};
+
+				tcon1_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+			};
+		};
+
 		mmc0: mmc@01c0f000 {
 			/* compatible and clocks are in per SoC .dtsi file */
 			reg = <0x01c0f000 0x1000>;
@@ -310,6 +536,16 @@
 				function = "i2c2";
 			};
 
+			i2s0_pins: i2s0 {
+				pins = "PA18", "PA19", "PA20", "PA21";
+				function = "i2s0";
+			};
+
+			i2s1_pins: i2s1 {
+				pins = "PG10", "PG11", "PG12", "PG13";
+				function = "i2s1";
+			};
+
 			mmc0_pins_a: mmc0@0 {
 				pins = "PF0", "PF1", "PF2", "PF3",
 				       "PF4", "PF5";
@@ -381,6 +617,12 @@
 				pins = "PA13", "PA14";
 				function = "uart3";
 			};
+
+			uart3_rts_cts_pins: uart3_rts_cts {
+				pins = "PA15", "PA16";
+				function = "uart3";
+			};
+
 		};
 
 		timer@01c20c00 {
@@ -391,6 +633,55 @@
 			clocks = <&osc24M>;
 		};
 
+		emac: ethernet@1c30000 {
+			compatible = "allwinner,sun8i-h3-emac";
+			syscon = <&syscon>;
+			reg = <0x01c30000 0x10000>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			resets = <&ccu RST_BUS_EMAC>;
+			reset-names = "stmmaceth";
+			clocks = <&ccu CLK_BUS_EMAC>;
+			clock-names = "stmmaceth";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			mdio: mdio {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "snps,dwmac-mdio";
+			};
+
+			mdio-mux {
+				compatible = "allwinner,sun8i-h3-mdio-mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mdio-parent-bus = <&mdio>;
+				/* Only one MDIO is usable at the time */
+				internal_mdio: mdio@1 {
+					compatible = "allwinner,sun8i-h3-mdio-internal";
+					reg = <1>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					int_mii_phy: ethernet-phy@1 {
+						compatible = "ethernet-phy-ieee802.3-c22";
+						reg = <1>;
+						clocks = <&ccu CLK_BUS_EPHY>;
+						resets = <&ccu RST_BUS_EPHY>;
+					};
+				};
+
+				external_mdio: mdio@2 {
+					reg = <2>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+				};
+			};
+		};
+
 		spi0: spi@01c68000 {
 			compatible = "allwinner,sun8i-h3-spi";
 			reg = <0x01c68000 0x1000>;
@@ -450,6 +741,45 @@
 			status = "disabled";
 		};
 
+		i2s0: i2s@01c22000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-h3-i2s";
+			reg = <0x01c22000 0x400>;
+			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 3>, <&dma 3>;
+			resets = <&ccu RST_BUS_I2S0>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		i2s1: i2s@01c22400 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-h3-i2s";
+			reg = <0x01c22400 0x400>;
+			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 4>, <&dma 4>;
+			resets = <&ccu RST_BUS_I2S1>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		i2s2: i2s@1c22800 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-h3-i2s";
+			reg = <0x01c22800 0x400>;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 27>;
+			resets = <&ccu RST_BUS_I2S2>;
+			dma-names = "tx";
+			status = "disabled";
+		};
+
 		codec: codec@01c22c00 {
 			#sound-dai-cells = <0>;
 			compatible = "allwinner,sun8i-h3-codec";
@@ -544,7 +874,7 @@
 
 		i2c2: i2c@01c2b400 {
 			compatible = "allwinner,sun6i-a31-i2c";
-			reg = <0x01c2b000 0x400>;
+			reg = <0x01c2b400 0x400>;
 			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ccu CLK_BUS_I2C2>;
 			resets = <&ccu RST_BUS_I2C2>;
@@ -598,6 +928,20 @@
 			status = "disabled";
 		};
 
+		r_i2c: i2c@01f02400 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01f02400 0x400>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&r_i2c_pins>;
+			clocks = <&r_ccu CLK_APB0_I2C>;
+			clock-frequency = <100000>;
+			resets = <&r_ccu RST_APB0_I2C>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		r_pio: pinctrl@01f02c00 {
 			compatible = "allwinner,sun8i-h3-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
@@ -613,6 +957,11 @@
 				pins = "PL11";
 				function = "s_cir_rx";
 			};
+
+			r_i2c_pins: r-i2c {
+				pins = "PL0", "PL1";
+				function = "s_i2c";
+			};
 		};
 	};
 };
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index fcf1473d6fed..4ac9d3fc1de8 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -381,7 +381,7 @@ static void __dma_free_remap(void *cpu_addr, size_t size)
 			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
 }
 
-#define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_256K
+#define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_2M
 static struct gen_pool *atomic_pool;
 
 static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile
index ff35e184e422..90bcd93be4b3 100644
--- a/arch/arm64/boot/dts/allwinner/Makefile
+++ b/arch/arm64/boot/dts/allwinner/Makefile
@@ -4,11 +4,15 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-nanopi-a64.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-olinuxino.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-orangepi-win.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-plus.dtb sun50i-a64-pine64.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pinebook.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-sopine-baseboard.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-pc2.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-prime.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-neo-plus2.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-nanopi-m1-plus2.dtb
 
 always		:= $(dtb-y)
 subdir-y	:= $(dts-dirs)
diff --git a/arch/arm64/boot/dts/allwinner/axp803.dtsi b/arch/arm64/boot/dts/allwinner/axp803.dtsi
index ff8af52743ff..3a8615231b7c 100644
--- a/arch/arm64/boot/dts/allwinner/axp803.dtsi
+++ b/arch/arm64/boot/dts/allwinner/axp803.dtsi
@@ -49,6 +49,16 @@
 	interrupt-controller;
 	#interrupt-cells = <1>;
 
+	ac_power_supply: ac-power-supply {
+		compatible = "x-powers,axp221-ac-power-supply";
+		status = "disabled";
+	};
+
+	battery_power_supply: battery-power-supply {
+		compatible = "x-powers,axp803-battery-power-supply";
+		status = "disabled";
+	};
+
 	regulators {
 		/* Default work frequency for buck regulators */
 		x-powers,dcdc-freq = <3000>;
@@ -147,4 +157,9 @@
 			regulator-name = "rtc-ldo";
 		};
 	};
+
+	usb_power_supply: usb_power_supply {
+		compatible = "x-powers,axp803-usb-power-supply";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
index d347f52e27f6..10cb4d133c98 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
@@ -51,6 +51,7 @@
 	compatible = "sinovoip,bananapi-m64", "allwinner,sun50i-a64";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 		serial1 = &uart1;
 	};
@@ -65,10 +66,31 @@
 	};
 };
 
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
 &ehci1 {
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii-txid";
+	phy-handle = <&ext_rgmii_phy>;
+	status = "okay";
+};
+
+&hdmi {
+	hvcc-supply = <&reg_dldo1>;
+	status = "okay";
+};
+
 &i2c1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c1_pins>;
@@ -79,6 +101,17 @@
 	bias-pull-up;
 };
 
+&mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer1 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
@@ -119,6 +152,10 @@
 	status = "okay";
 };
 
+&ohci0 {
+	status = "okay";
+};
+
 &ohci1 {
 	status = "okay";
 };
@@ -136,6 +173,21 @@
 
 #include "axp803.dtsi"
 
+&ac_power_supply {
+	status = "okay";
+};
+
+&battery_power_supply {
+	status = "okay";
+};
+
+
+&reg_aldo1 {
+	regulator-min-microvolt = <2800000>;
+	regulator-max-microvolt = <2800000>;
+	regulator-name = "vcc-csi";
+};
+
 &reg_aldo2 {
 	regulator-always-on;
 	regulator-min-microvolt = <1800000>;
@@ -145,12 +197,13 @@
 
 &reg_aldo3 {
 	regulator-always-on;
-	regulator-min-microvolt = <3000000>;
-	regulator-max-microvolt = <3000000>;
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
 	regulator-name = "vcc-pll-avcc";
 };
 
 &reg_dc1sw {
+	regulator-always-on;
 	regulator-name = "vcc-phy";
 };
 
@@ -196,6 +249,12 @@
 	regulator-name = "vcc-wifi";
 };
 
+&reg_dldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avdd-csi";
+};
+
 &reg_dldo4 {
 	regulator-min-microvolt = <1800000>;
 	regulator-max-microvolt = <3300000>;
@@ -208,6 +267,12 @@
 	regulator-name = "cpvdd";
 };
 
+&reg_eldo3 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vdd-1v8-csi";
+};
+
 &reg_fldo1 {
 	regulator-min-microvolt = <1200000>;
 	regulator-max-microvolt = <1200000>;
@@ -230,6 +295,14 @@
 	regulator-name = "vcc-rtc";
 };
 
+&simplefb_hdmi {
+	vcc-hdmi-supply = <&reg_dldo1>;
+};
+
+&tcon1 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
index aa0b3844ad63..fa05f3881d4c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
@@ -196,6 +196,10 @@
 	regulator-name = "vcc-rtc";
 };
 
+&simplefb_hdmi {
+	vcc-hdmi-supply = <&reg_dldo1>;
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
index 2ef779b02757..d8fae3469eb5 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2017 Jagan Teki <jteki@openedev.com>
+ * Armbian(c)
  *
  * This file is dual-licensed: you can use it either under the terms
  * of the GPL or the X11 license, at your option. Note that this dual
@@ -51,12 +52,65 @@
 	compatible = "olimex,a64-olinuxino", "allwinner,sun50i-a64";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
+		serial1 = &uart1;
 	};
 
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+ 		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
+ 	};
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii-txid";
+	phy-handle = <&ext_rgmii_phy>;
+	status = "okay";
+};
+
+&hdmi {
+	hvcc-supply = <&reg_dldo1>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c1_pins {
+	bias-pull-up;
+};
+
+&mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer1 {
+	status = "okay";
 };
 
 &mmc0 {
@@ -70,6 +124,42 @@
 	status = "okay";
 };
 
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&reg_aldo2>;
+	vqmmc-supply = <&reg_dldo4>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	rtl8723bs: wifi@1 {
+		reg = <1>;
+		interrupt-parent = <&r_pio>;
+		interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>; /* PL3 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
 &r_rsb {
 	status = "okay";
 
@@ -78,6 +168,7 @@
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
 
@@ -196,8 +287,22 @@
 	regulator-name = "vcc-rtc";
 };
 
+&tcon1 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
 	status = "okay";
 };
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+	status = "okay";
+};
+
+&usbphy {
+	status = "okay";
+};
\ No newline at end of file
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
index 5f8ff4017d45..376d7bfaec31 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
@@ -51,31 +51,110 @@
 	compatible = "xunlong,orangepi-win", "allwinner,sun50i-a64";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
+		serial1 = &uart1;
 	};
 
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
-	reg_vcc3v3: vcc3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "vcc3v3";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 */
+		post-power-on-delay-ms = <50>;
 	};
 };
 
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
 &ehci1 {
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii";
+	phy-handle = <&ext_rgmii_phy>;
+	phy-supply = <&reg_dc1sw>;
+	status = "okay";
+};
+
+&hdmi {
+	hvcc-supply = <&reg_dldo1>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c1_pins {
+	bias-pull-up;
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer1 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
-	vmmc-supply = <&reg_vcc3v3>;
+	vmmc-supply = <&reg_dcdc1>;
 	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
 	cd-inverted;
+	disable-wp;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&reg_dldo2>;
+	vqmmc-supply = <&reg_dldo4>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	brcmf: brcmf@1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+		interrupt-parent = <&r_pio>;
+		interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 / EINT7 */
+		interrupt-names = "host-wake";
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&ohci0 {
 	status = "okay";
 };
 
@@ -83,12 +162,152 @@
 	status = "okay";
 };
 
+&r_rsb {
+        status = "okay";
+
+        axp803: pmic@3a3 {
+                compatible = "x-powers,axp803";
+                reg = <0x3a3>;
+                interrupt-parent = <&r_intc>;
+                interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+        };
+};
+
+#include "axp803.dtsi"
+
+&reg_aldo1 {
+	regulator-min-microvolt = <2800000>;
+	regulator-max-microvolt = <2800000>;
+	regulator-name = "vcc-csi";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pl";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pll-avcc";
+};
+
+&reg_dc1sw {
+	regulator-always-on;
+	regulator-name = "vcc-phy";
+};
+
+&reg_dcdc1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-3v3";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1040000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-cpux";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1500000>;
+	regulator-max-microvolt = <1500000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_dcdc6 {
+	regulator-always-on;
+	regulator-min-microvolt = <1100000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dldo1 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-hdmi-dsi";
+};
+
+&reg_dldo2 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-mipi";
+};
+
+&reg_dldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avdd-csi";
+};
+
+&reg_dldo4 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
+
+&reg_eldo1 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "cpvdd";
+};
+
+&reg_eldo3 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vdd-1v8-csi";
+};
+
+&reg_fldo1 {
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "vcc-1v2-hsic";
+};
+
+/*
+ * The A64 chip cannot work without this regulator off, although
+ * it seems to be only driving the AR100 core.
+ * Maybe we don't still know well about CPUs domain.
+ */
+&reg_fldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1100000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpus";
+};
+
+&reg_rtc_ldo {
+	regulator-name = "vcc-rtc";
+};
+
+&simplefb_hdmi {
+	vcc-hdmi-supply = <&reg_dldo1>;
+};
+
+&tcon1 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
 	status = "okay";
 };
 
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+	status = "okay";
+};
+
 &usbphy {
 	status = "okay";
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts
index f82ccf332c0f..ed715426fffc 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64-plus.dts
@@ -48,3 +48,18 @@
 
 	/* TODO: Camera, touchscreen, etc. */
 };
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii-txid";
+	phy-handle = <&ext_rgmii_phy>;
+	status = "okay";
+};
+
+&mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
index d06e34b5d192..5bb28070f023 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
@@ -51,6 +51,7 @@
 	compatible = "pine64,pine64", "allwinner,sun50i-a64";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 		serial1 = &uart1;
 		serial2 = &uart2;
@@ -61,6 +62,15 @@
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
+	};
+};
+
+&de {
+	status = "okay";
 };
 
 &ehci0 {
@@ -71,6 +81,20 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rmii_pins>;
+	phy-mode = "rmii";
+	phy-handle = <&ext_rmii_phy1>;
+	phy-supply = <&reg_dc1sw>;
+	status = "okay";
+};
+
+&hdmi {
+	hvcc-supply = <&reg_dldo1>;
+	status = "okay";
+};
+
 &i2c1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2c1_pins>;
@@ -81,6 +105,17 @@
 	bias-pull-up;
 };
 
+&mdio {
+	ext_rmii_phy1: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer1 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
@@ -92,6 +127,17 @@
 	status = "okay";
 };
 
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&reg_dldo4>;
+	vqmmc-supply = <&reg_eldo1>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	non-removable;
+	bus-width = <4>;
+	status = "okay";
+};
+
 &ohci0 {
 	status = "okay";
 };
@@ -113,6 +159,14 @@
 
 #include "axp803.dtsi"
 
+&ac_power_supply {
+	status = "okay";
+};
+
+&battery_power_supply {
+	status = "okay";
+};
+
 &reg_aldo2 {
 	regulator-always-on;
 	regulator-min-microvolt = <1800000>;
@@ -212,6 +266,14 @@
 	regulator-name = "vcc-rtc";
 };
 
+&simplefb_hdmi {
+	vcc-hdmi-supply = <&reg_dldo1>;
+};
+
+&tcon1 {
+	status = "okay";
+};
+
 /* On Exp and Euler connectors */
 &uart0 {
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
new file mode 100644
index 000000000000..fad0645725db
--- /dev/null
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2016 ARM Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This library 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 library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "sun50i-a64.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+	model = "Pinebook";
+	compatible = "pine64,pinebook", "allwinner,sun50i-a64";
+
+	aliases {
+		serial0 = &uart0;
+		ethernet0 = &rtl8723cs;
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 0>;
+		brightness-levels = <0 30 40 50 60 70 80 90 100>;
+		default-brightness-level = <6>;
+		enable-gpios = <&pio 3 23 GPIO_ACTIVE_HIGH>; /* PD23 */
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		lid-switch {
+			label = "Lid Switch";
+			gpios = <&r_pio 0 12 GPIO_ACTIVE_LOW>; /* PL12 */
+			linux,input-type = <EV_SW>;
+			linux,code = <SW_LID>;
+			linux,can-disable;
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	disable-wp;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&reg_dldo4>;
+	vqmmc-supply = <&reg_eldo1>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	rtl8723cs: wifi@1 {
+		reg = <1>;
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	vqmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pins>;
+	status = "okay";
+};
+
+&r_i2c {
+	pinctrl-names = "default";
+	pinctrl-0 = <&r_i2c_pins_a>;
+	status = "okay";
+
+	anx6345: anx6345@38 {
+		compatible = "analogix,anx6345";
+		reg = <0x38>;
+		reset-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
+		panel-supply = <&reg_dc1sw>;
+		dvdd25-supply = <&reg_dldo2>;
+		dvdd12-supply = <&reg_fldo1>;
+
+		port {
+			anx6345_in: endpoint {
+				remote-endpoint = <&tcon0_out_anx6345>;
+			};
+		};
+	};
+};
+
+&r_rsb {
+	status = "okay";
+
+	axp803: pmic@3a3 {
+		compatible = "x-powers,axp803";
+		reg = <0x3a3>;
+		interrupt-parent = <&r_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+#include "axp803.dtsi"
+
+&ac_power_supply {
+	status = "okay";
+};
+
+&battery_power_supply {
+	status = "okay";
+};
+
+&reg_aldo1 {
+	regulator-min-microvolt = <2800000>;
+	regulator-max-microvolt = <2800000>;
+	regulator-name = "vcc-csi";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pl";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-pll-avcc";
+};
+
+&reg_dc1sw {
+	regulator-name = "vcc-lcd";
+};
+
+&reg_dcdc1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-3v3";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-cpux";
+};
+
+/* DCDC3 is polyphased with DCDC2 */
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1500000>;
+	regulator-max-microvolt = <1500000>;
+	regulator-name = "vcc-dram";
+};
+
+&reg_dcdc6 {
+	regulator-always-on;
+	regulator-min-microvolt = <1100000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dldo1 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-hdmi";
+};
+
+&reg_dldo2 {
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "vcc-edp";
+};
+
+&reg_dldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avdd-csi";
+};
+
+&reg_dldo4 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
+
+&reg_eldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "cpvdd";
+};
+
+&reg_eldo3 {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-name = "vdd-1v8-csi";
+};
+
+&reg_fldo1 {
+	regulator-min-microvolt = <1200000>;
+	regulator-max-microvolt = <1200000>;
+	regulator-name = "vcc-1v2-hsic";
+};
+
+&reg_fldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1100000>;
+	regulator-max-microvolt = <1100000>;
+	regulator-name = "vdd-cpus";
+};
+
+&reg_ldo_io0 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-usb";
+	status = "okay";
+};
+
+&reg_rtc_ldo {
+	regulator-name = "vcc-rtc";
+};
+
+&simplefb_lcd {
+	vcc-lcd-supply = <&reg_dc1sw>;
+	edp-2v5-supply = <&reg_dldo2>;
+	edp-1v2-supply = <&reg_fldo1>;
+};
+
+&tcon0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&lcd_rgb666_pins>;
+
+	status = "okay";
+};
+
+&tcon0_out {
+	tcon0_out_anx6345: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&anx6345_in>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_vbus-supply = <&reg_ldo_io0>;
+	usb1_vbus-supply = <&reg_ldo_io0>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
index 17ccc12b58df..f9f9484948fd 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts
@@ -47,12 +47,15 @@
 
 #include "sun50i-a64-sopine.dtsi"
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
 	model = "SoPine with baseboard";
 	compatible = "pine64,sopine-baseboard", "pine64,sopine",
 		     "allwinner,sun50i-a64";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -66,6 +69,15 @@
 		regulator-min-microvolt = <1800000>;
 		regulator-max-microvolt = <1800000>;
 	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
+	};
+};
+
+&de {
+	status = "okay";
 };
 
 &ehci0 {
@@ -76,6 +88,42 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
+	phy-mode = "rgmii";
+	phy-handle = <&ext_rgmii_phy>;
+	phy-supply = <&reg_dc1sw>;
+	status = "okay";
+};
+
+&hdmi {
+	hvcc-supply = <&reg_dldo1>;
+	status = "okay";
+};
+
+&mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer1 {
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	vmmc-supply = <&reg_dldo4>;
+	vqmmc-supply = <&reg_eldo1>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	non-removable;
+	bus-width = <4>;
+	status = "okay";
+};
+
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_pins>;
@@ -117,6 +165,14 @@
 	regulator-name = "vcc-wifi";
 };
 
+&simplefb_hdmi {
+	vcc-hdmi-supply = <&reg_dldo1>;
+};
+
+&tcon1 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 788a6f8c5994..8134c6831e3f 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -42,16 +42,111 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <dt-bindings/clock/sun8i-de2.h>
 #include <dt-bindings/clock/sun50i-a64-ccu.h>
 #include <dt-bindings/clock/sun8i-r-ccu.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/sun8i-de2.h>
 #include <dt-bindings/reset/sun50i-a64-ccu.h>
+#include <dt-bindings/clock/sun8i-de2.h>
+#include <dt-bindings/reset/sun8i-de2.h>
+#include <dt-bindings/clock/sun8i-r-ccu.h>
+#include <dt-bindings/reset/sun8i-r-ccu.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	interrupt-parent = <&gic>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 
+	chosen {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		simplefb_lcd: framebuffer-lcd {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "mixer0-lcd0";
+			clocks = <&display_clocks CLK_BUS_MIXER0>,
+				 <&ccu CLK_BUS_TCON0>, <&ccu CLK_BUS_TCON0>,
+				 <&display_clocks CLK_MIXER0>,
+				 <&ccu CLK_TCON0>;
+			status = "disabled";
+		};
+
+		simplefb_hdmi: framebuffer-hdmi {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "mixer1-lcd1-hdmi";
+			clocks = <&display_clocks CLK_BUS_MIXER1>,
+				 <&ccu CLK_BUS_TCON1>, <&ccu CLK_BUS_HDMI>,
+				 <&display_clocks CLK_MIXER1>,
+				 <&ccu CLK_TCON1>, <&ccu CLK_HDMI>,
+				 <&ccu CLK_HDMI_DDC>;
+			status = "disabled";
+		};
+	};
+
+	cpu_opp_table: opp_table {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp@408000000 {
+			opp-hz = /bits/ 64 <408000000>;
+			opp-microvolt = <1000000 1000000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@648000000 {
+			opp-hz = /bits/ 64 <648000000>;
+			opp-microvolt = <1040000 1040000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@816000000 {
+			opp-hz = /bits/ 64 <816000000>;
+			opp-microvolt = <1080000 1080000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@912000000 {
+		       opp-hz = /bits/ 64 <912000000>;
+		       opp-microvolt = <1120000 1120000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@960000000 {
+		       opp-hz = /bits/ 64 <960000000>;
+		       opp-microvolt = <1160000 1160000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1008000000 {
+		       opp-hz = /bits/ 64 <1008000000>;
+		       opp-microvolt = <1200000 1200000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1056000000 {
+		       opp-hz = /bits/ 64 <1056000000>;
+		       opp-microvolt = <1240000 1240000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1104000000 {
+		       opp-hz = /bits/ 64 <1104000000>;
+		       opp-microvolt = <1260000 1260000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1152000000 {
+		       opp-hz = /bits/ 64 <1152000000>;
+		       opp-microvolt = <1300000 1300000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -61,6 +156,9 @@
 			device_type = "cpu";
 			reg = <0>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
+			cpu-supply = <&reg_cpu_fallback>;
+			#cooling-cells = <2>;
 		};
 
 		cpu1: cpu@1 {
@@ -68,6 +166,7 @@
 			device_type = "cpu";
 			reg = <1>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu2: cpu@2 {
@@ -75,6 +174,7 @@
 			device_type = "cpu";
 			reg = <2>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu3: cpu@3 {
@@ -82,9 +182,17 @@
 			device_type = "cpu";
 			reg = <3>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 	};
 
+	de: display-engine {
+		compatible = "allwinner,sun50i-a64-display-engine";
+		allwinner,pipelines = <&mixer0>,
+				      <&mixer1>;
+		status = "disabled";
+	};
+
 	osc24M: osc24M_clk {
 		#clock-cells = <0>;
 		compatible = "fixed-clock";
@@ -112,8 +220,103 @@
 		method = "smc";
 	};
 
+	thermal-zones {
+		cpu-thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&ths>;
+
+			trips {
+				cpu_warm: cpu_warm {
+					temperature = <65000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot_pre: cpu_hot_pre {
+					temperature = <70000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot: cpu_hot {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot_pre: cpu_very_hot_pre {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot: cpu_very_hot {
+					temperature = <90000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				cpu_warm_limit_cpu {
+					trip = <&cpu_warm>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT 2>;
+				};
+
+				cpu_hot_pre_limit_cpu {
+					trip = <&cpu_hot_pre>;
+					cooling-device = <&cpu0 2 3>;
+				};
+
+				cpu_hot_limit_cpu {
+					trip = <&cpu_hot>;
+					cooling-device = <&cpu0 3 4>;
+				};
+
+				cpu_very_hot_pre_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 5 6>;
+				};
+
+				cpu_very_hot_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	reg_cpu_fallback: reg_cpu_fallback  {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-cpux-dummy";
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		cma: linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x4000000>;
+			alignment = <0x2000>;
+			linux,cma-default;
+		};
+	};
 	timer {
 		compatible = "arm,armv8-timer";
+		fsl,erratum-a008585;
 		interrupts = <GIC_PPI 13
 			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
 			     <GIC_PPI 14
@@ -130,12 +333,217 @@
 		#size-cells = <1>;
 		ranges;
 
+		ths: thermal-sensor@1c25000 {
+			compatible = "allwinner,sun50i-h5-ths";
+			reg = <0x01c25000 0x100>;
+			clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_THS>;
+			#thermal-sensor-cells = <0>;
+			#io-channel-cells = <0>;
+		};
+
+		display_clocks: clock@1000000 {
+			compatible = "allwinner,sun50i-a64-de2-clk";
+			reg = <0x01000000 0x100000>;
+			clocks = <&ccu CLK_DE>,
+				 <&ccu CLK_BUS_DE>;
+			clock-names = "mod",
+				      "bus";
+			resets = <&ccu RST_BUS_DE>;
+			allwinner,sram = <&de2_sram 1>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		mixer0: mixer@1100000 {
+			compatible = "allwinner,sun50i-a64-de2-mixer0";
+			reg = <0x01100000 0x100000>;
+			clocks = <&display_clocks CLK_MIXER0>,
+				 <&display_clocks CLK_BUS_MIXER0>;
+			clock-names = "mod",
+				      "bus";
+			resets = <&display_clocks RST_MIXER0>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					mixer0_out_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_mixer0>;
+					};
+
+					mixer0_out_tcon1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&tcon1_in_mixer0>;
+					};
+				};
+			};
+		};
+
+		mixer1: mixer@1200000 {
+			compatible = "allwinner,sun50i-a64-de2-mixer1";
+			reg = <0x01200000 0x100000>;
+			clocks = <&display_clocks CLK_MIXER1>,
+				 <&display_clocks CLK_BUS_MIXER1>;
+			clock-names = "mod",
+				      "bus";
+			resets = <&display_clocks RST_MIXER1>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer1_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					mixer1_out_tcon1: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon1_in_mixer1>;
+					};
+
+					mixer1_out_tcon0: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&tcon0_in_mixer1>;
+					};
+				};
+			};
+		};
+
+		tcon0: lcd-controller@01c0c000 {
+			compatible = "allwinner,sun50i-a64-tcon0";
+			reg = <0x01c0c000 0x1000>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON0>,
+				 <&ccu CLK_TCON0>;
+			clock-names = "ahb",
+				      "tcon-ch0";
+			clock-output-names = "tcon-pixel-clock";
+			resets = <&ccu RST_BUS_TCON0>;
+			reset-names = "lcd";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon0_in_mixer0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&mixer0_out_tcon0>;
+					};
+
+					tcon0_in_mixer1: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&mixer1_out_tcon0>;
+					};
+				};
+
+				tcon0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+			};
+		};
+
+		tcon1: lcd-controller@1c0d000 {
+			compatible = "allwinner,sun50i-a64-tcon1";
+			reg = <0x01c0d000 0x1000>;
+			interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON1>,
+				 <&ccu CLK_TCON1>;
+			clock-names = "ahb",
+				      "tcon-ch1";
+			resets = <&ccu RST_BUS_TCON1>;
+			reset-names = "lcd";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon1_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon1_in_mixer1: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&mixer1_out_tcon1>;
+					};
+
+					tcon1_in_mixer0: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&mixer0_out_tcon1>;
+					};
+				};
+
+				tcon1_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					tcon1_out_hdmi: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&hdmi_in_tcon1>;
+					};
+				};
+			};
+		};
+
 		syscon: syscon@1c00000 {
 			compatible = "allwinner,sun50i-a64-system-controller",
 				"syscon";
 			reg = <0x01c00000 0x1000>;
 		};
 
+		dma: dma-controller@1c02000 {
+			compatible = "allwinner,sun50i-a64-dma";
+			reg = <0x01c02000 0x1000>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_DMA>;
+			dma-channels = <8>;
+			dma-requests = <27>;
+			resets = <&ccu RST_BUS_DMA>;
+			#dma-cells = <1>;
+		};
+
+		sram-controller@1c00000 {
+			compatible = "allwinner,sun50i-a64-sram-controller";
+			reg = <0x01c00000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			sram_c: sram@18000 {
+				compatible = "mmio-sram";
+				reg = <0x00018000 0x28000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x00018000 0x28000>;
+
+				de2_sram: sram-section@0 {
+					compatible = "allwinner,sun50i-a64-sram-c";
+					reg = <0x0000 0x28000>;
+				};
+			};
+		};
+
 		mmc0: mmc@1c0f000 {
 			compatible = "allwinner,sun50i-a64-mmc";
 			reg = <0x01c0f000 0x1000>;
@@ -286,6 +694,15 @@
 				function = "i2c1";
 			};
 
+			lcd_rgb666_pins: lcd-rgb666 {
+				pins = "PD0", "PD1", "PD2", "PD3", "PD4",
+				       "PD5", "PD6", "PD7", "PD8", "PD9",
+				       "PD10", "PD11", "PD12", "PD13",
+				       "PD14", "PD15", "PD16", "PD17",
+				       "PD18", "PD19", "PD20", "PD21";
+				function = "lcd0";
+			};
+
 			mmc0_pins: mmc0-pins {
 				pins = "PF0", "PF1", "PF2", "PF3",
 				       "PF4", "PF5";
@@ -311,6 +728,11 @@
 				bias-pull-up;
 			};
 
+			pwm0_pins: pwm0 {
+				pins = "PD22";
+				function = "pwm";
+			};
+
 			rmii_pins: rmii_pins {
 				pins = "PD10", "PD11", "PD13", "PD14", "PD17",
 				       "PD18", "PD19", "PD20", "PD22", "PD23";
@@ -326,6 +748,16 @@
 				drive-strength = <40>;
 			};
 
+			spi0_pins: spi0 {
+				pins = "PC0", "PC1", "PC2", "PC3";
+				function = "spi0";
+			};
+
+			spi1_pins: spi1 {
+				pins = "PA15", "PA16", "PA14", "PA13";
+				function = "spi1";
+			};
+
 			uart0_pins_a: uart0@0 {
 				pins = "PB8", "PB9";
 				function = "uart0";
@@ -362,6 +794,42 @@
 			};
 		};
 
+		pwm: pwm@01c21400 {
+			compatible = "allwinner,sun50i-a64-pwm";
+			reg = <0x01c21400 0x8>;
+			clocks = <&osc24M>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		spi0: spi@01c68000 {
+			compatible = "allwinner,sun8i-h3-spi";
+			reg = <0x01c68000 0x1000>;
+			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+			clock-names = "ahb", "mod";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi0_pins>;
+			resets = <&ccu RST_BUS_SPI0>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		spi1: spi@01c69000 {
+			compatible = "allwinner,sun8i-h3-spi";
+			reg = <0x01c69000 0x1000>;
+			interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+			clock-names = "ahb", "mod";
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi1_pins>;
+			resets = <&ccu RST_BUS_SPI1>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		uart0: serial@1c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
@@ -450,6 +918,82 @@
 			#size-cells = <0>;
 		};
 
+		emac: ethernet@1c30000 {
+			compatible = "allwinner,sun50i-a64-emac";
+			syscon = <&syscon>;
+			reg = <0x01c30000 0x10000>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+			resets = <&ccu RST_BUS_EMAC>;
+			reset-names = "stmmaceth";
+			clocks = <&ccu CLK_BUS_EMAC>;
+			clock-names = "stmmaceth";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mdio: mdio {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "snps,dwmac-mdio";
+			};
+
+			mdio-mux {
+				compatible = "allwinner,sun8i-h3-mdio-mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mdio-parent-bus = <&mdio>;
+				/* Only one MDIO is usable at the time */
+				internal_mdio: mdio@1 {
+					compatible = "allwinner,sun50i-a64-emac";
+ 					reg = <1>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					int_mii_phy: ethernet-phy@1 {
+						compatible = "ethernet-phy-ieee802.3-c22";
+						reg = <1>;
+						clocks = <&ccu CLK_BUS_EMAC>;
+						resets = <&ccu RST_BUS_EMAC>;
+					};
+				};
+
+				external_mdio: mdio@2 {
+					reg = <2>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+ 				};
+ 			};
+		};
+
+		mali: gpu@1c40000 {
+			compatible = "allwinner,sun50i-a64-mali",
+				     "allwinner,sun7i-a20-mali", "arm,mali-400";
+			reg = <0x01c40000 0x10000>;
+			interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "gp",
+					  "gpmmu",
+					  "pp0",
+					  "ppmmu0",
+					  "pp1",
+					  "ppmmu1",
+					  "pmu";
+			clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
+			clock-names = "bus", "core";
+			resets = <&ccu RST_BUS_GPU>;
+			memory-region = <&cma>;
+
+			assigned-clocks = <&ccu CLK_GPU>;
+			assigned-clock-rates = <384000000>;
+		};
+
 		gic: interrupt-controller@1c81000 {
 			compatible = "arm,gic-400";
 			reg = <0x01c81000 0x1000>,
@@ -461,6 +1005,36 @@
 			#interrupt-cells = <3>;
 		};
 
+		hdmi: hdmi@1ee0000 {
+			compatible = "allwinner,h3-dw-hdmi";
+			reg = <0x01ee0000 0x10000>,
+			      <0x01ef0000 0x10000>;
+			reg-io-width = <1>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI>,
+				 <&ccu CLK_HDMI_DDC>;
+			clock-names = "iahb", "isfr", "iddc";
+			resets = <&ccu RST_BUS_HDMI0>, <&ccu RST_BUS_HDMI1>;
+			reset-names = "hdmi", "ddc";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					hdmi_in_tcon1: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon1_out_hdmi>;
+					};
+				};
+			};
+		};
+
 		rtc: rtc@1f00000 {
 			compatible = "allwinner,sun6i-a31-rtc";
 			reg = <0x01f00000 0x54>;
@@ -477,6 +1051,14 @@
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		nmi_intc: interrupt-controller@01f00c0c {
+			compatible = "allwinner,sun6i-a31-sc-nmi";
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			reg = <0x01f00c0c 0x38>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		r_ccu: clock@1f01400 {
 			compatible = "allwinner,sun50i-a64-r-ccu";
 			reg = <0x01f01400 0x100>;
@@ -487,6 +1069,17 @@
 			#reset-cells = <1>;
 		};
 
+		r_i2c: i2c@1f02400 {
+			compatible = "allwinner,sun6i-a31-i2c";
+			reg = <0x01f02400 0x400>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&r_ccu CLK_APB0_I2C>;
+			resets = <&r_ccu RST_APB0_I2C>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		r_pio: pinctrl@01f02c00 {
 			compatible = "allwinner,sun50i-a64-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
@@ -502,6 +1095,11 @@
 				pins = "PL0", "PL1";
 				function = "s_rsb";
 			};
+
+			r_i2c_pins_a: i2c-a {
+				pins = "PL8", "PL9";
+				function = "s_i2c";
+			};
 		};
 
 		r_rsb: rsb@1f03400 {
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-m1-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-m1-plus2.dts
new file mode 100644
index 000000000000..484c81c6c495
--- /dev/null
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-m1-plus2.dts
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ * Copyright (C) 2017 Armbian
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "FriendlyARM Nanopi M1 Plus 2";
+	compatible = "friendlyarm,nanopi-neo2", "allwinner,sun50i-h5";
+
+	aliases {
+		ethernet0 = &emac;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr {
+			label = "nanopi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		status {
+			label = "nanopi:blue:status";
+			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	reg_gmac_3v3: gmac-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "gmac-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		enable-active-high;
+		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_vcc3v3: vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usb0_vbus: usb0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb0-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
+		status = "okay";
+	};
+
+	 wifi_pwrseq: wifi_pwrseq {
+        compatible = "mmc-pwrseq-simple";
+        reset-gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
+        post-power-on-delay-ms = <50>;
+    };
+
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ehci2 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&mdio {
+	ext_rgmii_phy: ethernet-phy@7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+        pinctrl-names = "default";
+        pinctrl-0 = <&mmc1_pins_a>;
+        vmmc-supply = <&reg_vcc3v3>;
+        vqmmc-supply = <&reg_vcc3v3>;
+        mmc-pwrseq = <&wifi_pwrseq>;
+        bus-width = <4>;
+        non-removable;
+        status = "okay";
+
+        brcmf: brcmf@1 {
+                reg = <1>;
+                compatible = "brcm,bcm4329-fmac";
+                interrupt-parent = <&r_pio>;
+                interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 / EINT7 */
+                interrupt-names = "host-wake";
+                pinctrl-names = "default";
+                pinctrl-0 = <&wifi_wake>;
+        };
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&de {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&ohci2 {
+	status = "okay";
+};
+
+&ohci3 {
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&r_pio {
+	wifi_wake: wifi_wake@0 {
+		pins = "PL7";
+		function = "irq";
+		bias-pull-up;
+	};
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&r_i2c {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/* USB Type-A port's VBUS is always on */
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+	usb0_vbus-supply = <&reg_usb0_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
new file mode 100644
index 000000000000..d5156e1228b0
--- /dev/null
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ * Copyright (C) 2017 Armbian
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "FriendlyARM NanoPi NEO Plus 2";
+	compatible = "friendlyarm,nanopi-neo2", "allwinner,sun50i-h5";
+
+	aliases {
+		ethernet0 = &emac;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr {
+			label = "nanopi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		status {
+			label = "nanopi:blue:status";
+			gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	reg_gmac_3v3: gmac-3v3 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		regulator-name = "gmac-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		enable-active-high;
+		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_vcc3v3: vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	reg_usb0_vbus: usb0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb0-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
+		status = "okay";
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+        compatible = "mmc-pwrseq-simple";
+        pinctrl-names = "default";
+        pinctrl-0 = <&wifi_en_npi>;
+        reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */
+        post-power-on-delay-ms = <200>;
+    };
+
+	rfkill_bt {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_pwr_pin>;
+		reset-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+		clocks = <&osc32k>;
+		clock-frequency = <32768>;
+		rfkill-name = "sunxi-bt";
+		rfkill-type = "bluetooth";
+	};
+
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci3 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&mmc1_pins_a>;
+    vmmc-supply = <&reg_vcc3v3>;
+    vqmmc-supply = <&reg_vcc3v3>;
+    mmc-pwrseq = <&wifi_pwrseq>;
+    bus-width = <4>;
+    non-removable;
+    status = "okay";
+
+    brcmf: bcrmf@1 {
+        reg = <1>;
+        compatible = "brcm,bcm4329-fmac";
+    };
+};
+
+&mmc2 {
+    pinctrl-names = "default";
+    pinctrl-0 = <&mmc2_8bit_pins>;
+    vmmc-supply = <&reg_vcc3v3>;
+    bus-width = <8>;
+    non-removable;
+    cap-mmc-hw-reset;
+    boot_device = <0>;
+    status = "okay";
+};
+
+&mmc2_8bit_pins {
+    /* Increase drive strength for DDR modes */
+    drive-strength = <40>;
+    /* eMMC is missing pull-ups */
+    bias-pull-up;
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci3 {
+	status = "okay";
+};
+
+&pio {
+	gmac_power_pin_nanopi: gmac_power_pin@0 {
+		pins = "PD6";
+		function = "gpio_out";
+	};
+	bt_pwr_pin: bt_pwr_pin@0 {
+		pins = "PG13";
+		function = "gpio_out";
+	};
+};
+
+&r_pio {
+    wifi_en_npi: wifi_en_pin {
+        pins = "PL7";
+        function = "gpio_out";
+    };
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbphy {
+	/* USB Type-A port's VBUS is always on */
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+	usb0_vbus-supply = <&reg_usb0_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
index 1c2387bd5df6..6eb8092d8e57 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts
@@ -50,6 +50,7 @@
 	compatible = "friendlyarm,nanopi-neo2", "allwinner,sun50i-h5";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -108,6 +109,22 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@7 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <7>;
+	};
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
index 4f77c8470f6c..f5210e4026e2 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
@@ -59,6 +59,7 @@
 	};
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
 	};
 
@@ -120,6 +121,14 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&vdd_cpu>;
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -136,12 +145,40 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -167,6 +204,28 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&r_i2c {
+	status = "okay";
+
+	vdd_cpu: regulator@65 {
+		compatible = "silergy,sy8106a";
+		reg = <0x65>;
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1400000>;
+		regulator-ramp-delay = <200>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
index 6be06873e5af..ad320a2eddd8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
@@ -54,7 +54,9 @@
 	compatible = "xunlong,orangepi-prime", "allwinner,sun50i-h5";
 
 	aliases {
+		ethernet0 = &emac;
 		serial0 = &uart0;
+		ethernet1 = &rtl8723cs;
 	};
 
 	chosen {
@@ -127,6 +129,14 @@
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&vdd_cpu>;
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -143,12 +153,40 @@
 	status = "okay";
 };
 
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&i2s2 {
+	status = "okay";
+};
+
 &ir {
 	pinctrl-names = "default";
 	pinctrl-0 = <&ir_pins_a>;
 	status = "okay";
 };
 
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mixer0 {
+	status = "okay";
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
@@ -166,6 +204,10 @@
 	bus-width = <4>;
 	non-removable;
 	status = "okay";
+
+	rtl8723cs: sdio_wifi@1 {
+		reg = <1>;
+	};
 };
 
 &ohci0 {
@@ -184,6 +226,28 @@
 	status = "okay";
 };
 
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&r_i2c {
+	status = "okay";
+
+	vdd_cpu: regulator@65 {
+		compatible = "silergy,sy8106a";
+		reg = <0x65>;
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1400000>;
+		regulator-ramp-delay = <200>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
new file mode 100644
index 000000000000..c3333f61e900
--- /dev/null
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun50i-h5.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "Xunlong Orange Pi Zero Plus";
+	compatible = "xunlong,orangepi-pc2", "allwinner,sun50i-h5";
+
+	reg_vcc3v3: vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	aliases {
+		ethernet0 = &emac;
+		ethernet1 = &rtl8189ftv;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		pwr {
+			label = "orangepi:green:pwr";
+			gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		status {
+			label = "orangepi:red:status";
+			gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	reg_gmac_3v3: gmac-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "gmac-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		enable-active-high;
+		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_usb0_vbus: usb0-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb0-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
+		status = "okay";
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rgmii_pins>;
+	phy-supply = <&reg_gmac_3v3>;
+	phy-handle = <&ext_rgmii_phy>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&external_mdio {
+	ext_rgmii_phy: ethernet-phy@1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <1>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+
+	/*
+	 * Explicitly define the sdio device, so that we can add an ethernet
+	 * alias for it (which e.g. makes u-boot set a mac-address).
+	 */
+	rtl8189ftv: sdio_wifi@1 {
+		reg = <1>;
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/* USB Type-A ports' VBUS is always on */
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
index b6b7a561df8c..d71a8b8b94b0 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
@@ -43,15 +43,17 @@
 /dts-v1/;
 
 #include "sun50i-h5.dtsi"
-
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
-	model = "OrangePi Zero Plus2";
+	model = "Xunlong Orange Pi Zero Plus2";
 	compatible = "xunlong,orangepi-zero-plus2", "allwinner,sun50i-h5";
 
 	aliases {
 		serial0 = &uart0;
+		ethernet1 = &brcmf;
 	};
 
 	chosen {
@@ -64,6 +66,30 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 	};
+
+    wifi_pwrseq: wifi_pwrseq {
+        compatible = "mmc-pwrseq-simple";
+        reset-gpios = <&pio 0 9 GPIO_ACTIVE_LOW>; /* PA9 */
+        post-power-on-delay-ms = <50>;
+    };
+
+	reg_sy8113b: gpio-regulator {
+		compatible = "regulator-gpio";
+		regulator-name = "vdd-cpux";
+		regulator-type = "voltage";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-ramp-delay = <50>; /* 4ms */
+
+		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */
+		enable-active-high;
+		gpios-states = <0x1>;
+		states = <1100000 0x0
+			  1300000 0x1>;
+	};
+
 };
 
 &mmc0 {
@@ -71,10 +97,31 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>;
+	cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
 
+&mmc1 {
+        pinctrl-names = "default";
+        pinctrl-0 = <&mmc1_pins_a>;
+        vmmc-supply = <&reg_vcc3v3>;
+        vqmmc-supply = <&reg_vcc3v3>;
+        mmc-pwrseq = <&wifi_pwrseq>;
+        bus-width = <4>;
+        non-removable;
+        status = "okay";
+
+        brcmf: brcmf@1 {
+                reg = <1>;
+                compatible = "brcm,bcm4329-fmac";
+                interrupt-parent = <&r_pio>;
+                interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 / EINT7 */
+                interrupt-names = "host-wake";
+                pinctrl-names = "default";
+                pinctrl-0 = <&wifi_wake>;
+        };
+};
+
 &mmc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc2_8bit_pins>;
@@ -85,8 +132,80 @@
 	status = "okay";
 };
 
+&cpu0 {
+	cpu-supply = <&reg_sy8113b>;
+};
+
+&de {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&spi0 {
+	/* Disable SPI NOR by default: it optional on Orange Pi Zero boards */
+	status = "disabled";
+
+	flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+		reg = <0>;
+		spi-max-frequency = <40000000>;
+	};
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&mixer0 {
+	status = "okay";
+};
+
+&r_pio {
+	wifi_wake: wifi_wake@0 {
+		pins = "PL7";
+		function = "irq";
+		bias-pull-up;
+	};
+};
+
+&sound_hdmi {
+	status = "okay";
+};
+
+&tcon0 {
+	status = "okay";
+};
+
+&r_i2c {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pins_a>;
 	status = "okay";
 };
+
+&usb_otg {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbphy {
+	/*
+	 * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only
+	 * power up the board; when it's used as OTG port, this VBUS is
+	 * always off even if the board is powered via GPIO pins.
+	 */
+	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+	status = "okay";
+};
\ No newline at end of file
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
index d9a720bff05d..25bf865e3791 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -41,17 +41,83 @@
  */
 
 #include <arm/sunxi-h3-h5.dtsi>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
+	cpu_opp_table: opp_table {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp@408000000 {
+			opp-hz = /bits/ 64 <408000000>;
+			opp-microvolt = <1000000 1000000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@648000000 {
+			opp-hz = /bits/ 64 <648000000>;
+			opp-microvolt = <1040000 1040000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@816000000 {
+			opp-hz = /bits/ 64 <816000000>;
+			opp-microvolt = <1080000 1080000 1300000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@912000000 {
+		       opp-hz = /bits/ 64 <912000000>;
+		       opp-microvolt = <1120000 1120000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@960000000 {
+		       opp-hz = /bits/ 64 <960000000>;
+		       opp-microvolt = <1160000 1160000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1008000000 {
+		       opp-hz = /bits/ 64 <1008000000>;
+		       opp-microvolt = <1200000 1200000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1056000000 {
+		       opp-hz = /bits/ 64 <1056000000>;
+		       opp-microvolt = <1240000 1240000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1104000000 {
+		       opp-hz = /bits/ 64 <1104000000>;
+		       opp-microvolt = <1260000 1260000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp@1152000000 {
+		       opp-hz = /bits/ 64 <1152000000>;
+		       opp-microvolt = <1300000 1300000 1300000>;
+		       clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		cpu@0 {
+		cpu0: cpu@0 {
 			compatible = "arm,cortex-a53", "arm,armv8";
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&ccu CLK_CPUX>;
+			clock-names = "cpu";
+			clock-latency = <244144>; /* 8 32k periods */
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
+			cpu-supply = <&reg_cpu_fallback>;
+			#cooling-cells = <2>;
 		};
 
 		cpu@1 {
@@ -59,6 +125,7 @@
 			device_type = "cpu";
 			reg = <1>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu@2 {
@@ -66,6 +133,7 @@
 			device_type = "cpu";
 			reg = <2>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
 		};
 
 		cpu@3 {
@@ -73,6 +141,24 @@
 			device_type = "cpu";
 			reg = <3>;
 			enable-method = "psci";
+			operating-points-v2 = <&cpu_opp_table>;
+		};
+	};
+
+	iio-hwmon {
+		compatible = "iio-hwmon";
+		io-channels = <&ths>;
+	};
+
+	soc {
+		ths: thermal-sensor@1c25000 {
+			compatible = "allwinner,sun50i-h5-ths";
+			reg = <0x01c25000 0x100>;
+			clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_THS>;
+			#thermal-sensor-cells = <0>;
+			#io-channel-cells = <0>;
 		};
 	};
 
@@ -81,6 +167,87 @@
 		method = "smc";
 	};
 
+	thermal-zones {
+		cpu-thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&ths>;
+
+			trips {
+				cpu_warm: cpu_warm {
+					temperature = <65000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot_pre: cpu_hot_pre {
+					temperature = <70000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_hot: cpu_hot {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot_pre: cpu_very_hot_pre {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_very_hot: cpu_very_hot {
+					temperature = <90000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				cpu_warm_limit_cpu {
+					trip = <&cpu_warm>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT 2>;
+				};
+
+				cpu_hot_pre_limit_cpu {
+					trip = <&cpu_hot_pre>;
+					cooling-device = <&cpu0 2 3>;
+				};
+
+				cpu_hot_limit_cpu {
+					trip = <&cpu_hot>;
+					cooling-device = <&cpu0 3 4>;
+				};
+
+				cpu_very_hot_pre_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 5 6>;
+				};
+
+				cpu_very_hot_limit_cpu {
+					trip = <&cpu_very_hot>;
+					cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	reg_cpu_fallback: reg_cpu_fallback  {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd-cpux-dummy";
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 13
@@ -98,6 +265,14 @@
 	compatible = "allwinner,sun50i-h5-ccu";
 };
 
+&display_clocks {
+	compatible = "allwinner,sun50i-h5-de2-clk";
+};
+
+&mixer1 {
+	resets = <&display_clocks RST_MIXER1>;
+};
+
 &mmc0 {
 	compatible = "allwinner,sun50i-h5-mmc",
 		     "allwinner,sun50i-a64-mmc";
diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile
index 3df2db7f8878..a4f01381fc46 100644
--- a/arch/arm64/boot/dts/broadcom/Makefile
+++ b/arch/arm64/boot/dts/broadcom/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-b.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-b-plus.dtb
 
 dts-dirs	+= northstar2
 dts-dirs	+= stingray
diff --git a/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b-plus.dts b/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b-plus.dts
new file mode 100644
index 000000000000..46ad2023cccf
--- /dev/null
+++ b/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b-plus.dts
@@ -0,0 +1,2 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "arm/bcm2837-rpi-3-b-plus.dts"
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
index 7e3cd0bd597d..e1c9104a336e 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -519,7 +519,7 @@ static struct ccu_div tcon1_clk = {
 		.hw.init	= CLK_HW_INIT_PARENTS("tcon1",
 						      tcon1_parents,
 						      &ccu_div_ops,
-						      CLK_SET_RATE_PARENT),
+						      0),
 	},
 };
 
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 5cdaf52669e4..38b029b7bb5a 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -17,6 +17,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
+#include <linux/soc/sunxi/sunxi_sram.h>
 
 #include "ccu_common.h"
 #include "ccu_div.h"
@@ -46,6 +47,13 @@ static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
 static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
 		   CLK_SET_RATE_PARENT);
 
+static SUNXI_CCU_M(mixer0_div_a83_clk, "mixer0-div", "pll-de", 0x0c, 0, 4,
+		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4,
+		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4,
+		   CLK_SET_RATE_PARENT);
+
 static struct ccu_common *sun8i_a83t_de2_clks[] = {
 	&mixer0_clk.common,
 	&mixer1_clk.common,
@@ -55,6 +63,20 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = {
 	&bus_mixer1_clk.common,
 	&bus_wb_clk.common,
 
+	&mixer0_div_a83_clk.common,
+	&mixer1_div_a83_clk.common,
+	&wb_div_a83_clk.common,
+};
+
+static struct ccu_common *sun8i_h3_de2_clks[] = {
+	&mixer0_clk.common,
+	&mixer1_clk.common,
+	&wb_clk.common,
+
+	&bus_mixer0_clk.common,
+	&bus_mixer1_clk.common,
+	&bus_wb_clk.common,
+
 	&mixer0_div_clk.common,
 	&mixer1_div_clk.common,
 	&wb_div_clk.common,
@@ -72,6 +94,23 @@ static struct ccu_common *sun8i_v3s_de2_clks[] = {
 };
 
 static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = {
+	.hws	= {
+		[CLK_MIXER0]		= &mixer0_clk.common.hw,
+		[CLK_MIXER1]		= &mixer1_clk.common.hw,
+		[CLK_WB]		= &wb_clk.common.hw,
+
+		[CLK_BUS_MIXER0]	= &bus_mixer0_clk.common.hw,
+		[CLK_BUS_MIXER1]	= &bus_mixer1_clk.common.hw,
+		[CLK_BUS_WB]		= &bus_wb_clk.common.hw,
+
+		[CLK_MIXER0_DIV]	= &mixer0_div_a83_clk.common.hw,
+		[CLK_MIXER1_DIV]	= &mixer1_div_a83_clk.common.hw,
+		[CLK_WB_DIV]		= &wb_div_a83_clk.common.hw,
+	},
+	.num	= CLK_NUMBER,
+};
+
+static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = {
 	.hws	= {
 		[CLK_MIXER0]		= &mixer0_clk.common.hw,
 		[CLK_MIXER1]		= &mixer1_clk.common.hw,
@@ -128,11 +167,21 @@ static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
 	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
 };
 
+static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = {
+	.ccu_clks	= sun8i_h3_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
+
+	.hw_clks	= &sun8i_h3_de2_hw_clks,
+
+	.resets		= sun8i_a83t_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
+};
+
 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
-	.ccu_clks	= sun8i_a83t_de2_clks,
-	.num_ccu_clks	= ARRAY_SIZE(sun8i_a83t_de2_clks),
+	.ccu_clks	= sun8i_h3_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
 
-	.hw_clks	= &sun8i_a83t_de2_hw_clks,
+	.hw_clks	= &sun8i_h3_de2_hw_clks,
 
 	.resets		= sun50i_a64_de2_resets,
 	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
@@ -148,6 +197,11 @@ static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = {
 	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
 };
 
+static bool sunxi_de2_clk_has_sram(const struct device_node *node)
+{
+	return of_device_is_compatible(node, "allwinner,sun50i-a64-de2-clk");
+}
+
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -191,11 +245,20 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (sunxi_de2_clk_has_sram(pdev->dev.of_node)) {
+		ret = sunxi_sram_claim(&pdev->dev);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Error couldn't map SRAM to device\n");
+			return ret;
+		}
+	}
+
 	/* The clocks need to be enabled for us to access the registers */
 	ret = clk_prepare_enable(bus_clk);
 	if (ret) {
 		dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
-		return ret;
+		goto err_release_sram;
 	}
 
 	ret = clk_prepare_enable(mod_clk);
@@ -224,6 +287,10 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
 	clk_disable_unprepare(mod_clk);
 err_disable_bus_clk:
 	clk_disable_unprepare(bus_clk);
+err_release_sram:
+	if (sunxi_de2_clk_has_sram(pdev->dev.of_node))
+		sunxi_sram_release(&pdev->dev);
+
 	return ret;
 }
 
@@ -232,21 +299,22 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
 		.compatible = "allwinner,sun8i-a83t-de2-clk",
 		.data = &sun8i_a83t_de2_clk_desc,
 	},
+	{
+		.compatible = "allwinner,sun8i-h3-de2-clk",
+		.data = &sun8i_h3_de2_clk_desc,
+	},
 	{
 		.compatible = "allwinner,sun8i-v3s-de2-clk",
 		.data = &sun8i_v3s_de2_clk_desc,
 	},
+	{
+		.compatible = "allwinner,sun50i-a64-de2-clk",
+		.data = &sun50i_a64_de2_clk_desc,
+	},
 	{
 		.compatible = "allwinner,sun50i-h5-de2-clk",
 		.data = &sun50i_a64_de2_clk_desc,
 	},
-	/*
-	 * The Allwinner A64 SoC needs some bit to be poke in syscon to make
-	 * DE2 really working.
-	 * So there's currently no A64 compatible here.
-	 * H5 shares the same reset line with A64, so here H5 is using the
-	 * clock description of A64.
-	 */
 	{ }
 };
 
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index aa44602896fa..0cbf70514a3a 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -37,7 +37,7 @@ static SUNXI_CCU_NKMP_WITH_GATE_LOCK(pll_cpux_clk, "pll-cpux",
 				     16, 2,	/* P */
 				     BIT(31),	/* gate */
 				     BIT(28),	/* lock */
-				     0);
+				     CLK_SET_RATE_UNGATE);
 
 /*
  * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from
@@ -55,7 +55,7 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
 				   0, 5,	/* M */
 				   BIT(31),	/* gate */
 				   BIT(28),	/* lock */
-				   0);
+				   CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video",
 					"osc24M", 0x0010,
@@ -67,7 +67,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video",
 					297000000,	/* frac rate 1 */
 					BIT(31),	/* gate */
 					BIT(28),	/* lock */
-					0);
+					CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
 					"osc24M", 0x0018,
@@ -79,7 +79,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
 					297000000,	/* frac rate 1 */
 					BIT(31),	/* gate */
 					BIT(28),	/* lock */
-					0);
+					CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr",
 				    "osc24M", 0x020,
@@ -88,7 +88,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr",
 				    0, 2,	/* M */
 				    BIT(31),	/* gate */
 				    BIT(28),	/* lock */
-				    0);
+				    CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph0_clk, "pll-periph0",
 					   "osc24M", 0x028,
@@ -97,7 +97,7 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph0_clk, "pll-periph0",
 					   BIT(31),	/* gate */
 					   BIT(28),	/* lock */
 					   2,		/* post-div */
-					   0);
+					   CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu",
 					"osc24M", 0x0038,
@@ -109,7 +109,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu",
 					297000000,	/* frac rate 1 */
 					BIT(31),	/* gate */
 					BIT(28),	/* lock */
-					0);
+					CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1",
 					   "osc24M", 0x044,
@@ -118,7 +118,7 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1",
 					   BIT(31),	/* gate */
 					   BIT(28),	/* lock */
 					   2,		/* post-div */
-					   0);
+					   CLK_SET_RATE_UNGATE);
 
 static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de",
 					"osc24M", 0x0048,
@@ -130,7 +130,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de",
 					297000000,	/* frac rate 1 */
 					BIT(31),	/* gate */
 					BIT(28),	/* lock */
-					0);
+					CLK_SET_RATE_UNGATE);
 
 static const char * const cpux_parents[] = { "osc32k", "osc24M",
 					     "pll-cpux" , "pll-cpux" };
@@ -440,7 +440,7 @@ static SUNXI_CCU_GATE(dram_ts_clk,	"dram-ts",	"dram",
 
 static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" };
 static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents,
-				 0x104, 0, 4, 24, 3, BIT(31), 0);
+				 0x104, 0, 4, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
 
 static const char * const tcon_parents[] = { "pll-video" };
 static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents,
@@ -475,7 +475,7 @@ static SUNXI_CCU_GATE(avs_clk,		"avs",		"osc24M",
 
 static const char * const hdmi_parents[] = { "pll-video" };
 static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
-				 0x150, 0, 4, 24, 2, BIT(31), 0);
+				 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT);
 
 static SUNXI_CCU_GATE(hdmi_ddc_clk,	"hdmi-ddc",	"osc24M",
 		      0x154, BIT(31), 0);
@@ -485,7 +485,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents,
 				 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL);
 
 static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu",
-			     0x1a0, 0, 3, BIT(31), 0);
+			     0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun8i_h3_ccu_clks[] = {
 	&pll_cpux_clk.common,
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
index 1b4baea37d81..add3a7c18212 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
@@ -35,9 +35,8 @@
 #define CLK_PLL_PERIPH0_2X	10
 #define CLK_PLL_GPU		11
 #define CLK_PLL_PERIPH1		12
-#define CLK_PLL_DE		13
 
-/* The CPUX clock is exported */
+/* The PLL_DE and CPUX clocks is exported */
 
 #define CLK_AXI			15
 #define CLK_AHB1		16
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index bcd496edc70f..0cd13f17fc11 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -42,12 +42,18 @@
 
 #define DMA_STAT		0x30
 
+/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */
+#define DMA_MAX_CHANNELS	(DMA_IRQ_CHAN_NR * 0x10 / 4)
+
 /*
  * sun8i specific registers
  */
 #define SUN8I_DMA_GATE		0x20
 #define SUN8I_DMA_GATE_ENABLE	0x4
 
+#define SUNXI_H3_SECURE_REG		0x20
+#define SUNXI_H3_DMA_GATE		0x28
+#define SUNXI_H3_DMA_GATE_ENABLE	0x4
 /*
  * Channels specific registers
  */
@@ -62,16 +68,19 @@
 #define DMA_CHAN_LLI_ADDR	0x08
 
 #define DMA_CHAN_CUR_CFG	0x0c
-#define DMA_CHAN_CFG_SRC_DRQ(x)		((x) & 0x1f)
+#define DMA_CHAN_MAX_DRQ		0x1f
+#define DMA_CHAN_CFG_SRC_DRQ(x)		((x) & DMA_CHAN_MAX_DRQ)
 #define DMA_CHAN_CFG_SRC_IO_MODE	BIT(5)
 #define DMA_CHAN_CFG_SRC_LINEAR_MODE	(0 << 5)
-#define DMA_CHAN_CFG_SRC_BURST(x)	(((x) & 0x3) << 7)
+#define DMA_CHAN_CFG_SRC_BURST_A31(x)	(((x) & 0x3) << 7)
+#define DMA_CHAN_CFG_SRC_BURST_H3(x)	(((x) & 0x3) << 6)
 #define DMA_CHAN_CFG_SRC_WIDTH(x)	(((x) & 0x3) << 9)
 
 #define DMA_CHAN_CFG_DST_DRQ(x)		(DMA_CHAN_CFG_SRC_DRQ(x) << 16)
 #define DMA_CHAN_CFG_DST_IO_MODE	(DMA_CHAN_CFG_SRC_IO_MODE << 16)
 #define DMA_CHAN_CFG_DST_LINEAR_MODE	(DMA_CHAN_CFG_SRC_LINEAR_MODE << 16)
-#define DMA_CHAN_CFG_DST_BURST(x)	(DMA_CHAN_CFG_SRC_BURST(x) << 16)
+#define DMA_CHAN_CFG_DST_BURST_A31(x)	(DMA_CHAN_CFG_SRC_BURST_A31(x) << 16)
+#define DMA_CHAN_CFG_DST_BURST_H3(x)	(DMA_CHAN_CFG_SRC_BURST_H3(x) << 16)
 #define DMA_CHAN_CFG_DST_WIDTH(x)	(DMA_CHAN_CFG_SRC_WIDTH(x) << 16)
 
 #define DMA_CHAN_CUR_SRC	0x10
@@ -90,6 +99,9 @@
 #define NORMAL_WAIT	8
 #define DRQ_SDRAM	1
 
+/* forward declaration */
+struct sun6i_dma_dev;
+
 /*
  * Hardware channels / ports representation
  *
@@ -111,7 +123,12 @@ struct sun6i_dma_config {
 	 * however these SoCs really have and need this bit, as seen in the
 	 * BSP kernel source code.
 	 */
-	bool gate_needed;
+	void (*clock_autogate_enable)(struct sun6i_dma_dev *);
+	void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
+	u32 src_burst_lengths;
+	u32 dst_burst_lengths;
+	u32 src_addr_widths;
+	u32 dst_addr_widths;
 };
 
 /*
@@ -175,6 +192,9 @@ struct sun6i_dma_dev {
 	struct sun6i_pchan	*pchans;
 	struct sun6i_vchan	*vchans;
 	const struct sun6i_dma_config *cfg;
+	u32			num_pchans;
+	u32			num_vchans;
+	u32			max_request;
 };
 
 static struct device *chan2dev(struct dma_chan *chan)
@@ -251,8 +271,12 @@ static inline s8 convert_burst(u32 maxburst)
 	switch (maxburst) {
 	case 1:
 		return 0;
+	case 4:
+		return 1;
 	case 8:
 		return 2;
+	case 16:
+		return 3;
 	default:
 		return -EINVAL;
 	}
@@ -260,11 +284,29 @@ static inline s8 convert_burst(u32 maxburst)
 
 static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
 {
-	if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) ||
-	    (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES))
-		return -EINVAL;
+	return ilog2(addr_width);
+}
+
+static void sun6i_enable_clock_autogate_a23(struct sun6i_dma_dev *sdev)
+{
+	writel(SUN8I_DMA_GATE_ENABLE, sdev->base + SUN8I_DMA_GATE);
+}
+
+static void sun6i_enable_clock_autogate_h3(struct sun6i_dma_dev *sdev)
+{
+	writel(SUNXI_H3_DMA_GATE_ENABLE, sdev->base + SUNXI_H3_DMA_GATE);
+}
 
-	return addr_width >> 1;
+static void sun6i_set_burst_length_a31(u32 *p_cfg, s8 src_burst, s8 dst_burst)
+{
+	*p_cfg |= DMA_CHAN_CFG_SRC_BURST_A31(src_burst) |
+		  DMA_CHAN_CFG_DST_BURST_A31(dst_burst);
+}
+
+static void sun6i_set_burst_length_h3(u32 *p_cfg, s8 src_burst, s8 dst_burst)
+{
+	*p_cfg |= DMA_CHAN_CFG_SRC_BURST_H3(src_burst) |
+		  DMA_CHAN_CFG_DST_BURST_H3(dst_burst);
 }
 
 static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
@@ -399,7 +441,6 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
 static void sun6i_dma_tasklet(unsigned long data)
 {
 	struct sun6i_dma_dev *sdev = (struct sun6i_dma_dev *)data;
-	const struct sun6i_dma_config *cfg = sdev->cfg;
 	struct sun6i_vchan *vchan;
 	struct sun6i_pchan *pchan;
 	unsigned int pchan_alloc = 0;
@@ -427,7 +468,7 @@ static void sun6i_dma_tasklet(unsigned long data)
 	}
 
 	spin_lock_irq(&sdev->lock);
-	for (pchan_idx = 0; pchan_idx < cfg->nr_max_channels; pchan_idx++) {
+	for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) {
 		pchan = &sdev->pchans[pchan_idx];
 
 		if (pchan->vchan || list_empty(&sdev->pending))
@@ -448,7 +489,7 @@ static void sun6i_dma_tasklet(unsigned long data)
 	}
 	spin_unlock_irq(&sdev->lock);
 
-	for (pchan_idx = 0; pchan_idx < cfg->nr_max_channels; pchan_idx++) {
+	for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) {
 		if (!(pchan_alloc & BIT(pchan_idx)))
 			continue;
 
@@ -470,7 +511,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
 	int i, j, ret = IRQ_NONE;
 	u32 status;
 
-	for (i = 0; i < sdev->cfg->nr_max_channels / DMA_IRQ_CHAN_NR; i++) {
+	for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
 		status = readl(sdev->base + DMA_IRQ_STAT(i));
 		if (!status)
 			continue;
@@ -510,47 +551,49 @@ static int set_config(struct sun6i_dma_dev *sdev,
 			enum dma_transfer_direction direction,
 			u32 *p_cfg)
 {
+	enum dma_slave_buswidth src_addr_width, dst_addr_width;
+	u32 src_maxburst, dst_maxburst;
 	s8 src_width, dst_width, src_burst, dst_burst;
 
+	src_addr_width = sconfig->src_addr_width;
+	dst_addr_width = sconfig->dst_addr_width;
+	src_maxburst = sconfig->src_maxburst;
+	dst_maxburst = sconfig->dst_maxburst;
+
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
-		src_burst = convert_burst(sconfig->src_maxburst ?
-					sconfig->src_maxburst : 8);
-		src_width = convert_buswidth(sconfig->src_addr_width !=
-						DMA_SLAVE_BUSWIDTH_UNDEFINED ?
-				sconfig->src_addr_width :
-				DMA_SLAVE_BUSWIDTH_4_BYTES);
-		dst_burst = convert_burst(sconfig->dst_maxburst);
-		dst_width = convert_buswidth(sconfig->dst_addr_width);
+		if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		src_maxburst = src_maxburst ? src_maxburst : 8;
 		break;
 	case DMA_DEV_TO_MEM:
-		src_burst = convert_burst(sconfig->src_maxburst);
-		src_width = convert_buswidth(sconfig->src_addr_width);
-		dst_burst = convert_burst(sconfig->dst_maxburst ?
-					sconfig->dst_maxburst : 8);
-		dst_width = convert_buswidth(sconfig->dst_addr_width !=
-						DMA_SLAVE_BUSWIDTH_UNDEFINED ?
-				sconfig->dst_addr_width :
-				DMA_SLAVE_BUSWIDTH_4_BYTES);
+		if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		dst_maxburst = dst_maxburst ? dst_maxburst : 8;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (src_burst < 0)
-		return src_burst;
-	if (src_width < 0)
-		return src_width;
-	if (dst_burst < 0)
-		return dst_burst;
-	if (dst_width < 0)
-		return dst_width;
-
-	*p_cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
-		DMA_CHAN_CFG_SRC_WIDTH(src_width) |
-		DMA_CHAN_CFG_DST_BURST(dst_burst) |
+	if (!(BIT(src_addr_width) & sdev->slave.src_addr_widths))
+		return -EINVAL;
+	if (!(BIT(dst_addr_width) & sdev->slave.dst_addr_widths))
+		return -EINVAL;
+	if (!(BIT(src_maxburst) & sdev->cfg->src_burst_lengths))
+		return -EINVAL;
+	if (!(BIT(dst_maxburst) & sdev->cfg->dst_burst_lengths))
+		return -EINVAL;
+
+	src_width = convert_buswidth(src_addr_width);
+	dst_width = convert_buswidth(dst_addr_width);
+	dst_burst = convert_burst(dst_maxburst);
+	src_burst = convert_burst(src_maxburst);
+
+	*p_cfg = DMA_CHAN_CFG_SRC_WIDTH(src_width) |
 		DMA_CHAN_CFG_DST_WIDTH(dst_width);
 
+	sdev->cfg->set_burst_length(p_cfg, src_burst, dst_burst);
+
 	return 0;
 }
 
@@ -593,11 +636,11 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 		DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
 		DMA_CHAN_CFG_DST_LINEAR_MODE |
 		DMA_CHAN_CFG_SRC_LINEAR_MODE |
-		DMA_CHAN_CFG_SRC_BURST(burst) |
 		DMA_CHAN_CFG_SRC_WIDTH(width) |
-		DMA_CHAN_CFG_DST_BURST(burst) |
 		DMA_CHAN_CFG_DST_WIDTH(width);
 
+	sdev->cfg->set_burst_length(&v_lli->cfg, burst, burst);
+
 	sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
 
 	sun6i_dma_dump_lli(vchan, v_lli);
@@ -948,7 +991,7 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
 	struct dma_chan *chan;
 	u8 port = dma_spec->args[0];
 
-	if (port > sdev->cfg->nr_max_requests)
+	if (port > sdev->max_request)
 		return NULL;
 
 	chan = dma_get_any_slave_channel(&sdev->slave);
@@ -981,7 +1024,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
 {
 	int i;
 
-	for (i = 0; i < sdev->cfg->nr_max_vchans; i++) {
+	for (i = 0; i < sdev->num_vchans; i++) {
 		struct sun6i_vchan *vchan = &sdev->vchans[i];
 
 		list_del(&vchan->vc.chan.device_node);
@@ -1009,6 +1052,15 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
 	.nr_max_channels = 16,
 	.nr_max_requests = 30,
 	.nr_max_vchans   = 53,
+	.set_burst_length = sun6i_set_burst_length_a31,
+	.src_burst_lengths = BIT(1) | BIT(8),
+	.dst_burst_lengths = BIT(1) | BIT(8),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
 };
 
 /*
@@ -1020,24 +1072,76 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
 	.nr_max_channels = 8,
 	.nr_max_requests = 24,
 	.nr_max_vchans   = 37,
-	.gate_needed	 = true,
+	.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
+	.set_burst_length = sun6i_set_burst_length_a31,
+	.src_burst_lengths = BIT(1) | BIT(8),
+	.dst_burst_lengths = BIT(1) | BIT(8),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
 };
 
 static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
 	.nr_max_channels = 8,
 	.nr_max_requests = 28,
 	.nr_max_vchans   = 39,
+	.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
+	.set_burst_length = sun6i_set_burst_length_a31,
+	.src_burst_lengths = BIT(1) | BIT(8),
+	.dst_burst_lengths = BIT(1) | BIT(8),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
 };
 
 /*
  * The H3 has 12 physical channels, a maximum DRQ port id of 27,
  * and a total of 34 usable source and destination endpoints.
+ * It also supports additional burst lengths and bus widths,
+ * and the burst length fields have different offsets.
  */
 
 static struct sun6i_dma_config sun8i_h3_dma_cfg = {
 	.nr_max_channels = 12,
 	.nr_max_requests = 27,
 	.nr_max_vchans   = 34,
+	.clock_autogate_enable = sun6i_enable_clock_autogate_h3,
+	.set_burst_length = sun6i_set_burst_length_h3,
+	.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+	.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+};
+
+/*
+ * The A64 binding uses the number of dma channels from the
+ * device tree node.
+ */
+static struct sun6i_dma_config sun50i_a64_dma_cfg = {
+	.clock_autogate_enable = sun6i_enable_clock_autogate_h3,
+	.set_burst_length = sun6i_set_burst_length_h3,
+	.src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+	.dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
 };
 
 /*
@@ -1049,7 +1153,16 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
 	.nr_max_channels = 8,
 	.nr_max_requests = 23,
 	.nr_max_vchans   = 24,
-	.gate_needed	 = true,
+	.clock_autogate_enable = sun6i_enable_clock_autogate_a23,
+	.set_burst_length = sun6i_set_burst_length_a31,
+	.src_burst_lengths = BIT(1) | BIT(8),
+	.dst_burst_lengths = BIT(1) | BIT(8),
+	.src_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
+	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
 };
 
 static const struct of_device_id sun6i_dma_match[] = {
@@ -1058,13 +1171,14 @@ static const struct of_device_id sun6i_dma_match[] = {
 	{ .compatible = "allwinner,sun8i-a83t-dma", .data = &sun8i_a83t_dma_cfg },
 	{ .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
 	{ .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg },
+	{ .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun6i_dma_match);
 
 static int sun6i_dma_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *device;
+	struct device_node *np = pdev->dev.of_node;
 	struct sun6i_dma_dev *sdc;
 	struct resource *res;
 	int ret, i;
@@ -1073,10 +1187,9 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 	if (!sdc)
 		return -ENOMEM;
 
-	device = of_match_device(sun6i_dma_match, &pdev->dev);
-	if (!device)
+	sdc->cfg = of_device_get_match_data(&pdev->dev);
+	if (!sdc->cfg)
 		return -ENODEV;
-	sdc->cfg = device->data;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sdc->base = devm_ioremap_resource(&pdev->dev, res);
@@ -1129,37 +1242,57 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 	sdc->slave.device_pause			= sun6i_dma_pause;
 	sdc->slave.device_resume		= sun6i_dma_resume;
 	sdc->slave.device_terminate_all		= sun6i_dma_terminate_all;
-	sdc->slave.src_addr_widths		= BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
-						  BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
-						  BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
-	sdc->slave.dst_addr_widths		= BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
-						  BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
-						  BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+	sdc->slave.src_addr_widths		= sdc->cfg->src_addr_widths;
+	sdc->slave.dst_addr_widths		= sdc->cfg->dst_addr_widths;
 	sdc->slave.directions			= BIT(DMA_DEV_TO_MEM) |
 						  BIT(DMA_MEM_TO_DEV);
 	sdc->slave.residue_granularity		= DMA_RESIDUE_GRANULARITY_BURST;
 	sdc->slave.dev = &pdev->dev;
 
-	sdc->pchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_channels,
+	sdc->num_pchans = sdc->cfg->nr_max_channels;
+	sdc->num_vchans = sdc->cfg->nr_max_vchans;
+	sdc->max_request = sdc->cfg->nr_max_requests;
+
+	ret = of_property_read_u32(np, "dma-channels", &sdc->num_pchans);
+	if (ret && !sdc->num_pchans) {
+		dev_err(&pdev->dev, "Can't get dma-channels.\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "dma-requests", &sdc->max_request);
+	if (ret && !sdc->max_request) {
+		dev_info(&pdev->dev, "Missing dma-requests, using %u.\n",
+			 DMA_CHAN_MAX_DRQ);
+		sdc->max_request = DMA_CHAN_MAX_DRQ;
+	}
+
+	/*
+	 * If the number of vchans is not specified, derive it from the
+	 * highest port number, at most one channel per port and direction.
+	 */
+	if (!sdc->num_vchans)
+		sdc->num_vchans = 2 * (sdc->max_request + 1);
+
+	sdc->pchans = devm_kcalloc(&pdev->dev, sdc->num_pchans,
 				   sizeof(struct sun6i_pchan), GFP_KERNEL);
 	if (!sdc->pchans)
 		return -ENOMEM;
 
-	sdc->vchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_vchans,
+	sdc->vchans = devm_kcalloc(&pdev->dev, sdc->num_vchans,
 				   sizeof(struct sun6i_vchan), GFP_KERNEL);
 	if (!sdc->vchans)
 		return -ENOMEM;
 
 	tasklet_init(&sdc->task, sun6i_dma_tasklet, (unsigned long)sdc);
 
-	for (i = 0; i < sdc->cfg->nr_max_channels; i++) {
+	for (i = 0; i < sdc->num_pchans; i++) {
 		struct sun6i_pchan *pchan = &sdc->pchans[i];
 
 		pchan->idx = i;
 		pchan->base = sdc->base + 0x100 + i * 0x40;
 	}
 
-	for (i = 0; i < sdc->cfg->nr_max_vchans; i++) {
+	for (i = 0; i < sdc->num_vchans; i++) {
 		struct sun6i_vchan *vchan = &sdc->vchans[i];
 
 		INIT_LIST_HEAD(&vchan->node);
@@ -1199,8 +1332,8 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 		goto err_dma_unregister;
 	}
 
-	if (sdc->cfg->gate_needed)
-		writel(SUN8I_DMA_GATE_ENABLE, sdc->base + SUN8I_DMA_GATE);
+	if (sdc->cfg->clock_autogate_enable)
+		sdc->cfg->clock_autogate_enable(sdc);
 
 	return 0;
 
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 96cf64d0ee82..409a97d2696e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -434,16 +434,26 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi)
 static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
 			   unsigned int n)
 {
-	/* Must be set/cleared first */
-	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-
-	/* nshift factor = 0 */
-	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
-
-	hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
-		    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
-	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+	/*
+	 * Manual CTS setting doesn't work correctly on Allwinner SoCs with
+	 * dw hdmi v1.32a.
+	 */
+	if (hdmi->version != 0x132a) {
+		/* Must be set/cleared first */
+		hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+
+		/* nshift factor = 0 */
+		hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
+
+		hdmi_writeb(hdmi,
+			    ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+			    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+		hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+		hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+	} else {
+		/* set automatic CTS calculation */
+		hdmi_writeb(hdmi, 0x00, HDMI_AUD_CTS3);
+	}
 
 	hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3);
 	hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
@@ -1647,9 +1657,10 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 	 * then write one of the FC registers several times.
 	 *
 	 * The number of iterations matters and depends on the HDMI TX revision
-	 * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
-	 * i.MX6DL (v1.31a) have been identified as needing the workaround, with
-	 * 4 and 1 iterations respectively.
+	 * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
+	 * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
+	 * as needing the workaround, with 4 iterations for v1.30a and 1
+	 * iteration for others.
 	 * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing
 	 * the workaround with a single iteration.
 	 */
@@ -1659,6 +1670,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
 		count = 4;
 		break;
 	case 0x131a:
+	case 0x132a:
 	case 0x201a:
 		count = 1;
 		break;
@@ -1973,7 +1985,11 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
 	struct drm_connector *connector = &hdmi->connector;
 
 	connector->interlace_allowed = 1;
-	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	if (hdmi->phy.ops->setup_hpd)
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+	else
+		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+				    DRM_CONNECTOR_POLL_DISCONNECT;
 
 	drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
 
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index 373e33f22be4..d0fb82d69d72 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -142,7 +142,7 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_create);
  * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative
  * error code on failure.
  */
-static struct drm_gem_cma_object *
+struct drm_gem_cma_object *
 drm_gem_cma_create_with_handle(struct drm_file *file_priv,
 			       struct drm_device *drm, size_t size,
 			       uint32_t *handle)
@@ -169,6 +169,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv,
 
 	return cma_obj;
 }
+EXPORT_SYMBOL_GPL(drm_gem_cma_create_with_handle);
 
 /**
  * drm_gem_cma_free_object - free resources associated with a CMA GEM object
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 882d85db9053..eee6bc0eaf97 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -1,6 +1,6 @@
 config DRM_SUN4I
 	tristate "DRM Support for Allwinner A10 Display Engine"
-	depends on DRM && ARM && COMMON_CLK
+	depends on DRM && (ARM || ARM64) && COMMON_CLK
 	depends on ARCH_SUNXI || COMPILE_TEST
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_HELPER
@@ -40,6 +40,15 @@ config DRM_SUN4I_BACKEND
 	  do some alpha blending and feed graphics to TCON. If M is
 	  selected the module will be called sun4i-backend.
 
+config DRM_SUN8I_DW_HDMI
+	tristate "Support for Allwinner version of DesignWare HDMI"
+	depends on DRM_SUN4I
+	select DRM_DW_HDMI
+	help
+	  Choose this option if you have an Allwinner SoC with the
+	  DesignWare HDMI controller with custom HDMI PHY. If M is
+	  selected the module will be called sun8i_dw_hdmi.
+
 config DRM_SUN8I_MIXER
 	tristate "Support for Allwinner Display Engine 2.0 Mixer"
 	default MACH_SUN8I
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 55b32368f8fb..7ce43a4c6c70 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
 obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
 obj-$(CONFIG_DRM_SUN4I_HDMI)	+= sun4i-drm-hdmi.o
 obj-$(CONFIG_DRM_SUN8I_MIXER)		+= sun8i-mixer.o
+obj-$(CONFIG_DRM_SUN8I_DW_HDMI)	+= sun8i_dw_hdmi.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index e09161cf312f..4ef54aadee99 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -21,6 +21,8 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
 
+#include <uapi/drm/sun4i_drm.h>
+
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_tcon.h"
@@ -34,6 +36,27 @@ static void sun4i_drv_lastclose(struct drm_device *dev)
 
 DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
 
+static int sun4i_gem_create_ioctl(struct drm_device *drm, void *data,
+				  struct drm_file *file_priv)
+{
+	struct drm_sun4i_gem_create *args = data;
+	struct drm_gem_cma_object *cma_obj;
+	size_t size;
+
+	/* The Mali requires a 64 bytes alignment */
+	size = ALIGN(args->size, 64);
+
+	cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, size,
+						 &args->handle);
+
+	return PTR_ERR_OR_ZERO(cma_obj);
+}
+
+static const struct drm_ioctl_desc sun4i_drv_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(SUN4I_GEM_CREATE, sun4i_gem_create_ioctl,
+			  DRM_UNLOCKED | DRM_AUTH),
+};
+
 static struct drm_driver sun4i_drv_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 
@@ -46,6 +69,10 @@ static struct drm_driver sun4i_drv_driver = {
 	.major			= 1,
 	.minor			= 0,
 
+	/* Custom ioctls */
+	.ioctls			= sun4i_drv_ioctls,
+	.num_ioctls		= ARRAY_SIZE(sun4i_drv_ioctls),
+
 	/* GEM Operations */
 	.dumb_create		= drm_gem_cma_dumb_create,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
@@ -190,6 +217,7 @@ static bool sun4i_drv_node_is_tcon(struct device_node *node)
 		of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||
 		of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||
 		of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||
+		of_device_is_compatible(node, "allwinner,sun8i-h3-tcon") ||
 		of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");
 }
 
@@ -316,6 +344,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
 	{ .compatible = "allwinner,sun6i-a31-display-engine" },
 	{ .compatible = "allwinner,sun6i-a31s-display-engine" },
 	{ .compatible = "allwinner,sun8i-a33-display-engine" },
+	{ .compatible = "allwinner,sun8i-h3-display-engine" },
 	{ .compatible = "allwinner,sun8i-v3s-display-engine" },
 	{ }
 };
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 095bd6b4ae80..0aaadb7c6cfe 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -59,6 +59,7 @@ void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
 
 	/* Disable the TCON's channel */
 	if (channel == 0) {
+		WARN_ON(!tcon->quirks->has_channel_0);
 		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
 				   SUN4I_TCON0_CTL_TCON_ENABLE, 0);
 		clk_disable_unprepare(tcon->dclk);
@@ -78,6 +79,7 @@ void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
 
 	/* Enable the TCON's channel */
 	if (channel == 0) {
+		WARN_ON(!tcon->quirks->has_channel_0);
 		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
 				   SUN4I_TCON0_CTL_TCON_ENABLE,
 				   SUN4I_TCON0_CTL_TCON_ENABLE);
@@ -157,6 +159,8 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 	u8 clk_delay;
 	u32 val = 0;
 
+	WARN_ON(!tcon->quirks->has_channel_0);
+
 	/* Configure the dot clock */
 	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
 
@@ -366,10 +370,12 @@ static int sun4i_tcon_init_clocks(struct device *dev,
 	}
 	clk_prepare_enable(tcon->clk);
 
-	tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
-	if (IS_ERR(tcon->sclk0)) {
-		dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
-		return PTR_ERR(tcon->sclk0);
+	if (tcon->quirks->has_channel_0) {
+		tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
+		if (IS_ERR(tcon->sclk0)) {
+			dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
+			return PTR_ERR(tcon->sclk0);
+		}
 	}
 	clk_prepare_enable(tcon->sclk0);
 
@@ -553,10 +559,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 		goto err_free_clocks;
 	}
 
-	ret = sun4i_dclk_create(dev, tcon);
-	if (ret) {
-		dev_err(dev, "Couldn't create our TCON dot clock\n");
-		goto err_free_clocks;
+	if (tcon->quirks->has_channel_0) {
+		ret = sun4i_dclk_create(dev, tcon);
+		if (ret) {
+			dev_err(dev, "Couldn't create our TCON dot clock\n");
+			goto err_free_clocks;
+		}
 	}
 
 	ret = sun4i_tcon_init_irq(dev, tcon);
@@ -581,7 +589,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 	return 0;
 
 err_free_dotclock:
-	sun4i_dclk_free(tcon);
+	if (tcon->quirks->has_channel_0)
+		sun4i_dclk_free(tcon);
 err_free_clocks:
 	sun4i_tcon_free_clocks(tcon);
 err_assert_reset:
@@ -595,7 +604,9 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
 	struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
 	list_del(&tcon->list);
-	sun4i_dclk_free(tcon);
+
+	if (tcon->quirks->has_channel_0)
+		sun4i_dclk_free(tcon);
 	sun4i_tcon_free_clocks(tcon);
 }
 
@@ -627,23 +638,30 @@ static int sun4i_tcon_remove(struct platform_device *pdev)
 
 static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
 	.has_unknown_mux = true,
+	.has_channel_0	= true,
 	.has_channel_1	= true,
 };
 
 static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
+	.has_channel_0	= true,
 	.has_channel_1	= true,
 };
 
 static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
+	.has_channel_0	= true,
 	.has_channel_1	= true,
 };
 
 static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
-	/* nothing is supported */
+	.has_channel_0	= true,
 };
 
 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
-	/* nothing is supported */
+	.has_channel_0	= true,
+};
+
+static const struct sun4i_tcon_quirks sun8i_h3_quirks = {
+	.has_channel_1	= true,
 };
 
 static const struct of_device_id sun4i_tcon_of_table[] = {
@@ -651,6 +669,7 @@ static const struct of_device_id sun4i_tcon_of_table[] = {
 	{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
 	{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
 	{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
+	{ .compatible = "allwinner,sun8i-h3-tcon", .data = &sun8i_h3_quirks },
 	{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
 	{ }
 };
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 552c88ec16be..de035e598129 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -145,6 +145,7 @@
 
 struct sun4i_tcon_quirks {
 	bool	has_unknown_mux; /* sun5i has undocumented mux */
+	bool	has_channel_0;	/* some A83T+ TCONs don't have channel 0*/
 	bool	has_channel_1;	/* a33 does not have channel 1 */
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
new file mode 100644
index 000000000000..65db3e10e311
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2017, Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on hdmi_bsp_sun8iw7.c which is:
+ * Copyright (c) 2016 Allwinnertech Co., 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/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include "sun4i_crtc.h"
+#include "sun4i_tcon.h"
+
+#define SUN8I_HDMI_PHY_REG_POL		0x0000
+
+#define SUN8I_HDMI_PHY_REG_READ_EN	0x0010
+#define SUN8I_HDMI_PHY_REG_READ_EN_MAGIC	0x54524545
+
+#define SUN8I_HDMI_PHY_REG_UNSCRAMBLE	0x0014
+#define SUN8I_HDMI_PHY_REG_UNSCRAMBLE_MAGIC	0x42494E47
+
+#define SUN8I_HDMI_PHY_REG_CTRL		0x0020
+#define SUN8I_HDMI_PHY_REG_UNK1		0x0024
+#define SUN8I_HDMI_PHY_REG_UNK2		0x0028
+#define SUN8I_HDMI_PHY_REG_PLL		0x002c
+#define SUN8I_HDMI_PHY_REG_CLK		0x0030
+#define SUN8I_HDMI_PHY_REG_UNK3		0x0034
+
+#define SUN8I_HDMI_PHY_REG_STATUS	0x0038
+#define SUN8I_HDMI_PHY_REG_STATUS_READY		BIT(7)
+#define SUN8I_HDMI_PHY_REG_STATUS_HPD		BIT(19)
+
+#define SUN8I_HDMI_PHY_REG_CEC		0x003c
+
+#define to_sun8i_dw_hdmi(x)	container_of(x, struct sun8i_dw_hdmi, x)
+#define set_bits(p, v)		writel(readl(p) | (v), p)
+
+struct sun8i_dw_hdmi {
+	struct clk *clk_ahb;
+	struct clk *clk_ddc;
+	struct clk *clk_sfr;
+	struct device *dev;
+	struct drm_encoder encoder;
+	void __iomem *phy_base;
+	struct dw_hdmi_plat_data plat_data;
+	struct reset_control *rst_ddc;
+	struct reset_control *rst_hdmi;
+};
+
+static u32 sun8i_dw_hdmi_get_divider(int clk_khz)
+{
+	/*
+	 * Due to missing documentation of HDMI PHY, we know correct
+	 * settings only for following four PHY dividers. Select one
+	 * based on pixel clock.
+	 */
+	if (clk_khz <= 27000)
+		return 11;
+	else if (clk_khz <= 74250)
+		return 4;
+	else if (clk_khz <= 148500)
+		return 2;
+	else
+		return 1;
+}
+
+static void sun8i_dw_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+	struct sun4i_tcon *tcon = crtc->tcon;
+
+	DRM_DEBUG_DRIVER("Disabling HDMI Output\n");
+
+	sun4i_tcon_channel_disable(tcon, 1);
+}
+
+static void sun8i_dw_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+	struct sun4i_tcon *tcon = crtc->tcon;
+
+	DRM_DEBUG_DRIVER("Enabling HDMI Output\n");
+
+	sun4i_tcon_channel_enable(tcon, 1);
+}
+
+static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+					   struct drm_display_mode *mode,
+					   struct drm_display_mode *adj_mode)
+{
+	struct sun8i_dw_hdmi *hdmi = to_sun8i_dw_hdmi(encoder);
+	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+	struct sun4i_tcon *tcon = crtc->tcon;
+	u32 div;
+
+	sun4i_tcon1_mode_set(tcon, mode);
+
+	div = sun8i_dw_hdmi_get_divider(mode->crtc_clock);
+	clk_set_rate(hdmi->clk_sfr, mode->crtc_clock * 1000 * div);
+	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+}
+
+static const struct drm_encoder_helper_funcs
+				sun8i_dw_hdmi_encoder_helper_funcs = {
+	.mode_set = sun8i_dw_hdmi_encoder_mode_set,
+	.enable   = sun8i_dw_hdmi_encoder_enable,
+	.disable  = sun8i_dw_hdmi_encoder_disable,
+};
+
+static int sun8i_dw_hdmi_phy_init(struct dw_hdmi *hdmi_data, void *data,
+				  struct drm_display_mode *mode)
+{
+	struct sun8i_dw_hdmi *hdmi = (struct sun8i_dw_hdmi *)data;
+	u32 div = sun8i_dw_hdmi_get_divider(mode->crtc_clock);
+	u32 val;
+
+	/*
+	 * Unfortunately, we don't know much about those magic
+	 * numbers. They are taken from Allwinner BSP driver.
+	 */
+
+	val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+	writel(val & ~0xf000, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+
+	switch (div) {
+	case 1:
+		writel(0x30dc5fc0, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+		writel(0x800863C0, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CLK);
+		usleep_range(10000, 15000);
+		writel(1, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK3);
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(25));
+		msleep(200);
+		val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+		val = (val & 0x1f800) >> 11;
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL,
+			 BIT(31) | BIT(30));
+		if (val < 0x3d)
+			set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL,
+				 val + 2);
+		else
+			set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, 0x3f);
+		msleep(100);
+		writel(0x01FFFF7F, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+		writel(0x8063b000, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK1);
+		writel(0x0F8246B5, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK2);
+		break;
+	case 2:
+		writel(0x39dc5040, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+		writel(0x80084381, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CLK);
+		usleep_range(10000, 15000);
+		writel(1, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK3);
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(25));
+		msleep(100);
+		val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+		val = (val & 0x1f800) >> 11;
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL,
+			 BIT(31) | BIT(30));
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, val);
+		writel(0x01FFFF7F, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+		writel(0x8063a800, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK1);
+		writel(0x0F81C485, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK2);
+		break;
+	case 4:
+		writel(0x39dc5040, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+		writel(0x80084343, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CLK);
+		usleep_range(10000, 15000);
+		writel(1, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK3);
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(25));
+		msleep(100);
+		val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+		val = (val & 0x1f800) >> 11;
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL,
+			 BIT(31) | BIT(30));
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, val);
+		writel(0x01FFFF7F, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+		writel(0x8063b000, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK1);
+		writel(0x0F81C405, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK2);
+		break;
+	case 11:
+		writel(0x39dc5040, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+		writel(0x8008430a, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CLK);
+		usleep_range(10000, 15000);
+		writel(1, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK3);
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(25));
+		msleep(100);
+		val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+		val = (val & 0x1f800) >> 11;
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL,
+			 BIT(31) | BIT(30));
+		set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, val);
+		writel(0x01FFFF7F, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+		writel(0x8063b000, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK1);
+		writel(0x0F81C405, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK2);
+		break;
+	}
+
+	/* clear polarity bits */
+	val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_POL);
+	val &= ~0x300;
+
+	/*
+	 * Set polarity bits if necessary. Condition in original code
+	 * is a bit weird. This is attempt to make it more reasonable
+	 * and it works. It could be that bits and conditions are
+	 * related and should be separated.
+	 */
+	if (!(mode->flags & DRM_MODE_FLAG_PHSYNC) ||
+	    !(mode->flags & DRM_MODE_FLAG_PVSYNC)) {
+		val |= 0x300;
+	}
+
+	writel(val, hdmi->phy_base + SUN8I_HDMI_PHY_REG_POL);
+
+	return 0;
+}
+
+static void sun8i_dw_hdmi_phy_disable(struct dw_hdmi *hdmi_data, void *data)
+{
+	struct sun8i_dw_hdmi *hdmi = (struct sun8i_dw_hdmi *)data;
+
+	/* Disable output and stop PLL */
+	writel(7, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+	writel(0, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+}
+
+static enum drm_connector_status
+			sun8i_dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi_data,
+						   void *data)
+{
+	struct sun8i_dw_hdmi *hdmi = (struct sun8i_dw_hdmi *)data;
+	u32 reg_val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+
+	return (reg_val & SUN8I_HDMI_PHY_REG_STATUS_HPD) ?
+		connector_status_connected : connector_status_disconnected;
+}
+
+static const struct dw_hdmi_phy_ops sun8i_dw_hdmi_phy_ops = {
+	.init = &sun8i_dw_hdmi_phy_init,
+	.disable = &sun8i_dw_hdmi_phy_disable,
+	.read_hpd = &sun8i_dw_hdmi_phy_read_hpd,
+};
+
+static void sun8i_dw_hdmi_init(struct sun8i_dw_hdmi *hdmi)
+{
+	u32 timeout = 20;
+	u32 val;
+
+	/*
+	 * HDMI PHY settings are taken as-is from Allwinner BSP code.
+	 * There is no documentation.
+	 */
+	writel(0, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(0));
+	udelay(5);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(16));
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(1));
+	usleep_range(10, 20);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(2));
+	udelay(5);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(3));
+	usleep_range(40, 100);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(19));
+	usleep_range(100, 200);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(18));
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, 7 << 4);
+
+	/* Note that Allwinner code doesn't fail in case of timeout */
+	while (!(readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS) &
+		SUN8I_HDMI_PHY_REG_STATUS_READY)) {
+		if (!timeout--) {
+			dev_warn(hdmi->dev, "HDMI PHY init timeout!\n");
+			break;
+		}
+		usleep_range(100, 200);
+	}
+
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, 0xf << 8);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL, BIT(7));
+
+	writel(0x39dc5040, hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL);
+	writel(0x80084343, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CLK);
+	usleep_range(10000, 15000);
+	writel(1, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK3);
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(25));
+	msleep(100);
+	val = readl(hdmi->phy_base + SUN8I_HDMI_PHY_REG_STATUS);
+	val = (val & 0x1f800) >> 11;
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, BIT(31) | BIT(30));
+	set_bits(hdmi->phy_base + SUN8I_HDMI_PHY_REG_PLL, val);
+	writel(0x01FF0F7F, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CTRL);
+	writel(0x80639000, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK1);
+	writel(0x0F81C405, hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNK2);
+
+	/* enable read access to HDMI controller */
+	writel(SUN8I_HDMI_PHY_REG_READ_EN_MAGIC,
+	       hdmi->phy_base + SUN8I_HDMI_PHY_REG_READ_EN);
+
+	/* unscramble register offsets */
+	writel(SUN8I_HDMI_PHY_REG_UNSCRAMBLE_MAGIC,
+	       hdmi->phy_base + SUN8I_HDMI_PHY_REG_UNSCRAMBLE);
+
+	/* Reset PHY CEC settings. This gives dw hdmi total control over CEC. */
+	writel(0, hdmi->phy_base + SUN8I_HDMI_PHY_REG_CEC);
+}
+
+static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_hdmi_plat_data *plat_data;
+	struct drm_device *drm = data;
+	struct drm_encoder *encoder;
+	struct sun8i_dw_hdmi *hdmi;
+	struct resource *res;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	plat_data = &hdmi->plat_data;
+	hdmi->dev = &pdev->dev;
+	encoder = &hdmi->encoder;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	/* resource 0 is the memory region for the core controller */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	hdmi->phy_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(hdmi->phy_base))
+		return PTR_ERR(hdmi->phy_base);
+
+	hdmi->clk_ahb = devm_clk_get(dev, "iahb");
+	if (IS_ERR(hdmi->clk_ahb)) {
+		dev_err(dev, "Could not get iahb clock\n");
+		return PTR_ERR(hdmi->clk_ahb);
+	}
+
+	hdmi->clk_sfr = devm_clk_get(dev, "isfr");
+	if (IS_ERR(hdmi->clk_sfr)) {
+		dev_err(dev, "Could not get isfr clock\n");
+		return PTR_ERR(hdmi->clk_sfr);
+	}
+
+	hdmi->clk_ddc = devm_clk_get(dev, "ddc");
+	if (IS_ERR(hdmi->clk_ddc)) {
+		dev_err(dev, "Could not get ddc clock\n");
+		return PTR_ERR(hdmi->clk_ddc);
+	}
+
+	hdmi->rst_hdmi = devm_reset_control_get(dev, "hdmi");
+	if (IS_ERR(hdmi->rst_hdmi)) {
+		dev_err(dev, "Could not get hdmi reset control\n");
+		return PTR_ERR(hdmi->rst_hdmi);
+	}
+
+	hdmi->rst_ddc = devm_reset_control_get(dev, "ddc");
+	if (IS_ERR(hdmi->rst_ddc)) {
+		dev_err(dev, "Could not get ddc reset control\n");
+		return PTR_ERR(hdmi->rst_ddc);
+	}
+
+	ret = clk_prepare_enable(hdmi->clk_ahb);
+	if (ret) {
+		dev_err(dev, "Cannot enable ahb clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdmi->clk_sfr);
+	if (ret) {
+		dev_err(dev, "Cannot enable isfr clock: %d\n", ret);
+		goto err_ahb_clk;
+	}
+
+	ret = clk_prepare_enable(hdmi->clk_ddc);
+	if (ret) {
+		dev_err(dev, "Cannot enable ddc clock: %d\n", ret);
+		goto err_sfr_clk;
+	}
+
+	ret = reset_control_deassert(hdmi->rst_hdmi);
+	if (ret) {
+		dev_err(dev, "Could not deassert hdmi reset control\n");
+		goto err_ddc_clk;
+	}
+
+	ret = reset_control_deassert(hdmi->rst_ddc);
+	if (ret) {
+		dev_err(dev, "Could not deassert ddc reset control\n");
+		goto err_assert_hdmi_reset;
+	}
+
+	drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+
+	sun8i_dw_hdmi_init(hdmi);
+
+	plat_data->phy_ops = &sun8i_dw_hdmi_phy_ops,
+	plat_data->phy_name = "sun8i_dw_hdmi_phy",
+	plat_data->phy_data = hdmi;
+
+	ret = dw_hdmi_bind(pdev, encoder, plat_data);
+
+	/*
+	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
+	 * which would have called the encoder cleanup.  Do it manually.
+	 */
+	if (ret)
+		goto cleanup_encoder;
+
+	return 0;
+
+cleanup_encoder:
+	drm_encoder_cleanup(encoder);
+	reset_control_assert(hdmi->rst_ddc);
+err_assert_hdmi_reset:
+	reset_control_assert(hdmi->rst_hdmi);
+err_ddc_clk:
+	clk_disable_unprepare(hdmi->clk_ddc);
+err_sfr_clk:
+	clk_disable_unprepare(hdmi->clk_sfr);
+err_ahb_clk:
+	clk_disable_unprepare(hdmi->clk_ahb);
+
+	return ret;
+}
+
+static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
+				 void *data)
+{
+	return dw_hdmi_unbind(dev);
+}
+
+static const struct component_ops sun8i_dw_hdmi_ops = {
+	.bind	= sun8i_dw_hdmi_bind,
+	.unbind	= sun8i_dw_hdmi_unbind,
+};
+
+static int sun8i_dw_hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun8i_dw_hdmi_ops);
+}
+
+static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun8i_dw_hdmi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
+	{ .compatible = "allwinner,sun8i-h3-dw-hdmi" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
+
+struct platform_driver sun8i_dw_hdmi_pltfm_driver = {
+	.probe  = sun8i_dw_hdmi_probe,
+	.remove = sun8i_dw_hdmi_remove,
+	.driver = {
+		.name = "sun8i-dw-hdmi",
+		.of_match_table = sun8i_dw_hdmi_dt_ids,
+	},
+};
+module_platform_driver(sun8i_dw_hdmi_pltfm_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner H3 DW HDMI bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 519610e0bf66..56cde98976b2 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -390,11 +390,29 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
 	.ui_num = 1,
 };
 
+static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
+	.vi_num = 1,
+	.ui_num = 3,
+};
+
+static const struct sun8i_mixer_cfg sun8i_h3_mixer1_cfg = {
+	.vi_num = 1,
+	.ui_num = 1,
+};
+
 static const struct of_device_id sun8i_mixer_of_table[] = {
 	{
 		.compatible = "allwinner,sun8i-v3s-de2-mixer",
 		.data = &sun8i_v3s_mixer_cfg,
 	},
+	{
+		.compatible = "allwinner,sun8i-h3-de2-mixer0",
+		.data = &sun8i_h3_mixer0_cfg
+	},
+	{
+		.compatible = "allwinner,sun8i-h3-de2-mixer1",
+		.data = &sun8i_h3_mixer1_cfg
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 137f577d9432..abf89dacee38 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -22,6 +22,7 @@
  * shutdown for not being used.
  */
 
+#include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -31,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <linux/thermal.h>
 #include <linux/delay.h>
 
@@ -49,46 +51,23 @@ static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
 	return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
 }
 
+struct sun4i_gpadc_iio;
+
 struct gpadc_data {
 	int		temp_offset;
 	int		temp_scale;
+	int		temp_divider;
 	unsigned int	tp_mode_en;
 	unsigned int	tp_adc_select;
 	unsigned int	(*adc_chan_select)(unsigned int chan);
 	unsigned int	adc_chan_mask;
-};
-
-static const struct gpadc_data sun4i_gpadc_data = {
-	.temp_offset = -1932,
-	.temp_scale = 133,
-	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
-	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
-	.adc_chan_select = &sun4i_gpadc_chan_select,
-	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun5i_gpadc_data = {
-	.temp_offset = -1447,
-	.temp_scale = 100,
-	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
-	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
-	.adc_chan_select = &sun4i_gpadc_chan_select,
-	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun6i_gpadc_data = {
-	.temp_offset = -1623,
-	.temp_scale = 167,
-	.tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
-	.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
-	.adc_chan_select = &sun6i_gpadc_chan_select,
-	.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun8i_a33_gpadc_data = {
-	.temp_offset = -1662,
-	.temp_scale = 162,
-	.tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
+	unsigned int	temp_data;
+	int		(*sample_start)(struct sun4i_gpadc_iio *info);
+	int		(*sample_end)(struct sun4i_gpadc_iio *info);
+	void	(*reg_to_temp)(int val, int *temp);
+	bool		has_bus_clk;
+	bool		has_bus_rst;
+	bool		has_mod_clk;
 };
 
 struct sun4i_gpadc_iio {
@@ -103,6 +82,9 @@ struct sun4i_gpadc_iio {
 	atomic_t			ignore_temp_data_irq;
 	const struct gpadc_data		*data;
 	bool				no_irq;
+	struct clk			*ths_bus_clk;
+	struct clk			*mod_clk;
+	struct reset_control		*reset;
 	/* prevents concurrent reads of temperature and ADC */
 	struct mutex			mutex;
 	struct thermal_zone_device	*tzd;
@@ -277,11 +259,14 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
 	if (info->no_irq) {
 		pm_runtime_get_sync(indio_dev->dev.parent);
 
-		regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+		regmap_read(info->regmap, info->data->temp_data, val);
 
 		pm_runtime_mark_last_busy(indio_dev->dev.parent);
 		pm_runtime_put_autosuspend(indio_dev->dev.parent);
 
+		if (!*val)
+			return -EINVAL;
+
 		return 0;
 	}
 
@@ -306,6 +291,15 @@ static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val)
 	return 0;
 }
 
+static int sun4i_gpadc_temp_divider(struct iio_dev *indio_dev, int *val)
+{
+	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
+
+	*val = info->data->temp_divider;
+
+	return 0;
+}
+
 static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
 				struct iio_chan_spec const *chan, int *val,
 				int *val2, long mask)
@@ -383,10 +377,8 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int sun4i_gpadc_runtime_suspend(struct device *dev)
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
 {
-	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
-
 	/* Disable the ADC on IP */
 	regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
 	/* Disable temperature sensor on IP */
@@ -395,10 +387,23 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int sun4i_gpadc_runtime_resume(struct device *dev)
+static int sun8i_h3_gpadc_sample_end(struct sun4i_gpadc_iio *info)
+{
+	/* Disable temperature sensor */
+	regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2, 0);
+
+	return 0;
+}
+
+static int sun4i_gpadc_runtime_suspend(struct device *dev)
 {
 	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
 
+	return info->data->sample_end(info);
+}
+
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
 	/* clkin = 6MHz */
 	regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
 		     SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
@@ -416,22 +421,58 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
 	return 0;
 }
 
+static int sun8i_h3_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
+	regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2,
+		     SUN8I_H3_GPADC_CTRL2_TEMP_SENSE_EN |
+		     SUN8I_H3_GPADC_CTRL2_T_ACQ1(31));
+	regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
+		     SUN4I_GPADC_CTRL0_T_ACQ(31));
+	regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL3,
+		     SUN4I_GPADC_CTRL3_FILTER_EN |
+		     SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
+	regmap_write(info->regmap, SUN8I_H3_GPADC_INTC,
+		     SUN8I_H3_GPADC_INTC_TEMP_PERIOD(800));
+
+	return 0;
+}
+
+static int sun4i_gpadc_runtime_resume(struct device *dev)
+{
+	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+
+	return info->data->sample_start(info);
+}
+
 static int sun4i_gpadc_get_temp(void *data, int *temp)
 {
 	struct sun4i_gpadc_iio *info = data;
-	int val, scale, offset;
+	int val, scale, offset, divider;
 
 	if (sun4i_gpadc_temp_read(info->indio_dev, &val))
 		return -ETIMEDOUT;
 
 	sun4i_gpadc_temp_scale(info->indio_dev, &scale);
 	sun4i_gpadc_temp_offset(info->indio_dev, &offset);
+	sun4i_gpadc_temp_divider(info->indio_dev, &divider);
 
-	*temp = (val + offset) * scale;
+	if (info->data->reg_to_temp)
+		info->data->reg_to_temp(val, temp);
+	else
+		*temp = ((val + offset) * scale) / divider;
 
 	return 0;
 }
 
+void sun50i_h5_reg_to_temp(int val, int *temp)
+{
+	u32 data = (u32)val;
+	if (data <= 0x500)
+		*temp = (2590000 - 1452 * data) / 10000;
+	else
+		*temp = (2230000 - 1191 * data) / 10000;
+}
+
 static const struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
 	.get_temp = &sun4i_gpadc_get_temp,
 };
@@ -490,11 +531,118 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
 	return 0;
 }
 
+static const struct gpadc_data sun4i_gpadc_data = {
+	.temp_offset = -1932,
+	.temp_scale = 133,
+	.temp_divider = 1,
+	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
+	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
+	.adc_chan_select = &sun4i_gpadc_chan_select,
+	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+	.temp_data = SUN4I_GPADC_TEMP_DATA,
+	.sample_start = sun4i_gpadc_sample_start,
+	.sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun5i_gpadc_data = {
+	.temp_offset = -1447,
+	.temp_scale = 100,
+	.temp_divider = 1,
+	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
+	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
+	.adc_chan_select = &sun4i_gpadc_chan_select,
+	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+	.temp_data = SUN4I_GPADC_TEMP_DATA,
+	.sample_start = sun4i_gpadc_sample_start,
+	.sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun6i_gpadc_data = {
+	.temp_offset = -1623,
+	.temp_scale = 167,
+	.temp_divider = 1,
+	.tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
+	.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
+	.adc_chan_select = &sun6i_gpadc_chan_select,
+	.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
+	.temp_data = SUN4I_GPADC_TEMP_DATA,
+	.sample_start = sun4i_gpadc_sample_start,
+	.sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun8i_a33_gpadc_data = {
+	.temp_offset = -1662,
+	.temp_scale = 162,
+	.temp_divider = 1,
+	.tp_mode_en = SUN8I_A23_GPADC_CTRL1_CHOP_TEMP_EN,
+	.temp_data = SUN4I_GPADC_TEMP_DATA,
+	.sample_start = sun4i_gpadc_sample_start,
+	.sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun8i_h3_gpadc_data = {
+	/*
+	 * The original formula on the datasheet seems to be wrong.
+	 * These factors are calculated based on the formula in the BSP
+	 * kernel, which is originally Tem = 217 - (T / 8.253), in which Tem
+	 * is the temperature in Celsius degree and T is the raw value
+	 * from the sensor.
+	 */
+	.temp_offset = -1791,
+	.temp_scale = -121,
+	.temp_divider = 1,
+	.temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+	.sample_start = sun8i_h3_gpadc_sample_start,
+	.sample_end = sun8i_h3_gpadc_sample_end,
+	.has_bus_clk = true,
+	.has_bus_rst = true,
+	.has_mod_clk = true,
+};
+
+static const struct gpadc_data sun50i_a64_gpadc_data = {
+	.temp_offset = -2170,
+	.temp_scale = -1000,
+	.temp_divider = 8560,
+	.temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+	.sample_start = sun8i_h3_gpadc_sample_start,
+	.sample_end = sun8i_h3_gpadc_sample_end,
+	.has_bus_clk = true,
+	.has_bus_rst = true,
+	.has_mod_clk = true,
+};
+
+static const struct gpadc_data sun50i_h5_gpadc_data = {
+	/* Not done for now since requires 3 extra fields
+		and/or a custom temperature conversion function
+	 */
+	.temp_offset = -1791,
+	.temp_scale = -121,
+	.temp_divider = 1,
+	.temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+	.sample_start = sun8i_h3_gpadc_sample_start,
+	.sample_end = sun8i_h3_gpadc_sample_end,
+	.has_bus_clk = true,
+	.has_bus_rst = true,
+	.has_mod_clk = true,
+};
+
 static const struct of_device_id sun4i_gpadc_of_id[] = {
 	{
 		.compatible = "allwinner,sun8i-a33-ths",
 		.data = &sun8i_a33_gpadc_data,
 	},
+	{
+		.compatible = "allwinner,sun8i-h3-ths",
+		.data = &sun8i_h3_gpadc_data,
+	},
+	{
+		.compatible = "allwinner,sun50i-a64-ths",
+		.data = &sun50i_a64_gpadc_data,
+	},
+	{
+		.compatible = "allwinner,sun50i-h5-ths",
+		.data = &sun50i_h5_gpadc_data,
+	},
 	{ /* sentinel */ }
 };
 
@@ -529,17 +677,75 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
 		return ret;
 	}
 
+	if (info->data->has_bus_rst) {
+		info->reset = devm_reset_control_get(&pdev->dev, NULL);
+		if (IS_ERR(info->reset)) {
+			ret = PTR_ERR(info->reset);
+			return ret;
+		}
+
+		ret = reset_control_deassert(info->reset);
+		if (ret)
+			return ret;
+	}
+
+	if (info->data->has_bus_clk) {
+		info->ths_bus_clk = devm_clk_get(&pdev->dev, "bus");
+		if (IS_ERR(info->ths_bus_clk)) {
+			ret = PTR_ERR(info->ths_bus_clk);
+			goto assert_reset;
+		}
+
+		ret = clk_prepare_enable(info->ths_bus_clk);
+		if (ret)
+			goto assert_reset;
+	}
+
+	if (info->data->has_mod_clk) {
+		info->mod_clk = devm_clk_get(&pdev->dev, "mod");
+		if (IS_ERR(info->mod_clk)) {
+			ret = PTR_ERR(info->mod_clk);
+			goto disable_bus_clk;
+		}
+
+		/* Running at 6MHz */
+		ret = clk_set_rate(info->mod_clk, 6000000);
+		if (ret)
+			goto disable_bus_clk;
+
+		ret = clk_prepare_enable(info->mod_clk);
+		if (ret)
+			goto disable_bus_clk;
+	}
+
 	if (!IS_ENABLED(CONFIG_THERMAL_OF))
 		return 0;
 
 	info->sensor_device = &pdev->dev;
 	info->tzd = thermal_zone_of_sensor_register(info->sensor_device, 0,
 						    info, &sun4i_ts_tz_ops);
-	if (IS_ERR(info->tzd))
+	if (IS_ERR(info->tzd)) {
 		dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
 			PTR_ERR(info->tzd));
+		ret = PTR_ERR(info->tzd);
+		goto disable_mod_clk;
+	}
 
-	return PTR_ERR_OR_ZERO(info->tzd);
+	return 0;
+
+disable_mod_clk:
+	if (info->data->has_mod_clk)
+		clk_disable_unprepare(info->mod_clk);
+
+disable_bus_clk:
+	if (info->data->has_bus_clk)
+		clk_disable_unprepare(info->ths_bus_clk);
+
+assert_reset:
+	if (info->data->has_bus_rst)
+		reset_control_assert(info->reset);
+
+	return ret;
 }
 
 static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
@@ -698,6 +904,15 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
 	if (!info->no_irq)
 		iio_map_array_unregister(indio_dev);
 
+	if (info->data->has_mod_clk)
+		clk_disable_unprepare(info->mod_clk);
+
+	if (info->data->has_bus_clk)
+		clk_disable_unprepare(info->ths_bus_clk);
+
+	if (info->data->has_bus_rst)
+		reset_control_assert(info->reset);
+
 	return 0;
 }
 
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index dc8c1e3eafe7..6e3fab9587b7 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -157,7 +157,7 @@ static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip)
 
 	irq_set_percpu_devid(irq);
 	irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq);
-	irq_set_status_flags(irq, IRQ_NOAUTOEN);
+	irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW);
 }
 
 static void
@@ -175,6 +175,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
 		u32 ipi = ffs(mbox_val) - 1;
 
 		writel(1 << ipi, mailbox0);
+		dsb(sy);
 		handle_IPI(ipi, regs);
 #endif
 	} else if (stat) {
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 336de66ca408..13261f314100 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -28,6 +28,7 @@
 #include <linux/mfd/core.h>
 #include <linux/of_device.h>
 #include <linux/acpi.h>
+#include <linux/delay.h>
 
 #define AXP20X_OFF	0x80
 
@@ -81,6 +82,7 @@ static const struct regmap_range axp20x_volatile_ranges[] = {
 	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
 	regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
 	regmap_reg_range(AXP20X_GPIO20_SS, AXP20X_GPIO3_CTRL),
+	regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_DISCHRG_CC_7_0),
 	regmap_reg_range(AXP20X_FG_RES, AXP20X_RDC_L),
 };
 
@@ -892,6 +894,611 @@ static void axp20x_power_off(void)
 	msleep(500);
 }
 
+#define kobj_to_device(x) container_of(x, struct device, kobj)
+
+int axp20x_get_adc_freq(struct axp20x_dev *axp)
+{
+	unsigned int res;
+	int ret, freq = 25;
+
+	ret = regmap_read(axp->regmap, AXP20X_ADC_RATE, &res);
+	if (ret < 0) {
+		dev_warn(axp->dev, "Unable to read ADC sampling frequency: %d\n", ret);
+		return freq;
+	}
+	switch ((res & 0xC0) >> 6) {
+	case 0:
+		freq = 25;
+		break;
+	case 1:
+		freq = 50;
+		break;
+	case 2:
+		freq = 100;
+		break;
+	case 3:
+		freq = 200;
+		break;
+	}
+	return freq;
+}
+
+static ssize_t axp20x_sysfs_read_bin_file(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	int ret;
+
+	struct device *dev = kobj_to_device(kobj);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	ret = regmap_raw_read(axp->regmap, AXP20X_OCV(off), buf, count);
+	if (ret < 0)
+	{
+		dev_warn(axp->dev, "read_bin_file: error reading: %d\n", ret);
+		return ret;
+	}
+	return count;
+}
+
+static ssize_t axp20x_sysfs_write_bin_file(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t off, size_t count)
+{
+	int ret;
+
+	struct device *dev = kobj_to_device(kobj);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	ret = regmap_raw_write(axp->regmap, AXP20X_OCV(off), buf, count);
+	if (ret < 0)
+	{
+		dev_warn(axp->dev, "write_bin_file: error writing: %d\n", ret);
+		return ret;
+	}
+	return count;
+}
+
+static ssize_t axp20x_read_special(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int i, freq, ret = 0;
+	unsigned int res;
+	u32 lval1, lval2;
+	s64 llval;
+	u64 ullval;
+
+	const char *subsystem = kobject_name(kobj);
+	struct device *dev = kobj_to_device(kobj->parent);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	dev_dbg(axp->dev, "read_special: reading attribute %s of object %s\n", attr->attr.name, subsystem);
+
+	if (strcmp(subsystem, "battery") == 0) {
+		if (strcmp(attr->attr.name, "power") == 0) {
+			lval1 = 0;
+			for (i = 0; i < 3; i++) {
+				ret |= regmap_read(axp->regmap, AXP20X_PWR_BATT_H + i, &res);
+				lval1 |= res << ((2 - i) * 8);
+			}
+			llval = lval1 * 1100 / 1000;
+		} else if (strcmp(attr->attr.name, "charge") == 0) {
+			ret = regmap_raw_read(axp->regmap, AXP20X_CHRG_CC_31_24, &lval1, sizeof(lval1));
+			ret |= regmap_raw_read(axp->regmap, AXP20X_DISCHRG_CC_31_24, &lval2, sizeof(lval2));
+			be32_to_cpus(&lval1);
+			be32_to_cpus(&lval2);
+			ullval = abs((s64)lval1 - (s64)lval2) * 65536 * 500;
+			freq = axp20x_get_adc_freq(axp);
+			do_div(ullval, 3600 * freq);
+			llval = (lval1 < lval2) ? -ullval : ullval;
+		} else if (strcmp(attr->attr.name, "capacity") == 0) {
+			ret = regmap_read(axp->regmap, AXP20X_FG_RES, &res);
+			llval = res & 0x7f;
+		} else
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	if (ret < 0) {
+		dev_warn(axp->dev, "Unable to read parameter: %d\n", ret);
+		return ret;
+	}
+	return sprintf(buf, "%lld\n", llval);
+}
+
+static ssize_t axp20x_write_int(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int reg, var, ret = 0, scale, width = 12, offset = 0;
+	unsigned int res;
+
+	const char *subsystem = kobject_name(kobj);
+	struct device *dev = kobj_to_device(kobj->parent);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	dev_dbg(axp->dev, "write_int: writing attribute %s of object %s\n", attr->attr.name, subsystem);
+
+	ret = kstrtoint(buf, 10, &var);
+	if (ret < 0)
+		return ret;
+
+	if (strcmp(subsystem, "control") == 0) {
+		if (strcmp(attr->attr.name, "battery_rdc") == 0) {
+			reg = AXP20X_RDC_H;
+			scale = 1074;
+			width = 13;
+			offset = 537;
+			/* TODO: Disable & enable fuel gauge */
+		} else
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	res = (var + offset) / scale;
+
+	ret = regmap_write_bits(axp->regmap, reg, (1U << (width - 8)) - 1, (res >> 8) & 0xFF);
+	ret |= regmap_write_bits(axp->regmap, reg + 1, 0xFF, res & 0xFF);
+
+	if (ret < 0) {
+		dev_warn(axp->dev, "Unable to write parameter: %d\n", ret);
+		return ret;
+	}
+	return count;
+}
+
+static ssize_t axp20x_read_bool(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int val, ret, reg, bit;
+	unsigned int res;
+
+	const char *subsystem = kobject_name(kobj);
+	struct device *dev = kobj_to_device(kobj->parent);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	dev_dbg(axp->dev, "read_bool: reading attribute %s of object %s\n", attr->attr.name, subsystem);
+
+	if (strcmp(subsystem, "ac") == 0) {
+		if (strcmp(attr->attr.name, "connected") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 7;
+		} else if (strcmp(attr->attr.name, "used") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 6;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "vbus") == 0) {
+		if (strcmp(attr->attr.name, "connected") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 5;
+		} else if (strcmp(attr->attr.name, "used") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 4;
+		} else if (strcmp(attr->attr.name, "strong") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 3;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "battery") == 0) {
+		if (strcmp(attr->attr.name, "connected") == 0) {
+			reg = AXP20X_PWR_OP_MODE;
+			bit = 5;
+		} else if (strcmp(attr->attr.name, "charging") == 0) {
+			reg = AXP20X_PWR_INPUT_STATUS;
+			bit = 2;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "pmu") == 0) {
+		if (strcmp(attr->attr.name, "overheat") == 0) {
+			reg = AXP20X_PWR_OP_MODE;
+			bit = 7;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "charger") == 0) {
+		if (strcmp(attr->attr.name, "charging") == 0) {
+			reg = AXP20X_PWR_OP_MODE;
+			bit = 6;
+		} else if (strcmp(attr->attr.name, "cell_activation") == 0) {
+			reg = AXP20X_PWR_OP_MODE;
+			bit = 3;
+		} else if (strcmp(attr->attr.name, "low_power") == 0) {
+			reg = AXP20X_PWR_OP_MODE;
+			bit = 2;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "control") == 0) {
+		if (strcmp(attr->attr.name, "set_vbus_direct_mode") == 0) {
+			reg = AXP20X_VBUS_IPSOUT_MGMT;
+			bit = 6;
+		} else if (strcmp(attr->attr.name, "reset_charge_counter") == 0) {
+			reg = AXP20X_CC_CTRL;
+			bit = 5;
+		} else if (strcmp(attr->attr.name, "charge_rtc_battery") == 0) {
+			reg = AXP20X_CHRG_BAK_CTRL;
+			bit = 7;
+		} else if (strcmp(attr->attr.name, "disable_fuel_gauge") == 0) {
+			reg = AXP20X_FG_RES;
+			bit = 7;
+		} else
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	ret = regmap_read(axp->regmap, reg, &res);
+	if (ret < 0) {
+		dev_warn(axp->dev, "Unable to read parameter: %d\n", ret);
+		return ret;
+	}
+	val = (res & BIT(bit)) == BIT(bit) ? 1 : 0;
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t axp20x_write_bool(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int var, ret, reg, bit;
+
+	const char *subsystem = kobject_name(kobj);
+	struct device *dev = kobj_to_device(kobj->parent);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	dev_dbg(axp->dev, "write_bool: writing attribute %s of object %s", attr->attr.name, subsystem);
+
+	ret = kstrtoint(buf, 10, &var);
+	if (ret < 0)
+		return ret;
+
+	if (strcmp(subsystem, "control") == 0) {
+		if (strcmp(attr->attr.name, "set_vbus_direct_mode") == 0) {
+			reg = AXP20X_VBUS_IPSOUT_MGMT;
+			bit = 6;
+		} else if (strcmp(attr->attr.name, "reset_charge_counter") == 0) {
+			reg = AXP20X_CC_CTRL;
+			bit = 5;
+		} else if (strcmp(attr->attr.name, "charge_rtc_battery") == 0) {
+			reg = AXP20X_CHRG_BAK_CTRL;
+			bit = 7;
+		} else if (strcmp(attr->attr.name, "disable_fuel_gauge") == 0) {
+			reg = AXP20X_FG_RES;
+			bit = 7;
+		} else
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	ret = regmap_update_bits(axp->regmap, reg, BIT(bit), var ? BIT(bit) : 0);
+	if (ret)
+		dev_warn(axp->dev, "Unable to write value: %d", ret);
+	return count;
+}
+
+static int axp20x_averaging_helper(struct regmap *reg_map, int reg_h,
+	int width)
+{
+	long acc = 0;
+	int ret, i;
+
+	for (i = 0; i < 3; i++) {
+		ret = axp20x_read_variable_width(reg_map, reg_h, width);
+		if (ret < 0)
+			return ret;
+		acc += ret;
+		msleep(20); /* For 100Hz sampling frequency */
+	}
+	return (int)(acc / 3);
+}
+
+static ssize_t axp20x_read_int(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int val, ret, scale, reg, width = 12, offset = 0;
+
+	const char *subsystem = kobject_name(kobj);
+	struct device *dev = kobj_to_device(kobj->parent);
+	struct axp20x_dev *axp = dev_get_drvdata(dev);
+
+	dev_dbg(axp->dev, "read_int: reading attribute %s of object %s\n", attr->attr.name, subsystem);
+
+	if (strcmp(subsystem, "ac") == 0) {
+		if (strcmp(attr->attr.name, "voltage") == 0) {
+			reg = AXP20X_ACIN_V_ADC_H;
+			scale = 1700;
+		} else if (strcmp(attr->attr.name, "amperage") == 0) {
+			reg = AXP20X_ACIN_I_ADC_H;
+			scale = 625;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "vbus") == 0) {
+		if (strcmp(attr->attr.name, "voltage") == 0) {
+			reg = AXP20X_VBUS_V_ADC_H;
+			scale = 1700;
+		} else if (strcmp(attr->attr.name, "amperage") == 0) {
+			reg = AXP20X_VBUS_I_ADC_H;
+			scale = 375;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "battery") == 0) {
+		if (strcmp(attr->attr.name, "voltage") == 0) {
+			reg = AXP20X_BATT_V_H;
+			scale = 1100;
+		} else if (strcmp(attr->attr.name, "amperage") == 0) {
+			reg = AXP20X_BATT_DISCHRG_I_H;
+			scale = 500;
+			width = 13;
+		} else if (strcmp(attr->attr.name, "ts_voltage") == 0) {
+			reg = AXP20X_TS_IN_H;
+			scale = 800;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "pmu") == 0) {
+		if (strcmp(attr->attr.name, "temp") == 0) {
+			reg = AXP20X_TEMP_ADC_H;
+			scale = 100;
+			offset = 144700;
+		} else if (strcmp(attr->attr.name, "voltage") == 0) {
+			reg = AXP20X_IPSOUT_V_HIGH_H;
+			scale = 1400;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "charger") == 0) {
+		if (strcmp(attr->attr.name, "amperage") == 0) {
+			reg = AXP20X_BATT_CHRG_I_H;
+			scale = 500;
+		} else
+			return -EINVAL;
+	} else if (strcmp(subsystem, "control") == 0) {
+		if (strcmp(attr->attr.name, "battery_rdc") == 0) {
+			reg = AXP20X_RDC_H;
+			width = 13;
+			scale = 1074;
+			offset = 537;
+		} else
+			return -EINVAL;
+	} else
+		return -EINVAL;
+
+	ret = axp20x_averaging_helper(axp->regmap, reg, width);
+
+	if (ret < 0) {
+		dev_warn(axp->dev, "Unable to read parameter: %d\n", ret);
+		return ret;
+	}
+	val = ret * scale - offset;
+	return sprintf(buf, "%d\n", val);
+}
+
+/* AC IN */
+static struct kobj_attribute ac_in_voltage = __ATTR(voltage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute ac_in_amperage = __ATTR(amperage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute ac_in_connected = __ATTR(connected, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute ac_in_used = __ATTR(used, S_IRUGO, axp20x_read_bool, NULL);
+
+static struct attribute *axp20x_attributes_ac[] = {
+	&ac_in_voltage.attr,
+	&ac_in_amperage.attr,
+	&ac_in_connected.attr,
+	&ac_in_used.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_ac = {
+	.attrs = axp20x_attributes_ac,
+};
+
+/* Vbus */
+static struct kobj_attribute vbus_voltage = __ATTR(voltage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute vbus_amperage = __ATTR(amperage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute vbus_connected = __ATTR(connected, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute vbus_used = __ATTR(used, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute vbus_strong = __ATTR(strong, S_IRUGO, axp20x_read_bool, NULL);
+
+static struct attribute *axp20x_attributes_vbus[] = {
+	&vbus_voltage.attr,
+	&vbus_amperage.attr,
+	&vbus_connected.attr,
+	&vbus_used.attr,
+	&vbus_strong.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_vbus = {
+	.attrs = axp20x_attributes_vbus,
+};
+
+/* Battery */
+static struct kobj_attribute batt_voltage = __ATTR(voltage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute batt_amperage = __ATTR(amperage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute batt_ts_voltage = __ATTR(ts_voltage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute batt_power = __ATTR(power, S_IRUGO, axp20x_read_special, NULL);
+static struct kobj_attribute batt_charge = __ATTR(charge, S_IRUGO, axp20x_read_special, NULL);
+static struct kobj_attribute batt_capacity = __ATTR(capacity, S_IRUGO, axp20x_read_special, NULL);
+static struct kobj_attribute batt_connected = __ATTR(connected, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute batt_charging = __ATTR(charging, S_IRUGO, axp20x_read_bool, NULL);
+
+static struct attribute *axp20x_attributes_battery[] = {
+	&batt_voltage.attr,
+	&batt_amperage.attr,
+	&batt_ts_voltage.attr,
+	&batt_power.attr,
+	&batt_charge.attr,
+	&batt_capacity.attr,
+	&batt_connected.attr,
+	&batt_charging.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_battery = {
+	.attrs = axp20x_attributes_battery,
+};
+
+/* PMU */
+static struct kobj_attribute pmu_temp = __ATTR(temp, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute pmu_voltage = __ATTR(voltage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute pmu_overheat = __ATTR(overheat, S_IRUGO, axp20x_read_bool, NULL);
+
+static struct attribute *axp20x_attributes_pmu[] = {
+	&pmu_temp.attr,
+	&pmu_voltage.attr,
+	&pmu_overheat.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_pmu = {
+	.attrs = axp20x_attributes_pmu,
+};
+
+/* Charger */
+static struct kobj_attribute charger_amperage = __ATTR(amperage, S_IRUGO, axp20x_read_int, NULL);
+static struct kobj_attribute charger_charging = __ATTR(charging, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute charger_cell_activation = __ATTR(cell_activation, S_IRUGO, axp20x_read_bool, NULL);
+static struct kobj_attribute charger_low_power = __ATTR(low_power, S_IRUGO, axp20x_read_bool, NULL);
+
+static struct attribute *axp20x_attributes_charger[] = {
+	&charger_amperage.attr,
+	&charger_charging.attr,
+	&charger_cell_activation.attr,
+	&charger_low_power.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_charger = {
+	.attrs = axp20x_attributes_charger,
+};
+
+/* Control (writeable) */
+static struct kobj_attribute control_vbus_direct_mode = __ATTR(set_vbus_direct_mode, (S_IRUGO | S_IWUSR),
+	axp20x_read_bool, axp20x_write_bool);
+static struct kobj_attribute control_reset_charge_counter = __ATTR(reset_charge_counter, (S_IRUGO | S_IWUSR),
+	axp20x_read_bool, axp20x_write_bool);
+static struct kobj_attribute control_charge_rtc_battery = __ATTR(charge_rtc_battery, (S_IRUGO | S_IWUSR),
+	axp20x_read_bool, axp20x_write_bool);
+static struct kobj_attribute control_disable_fuel_gauge = __ATTR(disable_fuel_gauge, (S_IRUGO | S_IWUSR),
+	axp20x_read_bool, axp20x_write_bool);
+static struct kobj_attribute control_battery_rdc = __ATTR(battery_rdc, (S_IRUGO | S_IWUSR),
+	axp20x_read_int, axp20x_write_int);
+
+static struct attribute *axp20x_attributes_control[] = {
+	&control_vbus_direct_mode.attr,
+	&control_reset_charge_counter.attr,
+	&control_charge_rtc_battery.attr,
+	&control_disable_fuel_gauge.attr,
+	&control_battery_rdc.attr,
+	NULL,
+};
+
+static const struct attribute_group axp20x_group_control = {
+	.attrs = axp20x_attributes_control,
+};
+
+static struct {
+	struct kobject *ac;
+	struct kobject *vbus;
+	struct kobject *battery;
+	struct kobject *pmu;
+	struct kobject *charger;
+	struct kobject *control;
+} subsystems;
+
+static struct bin_attribute axp20x_ocv_curve = __BIN_ATTR(ocv_curve, S_IRUGO | S_IWUSR,
+	axp20x_sysfs_read_bin_file, axp20x_sysfs_write_bin_file, AXP20X_OCV_MAX + 1);
+
+static void axp20x_sysfs_create_subgroup(const char name[], struct axp20x_dev *axp,
+	struct kobject *subgroup, const struct attribute_group *attrs)
+{
+	int ret;
+	struct kobject *parent = &axp->dev->kobj;
+	subgroup = kobject_create_and_add(name, parent);
+	if (subgroup != NULL) {
+		ret = sysfs_create_group(subgroup, attrs);
+		if (ret) {
+			dev_warn(axp->dev, "Unable to register sysfs group: %s: %d", name, ret);
+			kobject_put(subgroup);
+		}
+	}
+}
+
+static void axp20x_sysfs_remove_subgroup(struct kobject *subgroup,
+	const struct attribute_group *attrs)
+{
+	sysfs_remove_group(subgroup, attrs);
+	kobject_put(subgroup);
+}
+
+static int axp20x_sysfs_init(struct axp20x_dev *axp)
+{
+	int ret;
+	unsigned int res;
+
+	/* Enable all ADC channels in the first register */
+	ret = regmap_write(axp->regmap, AXP20X_ADC_EN1, 0xFF);
+	if (ret)
+		dev_warn(axp->dev, "Unable to enable ADC: %d", ret);
+
+	/*
+	 * Set ADC sampling frequency to 100Hz (default is 25)
+	 * Always measure battery temperature (default: only when charging)
+	 */
+	ret = regmap_update_bits(axp->regmap, AXP20X_ADC_RATE, 0xC3, 0x82);
+	if (ret)
+		dev_warn(axp->dev, "Unable to set ADC frequency and TS current output: %d", ret);
+
+	/* Enable fuel gauge and charge counter */
+	ret = regmap_update_bits(axp->regmap, AXP20X_FG_RES, 0x80, 0x00);
+	if (ret)
+		dev_warn(axp->dev, "Unable to enable battery fuel gauge: %d", ret);
+	/* ret = regmap_update_bits(axp->regmap, AXP20X_CC_CTRL, 0xC0, 0x00); */
+	ret |= regmap_update_bits(axp->regmap, AXP20X_CC_CTRL, 0xC0, 0x80);
+	if (ret)
+		dev_warn(axp->dev, "Unable to enable battery charge counter: %d", ret);
+
+	/* Enable battery detection */
+	ret = regmap_read(axp->regmap, AXP20X_OFF_CTRL, &res);
+	if (ret == 0) {
+		if ((res & 0x40) != 0x40) {
+			dev_info(axp->dev, "Battery detection is disabled, enabling");
+			ret = regmap_update_bits(axp->regmap, AXP20X_OFF_CTRL, 0x40, 0x40);
+			if (ret)
+				dev_warn(axp->dev, "Unable to enable battery detection: %d", ret);
+		}
+	} else
+		dev_warn(axp->dev, "Unable to read register AXP20X_OFF_CTRL: %d", ret);
+
+	/* Get info about backup (RTC) battery */
+	ret = regmap_read(axp->regmap, AXP20X_CHRG_BAK_CTRL, &res);
+	if (ret == 0) {
+		dev_info(axp->dev, "Backup (RTC) battery charging is %s",
+			(res & 0x80) == 0x80 ? "enabled" : "disabled");
+		if ((res & 0x60) != 0x20)
+			dev_warn(axp->dev, "Backup (RTC) battery target voltage is not 3.0V");
+	} else
+		dev_warn(axp->dev, "Unable to read register AXP20X_CHRG_BAK_CTRL: %d", ret);
+
+	axp20x_sysfs_create_subgroup("ac", axp, subsystems.ac, &axp20x_group_ac);
+	axp20x_sysfs_create_subgroup("vbus", axp, subsystems.vbus, &axp20x_group_vbus);
+	axp20x_sysfs_create_subgroup("battery", axp, subsystems.battery, &axp20x_group_battery);
+	axp20x_sysfs_create_subgroup("pmu", axp, subsystems.pmu, &axp20x_group_pmu);
+	axp20x_sysfs_create_subgroup("charger", axp, subsystems.charger, &axp20x_group_charger);
+	axp20x_sysfs_create_subgroup("control", axp, subsystems.control, &axp20x_group_control);
+
+	ret = sysfs_create_bin_file(&axp->dev->kobj, &axp20x_ocv_curve);
+	if (ret)
+		dev_warn(axp->dev, "Unable to create sysfs ocv_curve file: %d", ret);
+
+	ret = sysfs_create_link_nowarn(power_kobj, &axp->dev->kobj, "axp_pmu");
+	if (ret)
+		dev_warn(axp->dev, "Unable to create sysfs symlink: %d", ret);
+	return ret;
+}
+
+static void axp20x_sysfs_exit(struct axp20x_dev *axp)
+{
+	sysfs_delete_link(power_kobj, &axp->dev->kobj, "axp_pmu");
+	sysfs_remove_bin_file(&axp->dev->kobj, &axp20x_ocv_curve);
+	axp20x_sysfs_remove_subgroup(subsystems.control, &axp20x_group_control);
+	axp20x_sysfs_remove_subgroup(subsystems.charger, &axp20x_group_charger);
+	axp20x_sysfs_remove_subgroup(subsystems.pmu, &axp20x_group_pmu);
+	axp20x_sysfs_remove_subgroup(subsystems.battery, &axp20x_group_battery);
+	axp20x_sysfs_remove_subgroup(subsystems.vbus, &axp20x_group_vbus);
+	axp20x_sysfs_remove_subgroup(subsystems.ac, &axp20x_group_ac);
+}
+
 int axp20x_match_device(struct axp20x_dev *axp20x)
 {
 	struct device *dev = axp20x->dev;
@@ -1043,6 +1650,10 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
 		pm_power_off = axp20x_power_off;
 	}
 
+	if (axp20x->variant == AXP209_ID || axp20x->variant == AXP202_ID) {
+		axp20x_sysfs_init(axp20x);
+	}
+
 	dev_info(axp20x->dev, "AXP20X driver loaded\n");
 
 	return 0;
@@ -1056,6 +1667,10 @@ int axp20x_device_remove(struct axp20x_dev *axp20x)
 		pm_power_off = NULL;
 	}
 
+	if (axp20x->variant == AXP209_ID || axp20x->variant == AXP202_ID) {
+		axp20x_sysfs_exit(axp20x);
+	}
+
 	mfd_remove_devices(axp20x->dev);
 	regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
 
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 5423c3bb388e..03c42c85ea5d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -50,6 +50,10 @@ struct nand_flash_dev nand_flash_ids[] = {
 	{"SDTNRGAMA 64G 3.3V 8-bit",
 		{ .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
 		  SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
+	{"H27UBG8T2BTR-BC 32G 3.3V 8-bit",
+		{ .id = {0xad, 0xd7, 0x94, 0xda, 0x74, 0xc3} },
+		  SZ_8K, SZ_4K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+		  NAND_ECC_INFO(40, SZ_1K), 0 },
 	{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
 		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
 		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 0fe3e39f870f..ce242739fcd6 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -948,6 +948,13 @@ static const struct flash_info spi_nor_ids[] = {
 
 	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
 
+	/* BergMicro Flashes */
+	{ "bg25q80", INFO(0xe04014, 0, 64 * 1024,  16, SECT_4K) },
+	{ "bg25q16", INFO(0xe04015, 0, 64 * 1024,  32, SECT_4K) },
+	{ "bg25q32", INFO(0xe04016, 0, 64 * 1024,  64, SECT_4K) },
+	{ "bg25q64", INFO(0xe04017, 0, 64 * 1024, 128, SECT_4K) },
+	{ "bg25q128", INFO(0xe04018, 0, 64 * 1024, 256, SECT_4K) },
+
 	/* EON -- en25xxx */
 	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
 	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 5790cd61436d..bf4acebb6bcd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -159,6 +159,7 @@ config DWMAC_SUN8I
 	tristate "Allwinner sun8i GMAC support"
 	default ARCH_SUNXI
 	depends on OF && (ARCH_SUNXI || COMPILE_TEST)
+	select MDIO_BUS_MUX
 	---help---
 	  Support for Allwinner H3 A83T A64 EMAC ethernet controllers.
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index e51b50d94074..729195cab41a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -442,9 +442,9 @@ struct stmmac_dma_ops {
 	void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
 			 int rxfifosz);
 	void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
-			    int fifosz);
+			    int fifosz, u8 qmode);
 	void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
-			    int fifosz);
+			    int fifosz, u8 qmode);
 	/* To track extra statistic (if supported) */
 	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
 				   void __iomem *ioaddr);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
index 1924788d28da..826626e870d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -51,15 +51,11 @@
 #define NSS_COMMON_CLK_SRC_CTRL_RGMII(x)	1
 #define NSS_COMMON_CLK_SRC_CTRL_SGMII(x)	((x >= 2) ? 1 : 0)
 
-#define NSS_COMMON_MACSEC_CTL			0x28
-#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x)	(1 << x)
-
 #define NSS_COMMON_GMAC_CTL(x)			(0x30 + (x * 4))
 #define NSS_COMMON_GMAC_CTL_CSYS_REQ		BIT(19)
 #define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL	BIT(16)
 #define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET	8
 #define NSS_COMMON_GMAC_CTL_IFG_OFFSET		0
-#define NSS_COMMON_GMAC_CTL_IFG_MASK		0x3f
 
 #define NSS_COMMON_CLK_DIV_RGMII_1000		1
 #define NSS_COMMON_CLK_DIV_RGMII_100		9
@@ -68,9 +64,6 @@
 #define NSS_COMMON_CLK_DIV_SGMII_100		4
 #define NSS_COMMON_CLK_DIV_SGMII_10		49
 
-#define QSGMII_PCS_MODE_CTL			0x68
-#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x)	BIT((x * 8) + 7)
-
 #define QSGMII_PCS_CAL_LCKDT_CTL		0x120
 #define QSGMII_PCS_CAL_LCKDT_CTL_RST		BIT(19)
 
@@ -83,15 +76,10 @@
 #define QSGMII_PHY_TX_DRIVER_EN			BIT(3)
 #define QSGMII_PHY_QSGMII_EN			BIT(7)
 #define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET	12
-#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK		0x7
 #define QSGMII_PHY_RX_DC_BIAS_OFFSET		18
-#define QSGMII_PHY_RX_DC_BIAS_MASK		0x3
 #define QSGMII_PHY_RX_INPUT_EQU_OFFSET		20
-#define QSGMII_PHY_RX_INPUT_EQU_MASK		0x3
 #define QSGMII_PHY_CDR_PI_SLEW_OFFSET		22
-#define QSGMII_PHY_CDR_PI_SLEW_MASK		0x3
 #define QSGMII_PHY_TX_DRV_AMP_OFFSET		28
-#define QSGMII_PHY_TX_DRV_AMP_MASK		0xf
 
 struct ipq806x_gmac {
 	struct platform_device *pdev;
@@ -217,7 +205,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
 	 * code and keep it consistent with the Linux convention, we'll number
 	 * them from 0 to 3 here.
 	 */
-	if (gmac->id < 0 || gmac->id > 3) {
+	if (gmac->id > 3) {
 		dev_err(dev, "invalid gmac id\n");
 		return -EINVAL;
 	}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index 61cb24810d10..9e6db16af663 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -1,8 +1,8 @@
 /*
  * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU
  *
- * Copyright (C) Alexandre Torgue 2015
- * Author:  Alexandre Torgue <alexandre.torgue@gmail.com>
+ * Copyright (C) STMicroelectronics SA 2017
+ * Author:  Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  * License terms:  GNU General Public License (GPL), version 2
  *
  */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 149fd0d5e069..fa67c318c238 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/mdio-mux.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
@@ -41,14 +42,14 @@
  *				This value is used for disabling properly EMAC
  *				and used as a good starting value in case of the
  *				boot process(uboot) leave some stuff.
- * @internal_phy:		Does the MAC embed an internal PHY
+ * @soc_has_internal_phy:	Does the MAC embed an internal PHY
  * @support_mii:		Does the MAC handle MII
  * @support_rmii:		Does the MAC handle RMII
  * @support_rgmii:		Does the MAC handle RGMII
  */
 struct emac_variant {
 	u32 default_syscon_value;
-	int internal_phy;
+	bool soc_has_internal_phy;
 	bool support_mii;
 	bool support_rmii;
 	bool support_rgmii;
@@ -61,7 +62,8 @@ struct emac_variant {
  * @rst_ephy:	reference to the optional EPHY reset for the internal PHY
  * @variant:	reference to the current board variant
  * @regmap:	regmap for using the syscon
- * @use_internal_phy: Does the current PHY choice imply using the internal PHY
+ * @internal_phy_powered: Does the internal PHY is enabled
+ * @mux_handle:	Internal pointer used by mdio-mux lib
  */
 struct sunxi_priv_data {
 	struct clk *tx_clk;
@@ -70,12 +72,13 @@ struct sunxi_priv_data {
 	struct reset_control *rst_ephy;
 	const struct emac_variant *variant;
 	struct regmap *regmap;
-	bool use_internal_phy;
+	bool internal_phy_powered;
+	void *mux_handle;
 };
 
 static const struct emac_variant emac_variant_h3 = {
 	.default_syscon_value = 0x58000,
-	.internal_phy = PHY_INTERFACE_MODE_MII,
+	.soc_has_internal_phy = true,
 	.support_mii = true,
 	.support_rmii = true,
 	.support_rgmii = true
@@ -83,20 +86,20 @@ static const struct emac_variant emac_variant_h3 = {
 
 static const struct emac_variant emac_variant_v3s = {
 	.default_syscon_value = 0x38000,
-	.internal_phy = PHY_INTERFACE_MODE_MII,
+	.soc_has_internal_phy = true,
 	.support_mii = true
 };
 
 static const struct emac_variant emac_variant_a83t = {
 	.default_syscon_value = 0,
-	.internal_phy = 0,
+	.soc_has_internal_phy = false,
 	.support_mii = true,
 	.support_rgmii = true
 };
 
 static const struct emac_variant emac_variant_a64 = {
 	.default_syscon_value = 0,
-	.internal_phy = 0,
+	.soc_has_internal_phy = false,
 	.support_mii = true,
 	.support_rmii = true,
 	.support_rgmii = true
@@ -195,6 +198,9 @@ static const struct emac_variant emac_variant_a64 = {
 #define H3_EPHY_LED_POL		BIT(17) /* 1: active low, 0: active high */
 #define H3_EPHY_SHUTDOWN	BIT(16) /* 1: shutdown, 0: power up */
 #define H3_EPHY_SELECT		BIT(15) /* 1: internal PHY, 0: external PHY */
+#define H3_EPHY_MUX_MASK	(H3_EPHY_SHUTDOWN | H3_EPHY_SELECT)
+#define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID	1
+#define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID	2
 
 /* H3/A64 specific bits */
 #define SYSCON_RMII_EN		BIT(13) /* 1: enable RMII (overrides EPIT) */
@@ -635,6 +641,159 @@ static int sun8i_dwmac_reset(struct stmmac_priv *priv)
 	return 0;
 }
 
+/* Search in mdio-mux node for internal PHY node and get its clk/reset */
+static int get_ephy_nodes(struct stmmac_priv *priv)
+{
+	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+	struct device_node *mdio_mux, *iphynode;
+	struct device_node *mdio_internal;
+	int ret;
+
+	mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
+	if (!mdio_mux) {
+		dev_err(priv->device, "Cannot get mdio-mux node\n");
+		return -ENODEV;
+	}
+
+	mdio_internal = of_find_compatible_node(mdio_mux, NULL,
+						"allwinner,sun8i-h3-mdio-internal");
+	if (!mdio_internal) {
+		dev_err(priv->device, "Cannot get internal_mdio node\n");
+		return -ENODEV;
+	}
+
+	/* Seek for internal PHY */
+	for_each_child_of_node(mdio_internal, iphynode) {
+		gmac->ephy_clk = of_clk_get(iphynode, 0);
+		if (IS_ERR(gmac->ephy_clk))
+			continue;
+		gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
+		if (IS_ERR(gmac->rst_ephy)) {
+			ret = PTR_ERR(gmac->rst_ephy);
+			if (ret == -EPROBE_DEFER)
+				return ret;
+			continue;
+		}
+		dev_info(priv->device, "Found internal PHY node\n");
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
+{
+	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+	int ret;
+
+	if (gmac->internal_phy_powered) {
+		dev_warn(priv->device, "Internal PHY already powered\n");
+		return 0;
+	}
+
+	dev_info(priv->device, "Powering internal PHY\n");
+	ret = clk_prepare_enable(gmac->ephy_clk);
+	if (ret) {
+		dev_err(priv->device, "Cannot enable internal PHY\n");
+		return ret;
+	}
+
+	/* Make sure the EPHY is properly reseted, as U-Boot may leave
+	 * it at deasserted state, and thus it may fail to reset EMAC.
+	 */
+	reset_control_assert(gmac->rst_ephy);
+
+	ret = reset_control_deassert(gmac->rst_ephy);
+	if (ret) {
+		dev_err(priv->device, "Cannot deassert internal phy\n");
+		clk_disable_unprepare(gmac->ephy_clk);
+		return ret;
+	}
+
+	gmac->internal_phy_powered = true;
+
+	return 0;
+}
+
+static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
+{
+	if (!gmac->internal_phy_powered)
+		return 0;
+
+	clk_disable_unprepare(gmac->ephy_clk);
+	reset_control_assert(gmac->rst_ephy);
+	gmac->internal_phy_powered = false;
+	return 0;
+}
+
+/* MDIO multiplexing switch function
+ * This function is called by the mdio-mux layer when it thinks the mdio bus
+ * multiplexer needs to switch.
+ * 'current_child' is the current value of the mux register
+ * 'desired_child' is the value of the 'reg' property of the target child MDIO
+ * node.
+ * The first time this function is called, current_child == -1.
+ * If current_child == desired_child, then the mux is already set to the
+ * correct bus.
+ */
+static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
+				     void *data)
+{
+	struct stmmac_priv *priv = data;
+	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+	u32 reg, val;
+	int ret = 0;
+	bool need_power_ephy = false;
+
+	if (current_child ^ desired_child) {
+		regmap_read(gmac->regmap, SYSCON_EMAC_REG, &reg);
+		switch (desired_child) {
+		case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
+			dev_info(priv->device, "Switch mux to internal PHY");
+			val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
+
+			need_power_ephy = true;
+			break;
+		case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
+			dev_info(priv->device, "Switch mux to external PHY");
+			val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN;
+			need_power_ephy = false;
+			break;
+		default:
+			dev_err(priv->device, "Invalid child ID %x\n",
+				desired_child);
+			return -EINVAL;
+		}
+		regmap_write(gmac->regmap, SYSCON_EMAC_REG, val);
+		if (need_power_ephy) {
+			ret = sun8i_dwmac_power_internal_phy(priv);
+			if (ret)
+				return ret;
+		} else {
+			sun8i_dwmac_unpower_internal_phy(gmac);
+		}
+		/* After changing syscon value, the MAC need reset or it will
+		 * use the last value (and so the last PHY set).
+		 */
+		ret = sun8i_dwmac_reset(priv);
+	}
+	return ret;
+}
+
+static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
+{
+	int ret;
+	struct device_node *mdio_mux;
+	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+
+	mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
+	if (!mdio_mux)
+		return -ENODEV;
+
+	ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn,
+			    &gmac->mux_handle, priv, priv->mii);
+	return ret;
+}
+
 static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 {
 	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
@@ -649,35 +808,24 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 			 "Current syscon value is not the default %x (expect %x)\n",
 			 val, reg);
 
-	if (gmac->variant->internal_phy) {
-		if (!gmac->use_internal_phy) {
-			/* switch to external PHY interface */
-			reg &= ~H3_EPHY_SELECT;
-		} else {
-			reg |= H3_EPHY_SELECT;
-			reg &= ~H3_EPHY_SHUTDOWN;
-			dev_dbg(priv->device, "Select internal_phy %x\n", reg);
-
-			if (of_property_read_bool(priv->plat->phy_node,
-						  "allwinner,leds-active-low"))
-				reg |= H3_EPHY_LED_POL;
-			else
-				reg &= ~H3_EPHY_LED_POL;
-
-			/* Force EPHY xtal frequency to 24MHz. */
-			reg |= H3_EPHY_CLK_SEL;
-
-			ret = of_mdio_parse_addr(priv->device,
-						 priv->plat->phy_node);
-			if (ret < 0) {
-				dev_err(priv->device, "Could not parse MDIO addr\n");
-				return ret;
-			}
-			/* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
-			 * address. No need to mask it again.
-			 */
-			reg |= ret << H3_EPHY_ADDR_SHIFT;
+	if (gmac->variant->soc_has_internal_phy) {
+		if (of_property_read_bool(node, "allwinner,leds-active-low"))
+			reg |= H3_EPHY_LED_POL;
+		else
+			reg &= ~H3_EPHY_LED_POL;
+
+		/* Force EPHY xtal frequency to 24MHz. */
+		reg |= H3_EPHY_CLK_SEL;
+
+		ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node);
+		if (ret < 0) {
+			dev_err(priv->device, "Could not parse MDIO addr\n");
+			return ret;
 		}
+		/* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
+		 * address. No need to mask it again.
+		 */
+		reg |= 1 << H3_EPHY_ADDR_SHIFT;
 	}
 
 	if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
@@ -750,81 +898,21 @@ static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac)
 	regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
 }
 
-static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
+static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
 {
-	struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
-	int ret;
-
-	if (!gmac->use_internal_phy)
-		return 0;
-
-	ret = clk_prepare_enable(gmac->ephy_clk);
-	if (ret) {
-		dev_err(priv->device, "Cannot enable ephy\n");
-		return ret;
-	}
-
-	/* Make sure the EPHY is properly reseted, as U-Boot may leave
-	 * it at deasserted state, and thus it may fail to reset EMAC.
-	 */
-	reset_control_assert(gmac->rst_ephy);
+	struct sunxi_priv_data *gmac = priv;
 
-	ret = reset_control_deassert(gmac->rst_ephy);
-	if (ret) {
-		dev_err(priv->device, "Cannot deassert ephy\n");
-		clk_disable_unprepare(gmac->ephy_clk);
-		return ret;
+	if (gmac->variant->soc_has_internal_phy) {
+		/* sun8i_dwmac_exit could be called with mdiomux uninit */
+		if (gmac->mux_handle)
+			mdio_mux_uninit(gmac->mux_handle);
+		if (gmac->internal_phy_powered)
+			sun8i_dwmac_unpower_internal_phy(gmac);
 	}
 
-	return 0;
-}
-
-static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
-{
-	if (!gmac->use_internal_phy)
-		return 0;
-
-	clk_disable_unprepare(gmac->ephy_clk);
-	reset_control_assert(gmac->rst_ephy);
-	return 0;
-}
-
-/* sun8i_power_phy() - Activate the PHY:
- * In case of error, no need to call sun8i_unpower_phy(),
- * it will be called anyway by sun8i_dwmac_exit()
- */
-static int sun8i_power_phy(struct stmmac_priv *priv)
-{
-	int ret;
-
-	ret = sun8i_dwmac_power_internal_phy(priv);
-	if (ret)
-		return ret;
-
-	ret = sun8i_dwmac_set_syscon(priv);
-	if (ret)
-		return ret;
-
-	/* After changing syscon value, the MAC need reset or it will use
-	 * the last value (and so the last PHY set.
-	 */
-	ret = sun8i_dwmac_reset(priv);
-	if (ret)
-		return ret;
-	return 0;
-}
-
-static void sun8i_unpower_phy(struct sunxi_priv_data *gmac)
-{
 	sun8i_dwmac_unset_syscon(gmac);
-	sun8i_dwmac_unpower_internal_phy(gmac);
-}
-
-static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
-{
-	struct sunxi_priv_data *gmac = priv;
 
-	sun8i_unpower_phy(gmac);
+	reset_control_put(gmac->rst_ephy);
 
 	clk_disable_unprepare(gmac->tx_clk);
 
@@ -853,7 +941,7 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
 	if (!mac)
 		return NULL;
 
-	ret = sun8i_power_phy(priv);
+	ret = sun8i_dwmac_set_syscon(priv);
 	if (ret)
 		return NULL;
 
@@ -895,6 +983,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 	struct sunxi_priv_data *gmac;
 	struct device *dev = &pdev->dev;
 	int ret;
+	struct stmmac_priv *priv;
+	struct net_device *ndev;
 
 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
 	if (ret)
@@ -938,29 +1028,6 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 	}
 
 	plat_dat->interface = of_get_phy_mode(dev->of_node);
-	if (plat_dat->interface == gmac->variant->internal_phy) {
-		dev_info(&pdev->dev, "Will use internal PHY\n");
-		gmac->use_internal_phy = true;
-		gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0);
-		if (IS_ERR(gmac->ephy_clk)) {
-			ret = PTR_ERR(gmac->ephy_clk);
-			dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret);
-			return -EINVAL;
-		}
-
-		gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL);
-		if (IS_ERR(gmac->rst_ephy)) {
-			ret = PTR_ERR(gmac->rst_ephy);
-			if (ret == -EPROBE_DEFER)
-				return ret;
-			dev_err(&pdev->dev, "No EPHY reset control found %d\n",
-				ret);
-			return -EINVAL;
-		}
-	} else {
-		dev_info(&pdev->dev, "Will use external PHY\n");
-		gmac->use_internal_phy = false;
-	}
 
 	/* platform data specifying hardware features and callbacks.
 	 * hardware features were copied from Allwinner drivers.
@@ -979,12 +1046,45 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 
 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 	if (ret)
-		sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
+		goto dwmac_exit;
+
+	ndev = dev_get_drvdata(&pdev->dev);
+	priv = netdev_priv(ndev);
+	/* The mux must be registered after parent MDIO
+	 * so after stmmac_dvr_probe()
+	 */
+	if (gmac->variant->soc_has_internal_phy) {
+		ret = get_ephy_nodes(priv);
+		if (ret)
+			goto dwmac_exit;
+		ret = sun8i_dwmac_register_mdio_mux(priv);
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to register mux\n");
+			goto dwmac_mux;
+		}
+	} else {
+		ret = sun8i_dwmac_reset(priv);
+		if (ret)
+			goto dwmac_exit;
+	}
 
 	return ret;
+dwmac_mux:
+	sun8i_dwmac_unset_syscon(gmac);
+dwmac_exit:
+	sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
+return ret;
 }
 
 static const struct of_device_id sun8i_dwmac_match[] = {
+	{ .compatible = "allwinner,sun8i-h3-emac",
+		.data = &emac_variant_h3 },
+	{ .compatible = "allwinner,sun8i-v3s-emac",
+		.data = &emac_variant_v3s },
+	{ .compatible = "allwinner,sun8i-a83t-emac",
+		.data = &emac_variant_a83t },
+	{ .compatible = "allwinner,sun50i-a64-emac",
+		.data = &emac_variant_a64 },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index db5f2aee360b..31af98ba760e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -98,7 +98,7 @@
 #define	GMAC_PCS_IRQ_DEFAULT	(GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK |	\
 				 GMAC_INT_PCS_ANE)
 
-#define	GMAC_INT_DEFAULT_MASK	GMAC_INT_PMT_EN
+#define	GMAC_INT_DEFAULT_MASK	(GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
 
 enum dwmac4_irq_status {
 	time_stamp_irq = 0x00001000,
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
 	mmc_tx_irq = 0x00000400,
 	mmc_rx_irq = 0x00000200,
 	mmc_irq = 0x00000100,
+	lpi_irq = 0x00000020,
 	pmt_irq = 0x00000010,
 };
 
@@ -132,6 +133,10 @@ enum power_event {
 #define GMAC4_LPI_CTRL_STATUS_LPITXA	BIT(19)	/* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS	BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIEN	BIT(16)	/* LPI Enable */
+#define GMAC4_LPI_CTRL_STATUS_RLPIEX	BIT(3) /* Receive LPI Exit */
+#define GMAC4_LPI_CTRL_STATUS_RLPIEN	BIT(2) /* Receive LPI Entry */
+#define GMAC4_LPI_CTRL_STATUS_TLPIEX	BIT(1) /* Transmit LPI Exit */
+#define GMAC4_LPI_CTRL_STATUS_TLPIEN	BIT(0) /* Transmit LPI Entry */
 
 /* MAC Debug bitmap */
 #define GMAC_DEBUG_TFCSTS_MASK		GENMASK(18, 17)
@@ -225,6 +230,8 @@ enum power_event {
 #define MTL_CHAN_RX_DEBUG(x)		(MTL_CHANX_BASE_ADDR(x) + 0x38)
 
 #define MTL_OP_MODE_RSF			BIT(5)
+#define MTL_OP_MODE_TXQEN_MASK		GENMASK(3, 2)
+#define MTL_OP_MODE_TXQEN_AV		BIT(2)
 #define MTL_OP_MODE_TXQEN		BIT(3)
 #define MTL_OP_MODE_TSF			BIT(1)
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index e5566c121525..52a663e0a878 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -595,6 +595,25 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
 		x->irq_receive_pmt_irq_n++;
 	}
 
+	/* MAC tx/rx EEE LPI entry/exit interrupts */
+	if (intr_status & lpi_irq) {
+		/* Clear LPI interrupt by reading MAC_LPI_Control_Status */
+		u32 status = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+
+		if (status & GMAC4_LPI_CTRL_STATUS_TLPIEN) {
+			ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
+			x->irq_tx_path_in_lpi_mode_n++;
+		}
+		if (status & GMAC4_LPI_CTRL_STATUS_TLPIEX) {
+			ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
+			x->irq_tx_path_exit_lpi_mode_n++;
+		}
+		if (status & GMAC4_LPI_CTRL_STATUS_RLPIEN)
+			x->irq_rx_path_in_lpi_mode_n++;
+		if (status & GMAC4_LPI_CTRL_STATUS_RLPIEX)
+			x->irq_rx_path_exit_lpi_mode_n++;
+	}
+
 	dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
 	if (intr_status & PCS_RGSMIIIS_IRQ)
 		dwmac4_phystatus(ioaddr, x);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 898849bbc7d4..c110f6850ffa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -191,7 +191,7 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan)
 }
 
 static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
-				       u32 channel, int fifosz)
+				       u32 channel, int fifosz, u8 qmode)
 {
 	unsigned int rqs = fifosz / 256 - 1;
 	u32 mtl_rx_op, mtl_rx_int;
@@ -218,8 +218,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
 	mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
 	mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
 
-	/* enable flow control only if each channel gets 4 KiB or more FIFO */
-	if (fifosz >= 4096) {
+	/* Enable flow control only if each channel gets 4 KiB or more FIFO and
+	 * only if channel is not an AVB channel.
+	 */
+	if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
 		unsigned int rfd, rfa;
 
 		mtl_rx_op |= MTL_OP_MODE_EHFC;
@@ -271,7 +273,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
 }
 
 static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
-				       u32 channel, int fifosz)
+				       u32 channel, int fifosz, u8 qmode)
 {
 	u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
 	unsigned int tqs = fifosz / 256 - 1;
@@ -311,7 +313,11 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
 	 * reflect the available fifo size per queue (total fifo size / number
 	 * of enabled queues).
 	 */
-	mtl_tx_op |= MTL_OP_MODE_TXQEN;
+	mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
+	if (qmode != MTL_QUEUE_AVB)
+		mtl_tx_op |= MTL_OP_MODE_TXQEN;
+	else
+		mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
 	mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
 	mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a7b30f060536..a90a1ff5b29d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1784,6 +1784,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 	u32 txmode = 0;
 	u32 rxmode = 0;
 	u32 chan = 0;
+	u8 qmode = 0;
 
 	if (rxfifosz == 0)
 		rxfifosz = priv->dma_cap.rx_fifo_size;
@@ -1815,13 +1816,19 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 
 	/* configure all channels */
 	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-		for (chan = 0; chan < rx_channels_count; chan++)
+		for (chan = 0; chan < rx_channels_count; chan++) {
+			qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+
 			priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
-						   rxfifosz);
+						   rxfifosz, qmode);
+		}
+
+		for (chan = 0; chan < tx_channels_count; chan++) {
+			qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
 
-		for (chan = 0; chan < tx_channels_count; chan++)
 			priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
-						   txfifosz);
+						   txfifosz, qmode);
+		}
 	} else {
 		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
 					rxfifosz);
@@ -1990,6 +1997,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
 static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
 					  u32 rxmode, u32 chan)
 {
+	u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+	u8 txqmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
 	u32 rx_channels_count = priv->plat->rx_queues_to_use;
 	u32 tx_channels_count = priv->plat->tx_queues_to_use;
 	int rxfifosz = priv->plat->rx_fifo_size;
@@ -2006,9 +2015,9 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
 
 	if (priv->synopsys_id >= DWMAC_CORE_4_00) {
 		priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
-					   rxfifosz);
+					   rxfifosz, rxqmode);
 		priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
-					   txfifosz);
+					   txfifosz, txqmode);
 	} else {
 		priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
 					rxfifosz);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index d48cc32dc507..94b366b1f139 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -317,10 +317,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
 	bool mdio = true;
 	static const struct of_device_id need_mdio_ids[] = {
 		{ .compatible = "snps,dwc-qos-ethernet-4.10" },
-		{ .compatible = "allwinner,sun8i-a83t-emac" },
-		{ .compatible = "allwinner,sun8i-h3-emac" },
-		{ .compatible = "allwinner,sun8i-v3s-emac" },
-		{ .compatible = "allwinner,sun50i-a64-emac" },
 		{},
 	};
 
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index 37ee856c7680..b8be59633093 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -20,6 +20,8 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/microchipphy.h>
+#include <linux/of.h>
+#include <dt-bindings/net/microchip-lan78xx.h>
 
 #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC	"Microchip LAN88XX PHY driver"
@@ -70,6 +72,8 @@ static int lan88xx_probe(struct phy_device *phydev)
 {
 	struct device *dev = &phydev->mdio.dev;
 	struct lan88xx_priv *priv;
+	u32 led_modes[4];
+	int len;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -77,6 +81,27 @@ static int lan88xx_probe(struct phy_device *phydev)
 
 	priv->wolopts = 0;
 
+	len = of_property_read_variable_u32_array(dev->of_node,
+						  "microchip,led-modes",
+						  led_modes,
+						  0,
+						  ARRAY_SIZE(led_modes));
+	if (len >= 0) {
+		u32 reg = 0;
+		int i;
+
+		for (i = 0; i < len; i++) {
+			if (led_modes[i] > 15)
+				return -EINVAL;
+			reg |= led_modes[i] << (i * 4);
+		}
+		for (; i < ARRAY_SIZE(led_modes); i++)
+			reg |= LAN78XX_FORCE_LED_OFF << (i * 4);
+		(void)phy_write(phydev, LAN78XX_PHY_LED_MODE_SELECT, reg);
+	} else if (len == -EOVERFLOW) {
+		return -EINVAL;
+	}
+
 	/* these values can be used to identify internal PHY */
 	priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
 	priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 7d38af5ed4b5..e69b6e424b53 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -13,6 +13,7 @@
  * option) any later version.
  *
  */
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/module.h>
 
@@ -22,11 +23,15 @@
 #define RTL821x_INER		0x12
 #define RTL821x_INER_INIT	0x6400
 #define RTL821x_INSR		0x13
+
+#define RTL8211_PAGE_SELECT	0x1f
+
 #define RTL8211E_INER_LINK_STATUS 0x400
+#define RTL8211E_EXT_PAGE_SELECT 0x1e
+#define RTL8211E_EXT_PAGE	0x7
 
 #define RTL8211F_INER_LINK_STATUS 0x0010
 #define RTL8211F_INSR		0x1d
-#define RTL8211F_PAGE_SELECT	0x1f
 #define RTL8211F_TX_DELAY	0x100
 
 MODULE_DESCRIPTION("Realtek PHY driver");
@@ -46,10 +51,10 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev)
 {
 	int err;
 
-	phy_write(phydev, RTL8211F_PAGE_SELECT, 0xa43);
+	phy_write(phydev, RTL8211_PAGE_SELECT, 0xa43);
 	err = phy_read(phydev, RTL8211F_INSR);
 	/* restore to default page 0 */
-	phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+	phy_write(phydev, RTL8211_PAGE_SELECT, 0x0);
 
 	return (err < 0) ? err : 0;
 }
@@ -102,7 +107,7 @@ static int rtl8211f_config_init(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
-	phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
+	phy_write(phydev, RTL8211_PAGE_SELECT, 0xd08);
 	reg = phy_read(phydev, 0x11);
 
 	/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
@@ -114,7 +119,35 @@ static int rtl8211f_config_init(struct phy_device *phydev)
 
 	phy_write(phydev, 0x11, reg);
 	/* restore to default page 0 */
-	phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
+	phy_write(phydev, RTL8211_PAGE_SELECT, 0x0);
+
+	return 0;
+}
+
+static int rtl8211e_config_init(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	struct device_node *of_node = dev->of_node;
+	int ret;
+
+	ret = genphy_config_init(phydev);
+	if (ret < 0)
+		return ret;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		/*
+		 * Disable the RX internal delay here.
+		 *
+		 * All the magic numbers are not documented on RTL8211E
+		 * datasheet. They're said to be from Realtek by Pine64.
+		 */
+		phy_write(phydev, RTL8211_PAGE_SELECT, RTL8211E_EXT_PAGE);
+		phy_write(phydev, RTL8211E_EXT_PAGE_SELECT, 0xa4);
+		phy_write(phydev, 0x1c, 0xb591);
+
+		/* Restore to default page 0 */
+		phy_write(phydev, RTL8211_PAGE_SELECT, 0);
+	}
 
 	return 0;
 }
@@ -159,6 +192,7 @@ static struct phy_driver realtek_drvs[] = {
 		.features	= PHY_GBIT_FEATURES,
 		.flags		= PHY_HAS_INTERRUPT,
 		.config_aneg	= &genphy_config_aneg,
+		.config_init	= rtl8211e_config_init,
 		.read_status	= &genphy_read_status,
 		.ack_interrupt	= &rtl821x_ack_interrupt,
 		.config_intr	= &rtl8211e_config_intr,
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 120e99914fd6..4b8478894ea9 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -38,6 +38,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/microchipphy.h>
 #include <linux/phy.h>
+#include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include "lan78xx.h"
 
@@ -1631,6 +1632,7 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)
 	u32 addr_lo, addr_hi;
 	int ret;
 	u8 addr[6];
+	const u8 *mac_addr;
 
 	ret = lan78xx_read_reg(dev, RX_ADDRL, &addr_lo);
 	ret = lan78xx_read_reg(dev, RX_ADDRH, &addr_hi);
@@ -1659,7 +1661,7 @@ static void lan78xx_init_mac_address(struct lan78xx_net *dev)
 			/* generate random MAC */
 			random_ether_addr(addr);
 			netif_dbg(dev, ifup, dev->net,
-				  "MAC address set to random addr");
+				"MAC address set to random addr");
 		}
 
 		addr_lo = addr[0] | (addr[1] << 8) |
@@ -1750,6 +1752,7 @@ static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
 
 static int lan78xx_mdio_init(struct lan78xx_net *dev)
 {
+	struct device_node *node;
 	int ret;
 
 	dev->mdiobus = mdiobus_alloc();
@@ -1779,7 +1782,13 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
 		break;
 	}
 
-	ret = mdiobus_register(dev->mdiobus);
+	node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
+	if (node) {
+		ret = of_mdiobus_register(dev->mdiobus, node);
+		of_node_put(node);
+	} else {
+		ret = mdiobus_register(dev->mdiobus);
+	}
 	if (ret) {
 		netdev_err(dev->net, "can't register MDIO bus\n");
 		goto exit1;
@@ -2068,6 +2077,28 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
 	mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
 	phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
 
+	if (phydev->mdio.dev.of_node) {
+		u32 reg;
+		int len;
+
+		len = of_property_count_elems_of_size(phydev->mdio.dev.of_node,
+						      "microchip,led-modes",
+						      sizeof(u32));
+		if (len >= 0) {
+			/* Ensure the appropriate LEDs are enabled */
+			lan78xx_read_reg(dev, HW_CFG, &reg);
+			reg &= ~(HW_CFG_LED0_EN_ |
+				 HW_CFG_LED1_EN_ |
+				 HW_CFG_LED2_EN_ |
+				 HW_CFG_LED3_EN_);
+			reg |= (len > 0) * HW_CFG_LED0_EN_ |
+				(len > 1) * HW_CFG_LED1_EN_ |
+				(len > 2) * HW_CFG_LED2_EN_ |
+				(len > 3) * HW_CFG_LED3_EN_;
+			lan78xx_write_reg(dev, HW_CFG, reg);
+		}
+	}
+
 	genphy_config_aneg(phydev);
 
 	dev->fc_autoneg = phydev->autoneg;
@@ -2496,7 +2527,7 @@ static void lan78xx_init_stats(struct lan78xx_net *dev)
 	dev->stats.rollover_max.eee_tx_lpi_transitions = 0xFFFFFFFF;
 	dev->stats.rollover_max.eee_tx_lpi_time = 0xFFFFFFFF;
 
-	lan78xx_defer_kevent(dev, EVENT_STAT_UPDATE);
+	set_bit(EVENT_STAT_UPDATE, &dev->flags);
 }
 
 static int lan78xx_open(struct net_device *net)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index bd91d4bad49b..d22e104b9da7 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -27,6 +27,7 @@
 #include <linux/usb/cdc.h>
 #include <linux/suspend.h>
 #include <linux/acpi.h>
+#include <linux/of_net.h>
 
 /* Information for net-next */
 #define NETNEXT_VERSION		"09"
@@ -1214,6 +1215,7 @@ static int set_ethernet_addr(struct r8152 *tp)
 {
 	struct net_device *dev = tp->netdev;
 	struct sockaddr sa;
+	const u8 *mac_addr;
 	int ret;
 
 	if (tp->version == RTL_VER_01) {
@@ -1228,6 +1230,16 @@ static int set_ethernet_addr(struct r8152 *tp)
 			ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
 	}
 
+	/* maybe the boot loader passed the MAC address in devicetree */
+	mac_addr = of_get_mac_address(tp->udev->dev.of_node);
+	if (mac_addr) {
+		memcpy(sa.sa_data, mac_addr, 6);
+		ether_addr_copy(tp->netdev->dev_addr, sa.sa_data);
+		netif_info(tp, probe, dev, "OF ether addr %pM\n",
+			   sa.sa_data);
+		ret = 1;
+	}
+
 	if (ret < 0) {
 		netif_err(tp, probe, dev, "Get ether addr fail\n");
 	} else if (!is_valid_ether_addr(sa.sa_data)) {
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 166920ae23f8..4086ce684217 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -31,6 +31,7 @@ config WIRELESS_WDS
 	  necessary, give up on our plan of removing it).
 
 source "drivers/net/wireless/admtek/Kconfig"
+source "drivers/net/wireless/rtl8189es/Kconfig"
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/atmel/Kconfig"
 source "drivers/net/wireless/broadcom/Kconfig"
@@ -44,6 +45,7 @@ source "drivers/net/wireless/realtek/Kconfig"
 source "drivers/net/wireless/rsi/Kconfig"
 source "drivers/net/wireless/st/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
+source "drivers/net/wireless/xradio/Kconfig"
 source "drivers/net/wireless/zydas/Kconfig"
 source "drivers/net/wireless/quantenna/Kconfig"
 
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7fc96306712a..3d31b6f831d8 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/
+obj-$(CONFIG_RTL8189ES) += rtl8189es/
 obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/
 obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/
 obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/
@@ -17,6 +18,7 @@ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
 obj-$(CONFIG_WLAN_VENDOR_ST) += st/
 obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
+obj-$(CONFIG_WLAN_VENDOR_XRADIO) += xradio/
 obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
 obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 163ddc49f951..0b76a615708e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -71,6 +71,7 @@ struct brcmf_bus_dcmd {
  * @wowl_config: specify if dongle is configured for wowl when going to suspend
  * @get_ramsize: obtain size of device memory.
  * @get_memdump: obtain device memory dump in provided buffer.
+ * @get_fwname: obtain firmware name.
  *
  * This structure provides an abstract interface towards the
  * bus specific driver. For control messages to common driver
@@ -87,6 +88,8 @@ struct brcmf_bus_ops {
 	void (*wowl_config)(struct device *dev, bool enabled);
 	size_t (*get_ramsize)(struct device *dev);
 	int (*get_memdump)(struct device *dev, void *data, size_t len);
+	int (*get_fwname)(struct device *dev, uint chip, uint chiprev,
+			  unsigned char *fw_name);
 };
 
 
@@ -224,6 +227,13 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
 	return bus->ops->get_memdump(bus->dev, data, len);
 }
 
+static inline
+int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
+			 unsigned char *fw_name)
+{
+	return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
+}
+
 /*
  * interface functions from common layer
  */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 7a2b49587b4d..9be0b051066a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
+#include <linux/firmware.h>
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include "core.h"
@@ -28,6 +29,7 @@
 #include "tracepoint.h"
 #include "common.h"
 #include "of.h"
+#include "firmware.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -104,12 +106,137 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
 		brcmf_err("Set join_pref error (%d)\n", err);
 }
 
+static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
+			    struct brcmf_dload_data_le *dload_buf,
+			    u32 len)
+{
+	s32 err;
+
+	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
+	dload_buf->flag = cpu_to_le16(flag);
+	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
+	dload_buf->len = cpu_to_le32(len);
+	dload_buf->crc = cpu_to_le32(0);
+	len = sizeof(*dload_buf) + len - 1;
+
+	err = brcmf_fil_iovar_data_set(ifp, "clmload", dload_buf, len);
+
+	return err;
+}
+
+static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name)
+{
+	struct brcmf_bus *bus = ifp->drvr->bus_if;
+	struct brcmf_rev_info *ri = &ifp->drvr->revinfo;
+	u8 fw_name[BRCMF_FW_NAME_LEN];
+	u8 *ptr;
+	size_t len;
+	s32 err;
+
+	memset(fw_name, 0, BRCMF_FW_NAME_LEN);
+	err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name);
+	if (err) {
+		brcmf_err("get firmware name failed (%d)\n", err);
+		goto done;
+	}
+
+	/* generate CLM blob file name */
+	ptr = strrchr(fw_name, '.');
+	if (!ptr) {
+		err = -ENOENT;
+		goto done;
+	}
+
+	len = ptr - fw_name + 1;
+	if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) {
+		err = -E2BIG;
+	} else {
+		strlcpy(clm_name, fw_name, len);
+		strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN);
+	}
+done:
+	return err;
+}
+
+static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
+{
+	struct device *dev = ifp->drvr->bus_if->dev;
+	struct brcmf_dload_data_le *chunk_buf;
+	const struct firmware *clm = NULL;
+	u8 clm_name[BRCMF_FW_NAME_LEN];
+	u32 chunk_len;
+	u32 datalen;
+	u32 cumulative_len;
+	u16 dl_flag = DL_BEGIN;
+	u32 status;
+	s32 err;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	memset(clm_name, 0, BRCMF_FW_NAME_LEN);
+	err = brcmf_c_get_clm_name(ifp, clm_name);
+	if (err) {
+		brcmf_err("get CLM blob file name failed (%d)\n", err);
+		return err;
+	}
+
+	err = request_firmware(&clm, clm_name, dev);
+	if (err) {
+		brcmf_info("no clm_blob available(err=%d), device may have limited channels available\n",
+			   err);
+		return 0;
+	}
+
+	chunk_buf = kzalloc(sizeof(*chunk_buf) + MAX_CHUNK_LEN - 1, GFP_KERNEL);
+	if (!chunk_buf) {
+		err = -ENOMEM;
+		goto done;
+	}
+
+	datalen = clm->size;
+	cumulative_len = 0;
+	do {
+		if (datalen > MAX_CHUNK_LEN) {
+			chunk_len = MAX_CHUNK_LEN;
+		} else {
+			chunk_len = datalen;
+			dl_flag |= DL_END;
+		}
+		memcpy(chunk_buf->data, clm->data + cumulative_len, chunk_len);
+
+		err = brcmf_c_download(ifp, dl_flag, chunk_buf, chunk_len);
+
+		dl_flag &= ~DL_BEGIN;
+
+		cumulative_len += chunk_len;
+		datalen -= chunk_len;
+	} while ((datalen > 0) && (err == 0));
+
+	if (err) {
+		brcmf_err("clmload (%zu byte file) failed (%d); ",
+			  clm->size, err);
+		/* Retrieve clmload_status and print */
+		err = brcmf_fil_iovar_int_get(ifp, "clmload_status", &status);
+		if (err)
+			brcmf_err("get clmload_status failed (%d)\n", err);
+		else
+			brcmf_dbg(INFO, "clmload_status=%d\n", status);
+		err = -EIO;
+	}
+
+	kfree(chunk_buf);
+done:
+	release_firmware(clm);
+	return err;
+}
+
 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 {
 	s8 eventmask[BRCMF_EVENTING_MASK_LEN];
 	u8 buf[BRCMF_DCMD_SMLEN];
 	struct brcmf_rev_info_le revinfo;
 	struct brcmf_rev_info *ri;
+	char *clmver;
 	char *ptr;
 	s32 err;
 
@@ -148,6 +275,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 	}
 	ri->result = err;
 
+	/* Do any CLM downloading */
+	err = brcmf_c_process_clm_blob(ifp);
+	if (err < 0) {
+		brcmf_err("download CLM blob file failed, %d\n", err);
+		goto done;
+	}
+
 	/* query for 'ver' to get version info from firmware */
 	memset(buf, 0, sizeof(buf));
 	strcpy(buf, "ver");
@@ -167,6 +301,26 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 	ptr = strrchr(buf, ' ') + 1;
 	strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
 
+	/* Query for 'clmver' to get CLM version info from firmware */
+	memset(buf, 0, sizeof(buf));
+	err = brcmf_fil_iovar_data_get(ifp, "clmver", buf, sizeof(buf));
+	if (err) {
+		brcmf_dbg(TRACE, "retrieving clmver failed, %d\n", err);
+	} else {
+		clmver = (char *)buf;
+		/* store CLM version for adding it to revinfo debugfs file */
+		memcpy(ifp->drvr->clmver, clmver, sizeof(ifp->drvr->clmver));
+
+		/* Replace all newline/linefeed characters with space
+		 * character
+		 */
+		ptr = clmver;
+		while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL)
+			*ptr = ' ';
+
+		brcmf_dbg(INFO, "CLM version = %s\n", clmver);
+	}
+
 	/* set mpc */
 	err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
 	if (err) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 590bef2defb9..7dbd8d41e324 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -955,6 +955,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
 	seq_printf(s, "anarev: %u\n", ri->anarev);
 	seq_printf(s, "nvramrev: %08x\n", ri->nvramrev);
 
+	seq_printf(s, "clmver: %s\n", bus_if->drvr->clmver);
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index a4dd313140f3..ae39128406cb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -141,6 +141,8 @@ struct brcmf_pub {
 	struct notifier_block inetaddr_notifier;
 	struct notifier_block inet6addr_notifier;
 	struct brcmf_mp_device *settings;
+
+	u8 clmver[BRCMF_DCMD_SMLEN];
 };
 
 /* forward declarations */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 05bd636011ec..f4efd6187163 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -155,6 +155,21 @@
 #define BRCMF_MFP_CAPABLE		1
 #define BRCMF_MFP_REQUIRED		2
 
+/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each
+ * ioctl. It is relatively small because firmware has small maximum size input
+ * playload restriction for ioctls.
+ */
+#define MAX_CHUNK_LEN			1400
+
+#define DLOAD_HANDLER_VER		1	/* Downloader version */
+#define DLOAD_FLAG_VER_MASK		0xf000	/* Downloader version mask */
+#define DLOAD_FLAG_VER_SHIFT		12	/* Downloader version shift */
+
+#define DL_BEGIN			0x0002
+#define DL_END				0x0004
+
+#define DL_TYPE_CLM			2
+
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
 	BRCMF_JOIN_PREF_RSSI = 1,
@@ -826,6 +841,22 @@ struct brcmf_pno_macaddr_le {
 	u8 mac[ETH_ALEN];
 };
 
+/**
+ * struct brcmf_dload_data_le - data passing to firmware for downloading
+ * @flag: flags related to download data.
+ * @dload_type: type of download data.
+ * @len: length in bytes of download data.
+ * @crc: crc of download data.
+ * @data: download data.
+ */
+struct brcmf_dload_data_le {
+	__le16 flag;
+	__le16 dload_type;
+	__le32 len;
+	__le32 crc;
+	u8 data[1];
+};
+
 /**
  * struct brcmf_pno_bssid_le - bssid configuration for PNO scan.
  *
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index e6e9b00b79d7..3c87157f5b85 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -1350,6 +1350,24 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
 	return 0;
 }
 
+static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				 u8 *fw_name)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+	struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+	int ret = 0;
+
+	if (devinfo->fw_name[0] != '\0')
+		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_pcie_fwnames,
+						ARRAY_SIZE(brcmf_pcie_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
 
 static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.txdata = brcmf_pcie_tx,
@@ -1359,6 +1377,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.wowl_config = brcmf_pcie_wowl_config,
 	.get_ramsize = brcmf_pcie_get_ramsize,
 	.get_memdump = brcmf_pcie_get_memdump,
+	.get_fwname = brcmf_pcie_get_fwname,
 };
 
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index d198a8780b96..638b6fa2999c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -3980,6 +3980,24 @@ brcmf_sdio_watchdog(unsigned long data)
 	}
 }
 
+static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				 u8 *fw_name)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+	int ret = 0;
+
+	if (sdiodev->fw_name[0] != '\0')
+		strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_sdio_fwnames,
+						ARRAY_SIZE(brcmf_sdio_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
+
 static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.stop = brcmf_sdio_bus_stop,
 	.preinit = brcmf_sdio_bus_preinit,
@@ -3990,6 +4008,7 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.wowl_config = brcmf_sdio_wowl_config,
 	.get_ramsize = brcmf_sdio_bus_get_ramsize,
 	.get_memdump = brcmf_sdio_bus_get_memdump,
+	.get_fwname = brcmf_sdio_get_fwname,
 };
 
 static void brcmf_sdio_firmware_callback(struct device *dev, int err,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 4ad830b7b1c9..3310a73561fc 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1135,12 +1135,30 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
 		device_set_wakeup_enable(devinfo->dev, false);
 }
 
+static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				u8 *fw_name)
+{
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+	int ret = 0;
+
+	if (devinfo->fw_name[0] != '\0')
+		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_usb_fwnames,
+						ARRAY_SIZE(brcmf_usb_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
+
 static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
 	.txdata = brcmf_usb_tx,
 	.stop = brcmf_usb_down,
 	.txctl = brcmf_usb_tx_ctlpkt,
 	.rxctl = brcmf_usb_rx_ctlpkt,
 	.wowl_config = brcmf_usb_wowl_config,
+	.get_fwname = brcmf_usb_get_fwname,
 };
 
 static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
diff --git a/drivers/net/wireless/rtl8189es/Kconfig b/drivers/net/wireless/rtl8189es/Kconfig
new file mode 100644
index 000000000000..4b53bc8bff0d
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/Kconfig
@@ -0,0 +1,5 @@
+config RTL8189ES
+	tristate "Realtek 8189E SDIO WiFi"
+	depends on USB
+	---help---
+	  Help message of RTL8189ES
diff --git a/drivers/net/wireless/rtl8189es/Makefile b/drivers/net/wireless/rtl8189es/Makefile
new file mode 100644
index 000000000000..d44e822b2b17
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/Makefile
@@ -0,0 +1,1676 @@
+EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
+EXTRA_CFLAGS += -O1
+#EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -Wall
+#EXTRA_CFLAGS += -Wextra
+#EXTRA_CFLAGS += -Werror
+#EXTRA_CFLAGS += -pedantic
+#EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes
+
+EXTRA_CFLAGS += -Wno-unused-variable
+EXTRA_CFLAGS += -Wno-unused-value
+EXTRA_CFLAGS += -Wno-unused-label
+EXTRA_CFLAGS += -Wno-unused-parameter
+EXTRA_CFLAGS += -Wno-unused-function
+EXTRA_CFLAGS += -Wno-unused
+#EXTRA_CFLAGS += -Wno-uninitialized
+#EXTRA_CFLAGS += -Wno-error=date-time	# Fix compile error on gcc 4.9 and later
+
+EXTRA_CFLAGS += -I$(src)/include
+
+EXTRA_LDFLAGS += --strip-debug
+
+CONFIG_AUTOCFG_CP = n
+
+########################## WIFI IC ############################
+CONFIG_MULTIDRV = n
+CONFIG_RTL8188E = y
+CONFIG_RTL8812A = n
+CONFIG_RTL8821A = n
+CONFIG_RTL8192E = n
+CONFIG_RTL8723B = n
+CONFIG_RTL8814A = n
+CONFIG_RTL8703B = n
+CONFIG_RTL8188F = n
+######################### Interface ###########################
+CONFIG_USB_HCI = n
+CONFIG_PCI_HCI = n
+CONFIG_SDIO_HCI = y
+CONFIG_GSPI_HCI = n
+########################## Features ###########################
+CONFIG_MP_INCLUDED = y
+CONFIG_POWER_SAVING = y
+CONFIG_USB_AUTOSUSPEND = n
+CONFIG_HW_PWRP_DETECTION = n
+CONFIG_WIFI_TEST = n
+CONFIG_BT_COEXIST = n
+CONFIG_INTEL_WIDI = n
+CONFIG_WAPI_SUPPORT = n
+CONFIG_EFUSE_CONFIG_FILE = n
+CONFIG_EXT_CLK = n
+CONFIG_TRAFFIC_PROTECT = y
+CONFIG_LOAD_PHY_PARA_FROM_FILE = y
+CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY = n
+CONFIG_CALIBRATE_TX_POWER_TO_MAX = n
+CONFIG_RTW_ADAPTIVITY_EN = disable
+CONFIG_RTW_ADAPTIVITY_MODE = normal
+CONFIG_SIGNAL_SCALE_MAPPING = n
+CONFIG_80211W = n
+CONFIG_REDUCE_TX_CPU_LOADING = n
+CONFIG_BR_EXT = y
+CONFIG_ANTENNA_DIVERSITY = n
+CONFIG_TDLS = n
+CONFIG_WIFI_MONITOR = n
+######################## Wake On Lan ##########################
+CONFIG_WOWLAN = n
+CONFIG_GPIO_WAKEUP = n
+CONFIG_WAKEUP_GPIO_IDX = default
+CONFIG_HIGH_ACTIVE = n
+CONFIG_PNO_SUPPORT = n
+CONFIG_PNO_SET_DEBUG = n
+CONFIG_AP_WOWLAN = n
+######### Notify SDIO Host Keep Power During Syspend ##########
+CONFIG_RTW_SDIO_PM_KEEP_POWER = y
+###################### Platform Related #######################
+CONFIG_PLATFORM_I386_PC = n
+CONFIG_PLATFORM_ANDROID_X86 = n
+CONFIG_PLATFORM_ARM_NV_TK1 = n
+CONFIG_PLATFORM_ANDROID_INTEL_X86 = n
+CONFIG_PLATFORM_JB_X86 = n
+CONFIG_PLATFORM_ARM_S3C2K4 = n
+CONFIG_PLATFORM_ARM_PXA2XX = n
+CONFIG_PLATFORM_ARM_S3C6K4 = n
+CONFIG_PLATFORM_MIPS_RMI = n
+CONFIG_PLATFORM_RTD2880B = n
+CONFIG_PLATFORM_MIPS_AR9132 = n
+CONFIG_PLATFORM_RTK_DMP = n
+CONFIG_PLATFORM_MIPS_PLM = n
+CONFIG_PLATFORM_MSTAR389 = n
+CONFIG_PLATFORM_MT53XX = n
+CONFIG_PLATFORM_ARM_MX51_241H = n
+CONFIG_PLATFORM_FS_MX61 = n
+CONFIG_PLATFORM_ACTIONS_ATJ227X = n
+CONFIG_PLATFORM_TEGRA3_CARDHU = n
+CONFIG_PLATFORM_TEGRA4_DALMORE = n
+CONFIG_PLATFORM_ARM_TCC8900 = n
+CONFIG_PLATFORM_ARM_TCC8920 = n
+CONFIG_PLATFORM_ARM_TCC8920_JB42 = n
+CONFIG_PLATFORM_ARM_RK2818 = n
+CONFIG_PLATFORM_ARM_RK3066 = n
+CONFIG_PLATFORM_ARM_RK3188 = n
+CONFIG_PLATFORM_ARM_URBETTER = n
+CONFIG_PLATFORM_ARM_TI_PANDA = n
+CONFIG_PLATFORM_MIPS_JZ4760 = n
+CONFIG_PLATFORM_DMP_PHILIPS = n
+CONFIG_PLATFORM_MSTAR_TITANIA12 = n
+CONFIG_PLATFORM_MSTAR = n
+CONFIG_PLATFORM_SZEBOOK = n
+CONFIG_PLATFORM_ARM_SUNxI = n
+CONFIG_PLATFORM_ARM_SUN6I = n
+CONFIG_PLATFORM_ARM_SUN7I = n
+CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n
+CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n
+CONFIG_PLATFORM_ACTIONS_ATM702X = n
+CONFIG_PLATFORM_ACTIONS_ATV5201 = n
+CONFIG_PLATFORM_ACTIONS_ATM705X = n
+CONFIG_PLATFORM_ARM_RTD299X = n
+CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n
+CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n
+CONFIG_PLATFORM_ARM_WMT = n
+CONFIG_PLATFORM_TI_DM365 = n
+CONFIG_PLATFORM_MOZART = n
+CONFIG_PLATFORM_RTK119X = n
+CONFIG_PLATFORM_NOVATEK_NT72668 = n
+CONFIG_PLATFORM_HISILICON = n
+###############################################################
+
+CONFIG_DRVEXT_MODULE = n
+
+export TopDIR ?= $(shell pwd)
+
+########### COMMON  #################################
+ifeq ($(CONFIG_GSPI_HCI), y)
+HCI_NAME = gspi
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+HCI_NAME = sdio
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+HCI_NAME = usb
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+HCI_NAME = pci
+endif
+
+
+_OS_INTFS_FILES :=	os_dep/osdep_service.o \
+			os_dep/linux/os_intfs.o \
+			os_dep/linux/$(HCI_NAME)_intf.o \
+			os_dep/linux/$(HCI_NAME)_ops_linux.o \
+			os_dep/linux/ioctl_linux.o \
+			os_dep/linux/xmit_linux.o \
+			os_dep/linux/mlme_linux.o \
+			os_dep/linux/recv_linux.o \
+			os_dep/linux/ioctl_cfg80211.o \
+			os_dep/linux/rtw_cfgvendor.o \
+			os_dep/linux/wifi_regd.o \
+			os_dep/linux/rtw_android.o \
+			os_dep/linux/rtw_proc.o
+
+ifeq ($(CONFIG_MP_INCLUDED), y)
+_OS_INTFS_FILES += os_dep/linux/ioctl_mp.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o
+_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o
+endif
+
+ifeq ($(CONFIG_GSPI_HCI), y)
+_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o
+_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o
+endif
+
+
+_HAL_INTFS_FILES :=	hal/hal_intf.o \
+			hal/hal_com.o \
+			hal/hal_com_phycfg.o \
+			hal/hal_phy.o \
+			hal/hal_dm.o \
+			hal/hal_btcoex.o \
+			hal/hal_mp.o \
+			hal/hal_hci/hal_$(HCI_NAME).o \
+			hal/led/hal_$(HCI_NAME)_led.o
+
+			
+_OUTSRC_FILES := hal/phydm/phydm_debug.o	\
+		hal/phydm/phydm_antdiv.o\
+		hal/phydm/phydm_antdect.o\
+		hal/phydm/phydm_interface.o\
+		hal/phydm/phydm_hwconfig.o\
+		hal/phydm/phydm.o\
+		hal/phydm/halphyrf_ce.o\
+		hal/phydm/phydm_edcaturbocheck.o\
+		hal/phydm/phydm_dig.o\
+		hal/phydm/phydm_pathdiv.o\
+		hal/phydm/phydm_rainfo.o\
+		hal/phydm/phydm_dynamicbbpowersaving.o\
+		hal/phydm/phydm_powertracking_ce.o\
+		hal/phydm/phydm_dynamictxpower.o\
+		hal/phydm/phydm_adaptivity.o\
+		hal/phydm/phydm_cfotracking.o\
+		hal/phydm/phydm_noisemonitor.o\
+		hal/phydm/phydm_acs.o
+
+EXTRA_CFLAGS += -I$(src)/platform
+_PLATFORM_FILES := platform/platform_ops.o
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+EXTRA_CFLAGS += -I$(src)/hal/btc
+_OUTSRC_FILES += hal/btc/HalBtc8192e1Ant.o \
+				hal/btc/HalBtc8192e2Ant.o \
+				hal/btc/HalBtc8723b1Ant.o \
+				hal/btc/HalBtc8723b2Ant.o \
+				hal/btc/HalBtc8812a1Ant.o \
+				hal/btc/HalBtc8812a2Ant.o \
+				hal/btc/HalBtc8821a1Ant.o \
+				hal/btc/HalBtc8821a2Ant.o \
+				hal/btc/HalBtc8821aCsr2Ant.o \
+				hal/btc/HalBtc8703b1Ant.o \
+				hal/btc/HalBtc8703b2Ant.o 
+endif
+
+
+########### HAL_RTL8188E #################################
+ifeq ($(CONFIG_RTL8188E), y)
+
+RTL871X = rtl8188e
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8189es
+endif
+
+ifeq ($(CONFIG_GSPI_HCI), y)
+MODULE_NAME = 8189es
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8188eu
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8188ee
+endif
+EXTRA_CFLAGS += -DCONFIG_RTL8188E
+
+_HAL_INTFS_FILES +=	hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8188EPwrSeq.o\
+ 					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o
+endif
+
+#hal/OUTSRC/$(RTL871X)/Hal8188EFWImg_CE.o
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\
+		hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\
+		hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\
+		hal/phydm/$(RTL871X)/halhwimg8188e_t_fw.o\
+		hal/phydm/$(RTL871X)/halhwimg8188e_s_fw.o\
+		hal/phydm/$(RTL871X)/halphyrf_8188e_ce.o\
+		hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\
+		hal/phydm/$(RTL871X)/hal8188erateadaptive.o\
+		hal/phydm/$(RTL871X)/phydm_rtl8188e.o
+
+endif
+
+########### HAL_RTL8192E #################################
+ifeq ($(CONFIG_RTL8192E), y)
+
+RTL871X = rtl8192e
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8192es
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8192eu
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8192ee
+endif
+EXTRA_CFLAGS += -DCONFIG_RTL8192E
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8192EPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_PCIE.o
+endif
+
+#hal/OUTSRC/$(RTL871X)/HalHWImg8188E_FW.o
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\
+		hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\
+		hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\
+		hal/phydm/$(RTL871X)/halhwimg8192e_fw.o\
+		hal/phydm/$(RTL871X)/halphyrf_8192e_ce.o\
+		hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\
+		hal/phydm/$(RTL871X)/phydm_rtl8192e.o
+
+endif
+
+########### HAL_RTL8812A_RTL8821A #################################
+
+ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n)
+
+RTL871X = rtl8812a
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8812au
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8812ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8812as
+endif
+
+_HAL_INTFS_FILES +=  hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8812PwrSeq.o \
+					hal/$(RTL871X)/Hal8821APwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_RTL8812A), y)
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o
+endif
+endif
+ifeq ($(CONFIG_RTL8821A), y)
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o
+endif
+endif
+
+ifeq ($(CONFIG_RTL8812A), y)
+EXTRA_CFLAGS += -DCONFIG_RTL8812A
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_fw.o\
+		hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\
+		hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\
+		hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\
+		hal/phydm/$(RTL871X)/halphyrf_8812a_ce.o\
+		hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\
+		hal/phydm/$(RTL871X)/phydm_rtl8812a.o
+endif
+
+ifeq ($(CONFIG_RTL8821A), y)
+
+ifeq ($(CONFIG_RTL8812A), n)
+
+RTL871X = rtl8821a
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME := 8821au
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME := 8821ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME := 8821as
+endif
+
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8821A
+_OUTSRC_FILES += hal/phydm/rtl8821a/halhwimg8821a_fw.o\
+		hal/phydm/rtl8821a/halhwimg8821a_mac.o\
+		hal/phydm/rtl8821a/halhwimg8821a_bb.o\
+		hal/phydm/rtl8821a/halhwimg8821a_rf.o\
+		hal/phydm/rtl8812a/halphyrf_8812a_ce.o\
+		hal/phydm/rtl8821a/halphyrf_8821a_ce.o\
+		hal/phydm/rtl8821a/phydm_regconfig8821a.o\
+		hal/phydm/rtl8821a/phydm_rtl8821a.o\
+		hal/phydm/rtl8821a/phydm_iqk_8821a_ce.o
+endif
+
+
+endif
+
+########### HAL_RTL8723B #################################
+ifeq ($(CONFIG_RTL8723B), y)
+
+RTL871X = rtl8723b
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8723bu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8723be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8723bs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8723B
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8723BPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o
+endif
+
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\
+								hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\
+								hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\
+								hal/phydm/$(RTL871X)/halhwimg8723b_fw.o\
+								hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\
+								hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\
+								hal/phydm/$(RTL871X)/halphyrf_8723b_ce.o\
+								hal/phydm/$(RTL871X)/phydm_rtl8723b.o
+
+endif
+
+########### HAL_RTL8814A #################################
+ifeq ($(CONFIG_RTL8814A), y)
+
+RTL871X = rtl8814a
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8814au
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8814ae
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8814as
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8814A
+
+_HAL_INTFS_FILES +=  hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8814PwrSeq.o \
+					hal/$(RTL871X)/$(RTL871X)_xmit.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+ifeq ($(CONFIG_GSPI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+endif
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o
+endif
+
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\
+								hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\
+								hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\
+								hal/phydm/$(RTL871X)/halhwimg8814a_fw.o\
+								hal/phydm/$(RTL871X)/phydm_iqk_8814a.o\
+								hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\
+								hal/phydm/$(RTL871X)/halphyrf_8814a_ce.o\
+								hal/phydm/$(RTL871X)/phydm_rtl8814a.o
+
+endif
+
+
+########### HAL_RTL8703B #################################
+ifeq ($(CONFIG_RTL8703B), y)
+
+RTL871X = rtl8703b
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8703bu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8703be
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8703bs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8703B
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8703BPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o
+endif
+
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\
+								hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\
+								hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\
+								hal/phydm/$(RTL871X)/halhwimg8703b_fw.o\
+								hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\
+								hal/phydm/$(RTL871X)/halphyrf_8703b.o
+endif
+
+########### HAL_RTL8188F #################################
+ifeq ($(CONFIG_RTL8188F), y)
+
+RTL871X = rtl8188f
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME = 8188fu
+endif
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME = 8188fe
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME = 8189fs
+endif
+
+EXTRA_CFLAGS += -DCONFIG_RTL8188F
+
+_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \
+					hal/$(RTL871X)/Hal8188FPwrSeq.o\
+					hal/$(RTL871X)/$(RTL871X)_sreset.o
+
+_HAL_INTFS_FILES +=	hal/$(RTL871X)/$(RTL871X)_hal_init.o \
+			hal/$(RTL871X)/$(RTL871X)_phycfg.o \
+			hal/$(RTL871X)/$(RTL871X)_rf6052.o \
+			hal/$(RTL871X)/$(RTL871X)_dm.o \
+			hal/$(RTL871X)/$(RTL871X)_rxdesc.o \
+			hal/$(RTL871X)/$(RTL871X)_cmd.o \
+
+
+_HAL_INTFS_FILES +=	\
+			hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \
+			hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o
+
+ifeq ($(CONFIG_PCI_HCI), y)
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o
+else
+_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o
+endif
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o
+endif
+
+_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\
+								hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\
+								hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\
+								hal/phydm/$(RTL871X)/halhwimg8188f_fw.o\
+								hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\
+								hal/phydm/$(RTL871X)/halphyrf_8188f.o \
+								hal/phydm/$(RTL871X)/phydm_rtl8188f.o
+
+endif
+
+########### AUTO_CFG  #################################
+
+ifeq ($(CONFIG_AUTOCFG_CP), y)
+
+ifeq ($(CONFIG_MULTIDRV), y)
+$(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else
+ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy)
+$(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy)
+$(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+else
+$(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h)
+endif
+endif
+
+endif
+
+########### END OF PATH  #################################
+
+
+ifeq ($(CONFIG_USB_HCI), y)
+ifeq ($(CONFIG_USB_AUTOSUSPEND), y)
+EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND
+endif
+endif
+
+ifeq ($(CONFIG_MP_INCLUDED), y)
+#MODULE_NAME := $(MODULE_NAME)_mp
+EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED
+endif
+
+ifeq ($(CONFIG_POWER_SAVING), y)
+EXTRA_CFLAGS += -DCONFIG_POWER_SAVING
+endif
+
+ifeq ($(CONFIG_HW_PWRP_DETECTION), y)
+EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION
+endif
+
+ifeq ($(CONFIG_WIFI_TEST), y)
+EXTRA_CFLAGS += -DCONFIG_WIFI_TEST
+endif
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+EXTRA_CFLAGS += -DCONFIG_BT_COEXIST
+endif
+
+ifeq ($(CONFIG_INTEL_WIDI), y)
+EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI
+endif
+
+ifeq ($(CONFIG_WAPI_SUPPORT), y)
+EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT
+endif
+
+
+ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y)
+EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE
+
+#EFUSE_MAP_PATH
+USER_EFUSE_MAP_PATH ?=
+ifneq ($(USER_EFUSE_MAP_PATH),)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\"
+else ifeq ($(MODULE_NAME), 8189es)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\"
+else ifeq ($(MODULE_NAME), 8723bs)
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\"
+else
+EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\"
+endif
+
+#WIFIMAC_PATH
+USER_WIFIMAC_PATH ?=
+ifneq ($(USER_WIFIMAC_PATH),)
+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\"
+else
+EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\"
+endif
+
+endif
+
+ifeq ($(CONFIG_EXT_CLK), y)
+EXTRA_CFLAGS += -DCONFIG_EXT_CLK
+endif
+
+ifeq ($(CONFIG_TRAFFIC_PROTECT), y)
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+endif
+
+ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y)
+EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE
+#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\"
+EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"\"
+endif
+
+ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y)
+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY
+endif
+
+ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y)
+EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX
+endif
+
+ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0
+else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1
+endif
+
+ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0
+else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense)
+EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1
+endif
+
+ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y)
+EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING
+endif
+
+ifeq ($(CONFIG_80211W), y)
+EXTRA_CFLAGS += -DCONFIG_IEEE80211W
+endif
+
+ifeq ($(CONFIG_WOWLAN), y)
+EXTRA_CFLAGS += -DCONFIG_WOWLAN
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_AP_WOWLAN), y)
+EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_PNO_SUPPORT), y)
+EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT
+ifeq ($(CONFIG_PNO_SET_DEBUG), y)
+EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG
+endif
+endif
+
+ifeq ($(CONFIG_GPIO_WAKEUP), y)
+EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP
+ifeq ($(CONFIG_HIGH_ACTIVE), y)
+EXTRA_CFLAGS += -DHIGH_ACTIVE=1
+else
+EXTRA_CFLAGS += -DHIGH_ACTIVE=0
+endif
+endif
+
+ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default)
+EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX)
+endif
+
+ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y)
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER
+endif
+endif
+
+ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y)
+EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING
+endif
+
+ifeq ($(CONFIG_BR_EXT), y)
+BR_NAME = br0
+EXTRA_CFLAGS += -DCONFIG_BR_EXT
+EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"'
+endif
+
+ifeq ($(CONFIG_ANTENNA_DIVERSITY), y)
+EXTRA_CFLAGS += -DCONFIG_ANTENNA_DIVERSITY
+endif
+
+ifeq ($(CONFIG_TDLS), y)
+EXTRA_CFLAGS += -DCONFIG_TDLS
+endif
+
+ifeq ($(CONFIG_WIFI_MONITOR), y)
+EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR
+endif
+
+EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04
+
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_PLATFORM_I386_PC), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH ?= $(SUBARCH)
+CROSS_COMPILE ?=
+KVER  := $(shell uname -r)
+KSRC := /lib/modules/$(KVER)/build
+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
+INSTALL_PREFIX :=
+endif
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X
+#ARCH := arm
+ARCH := $(R_ARCH)
+#CROSS_COMPILE := arm-none-linux-gnueabi-
+CROSS_COMPILE := $(R_CROSS_COMPILE)
+KVER:= 3.4.0
+#KSRC := ../../../../build/out/kernel
+KSRC := $(KERNEL_BUILD_PATH)
+MODULE_NAME :=wlan
+endif
+
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_arm_act_sdio.o
+endif
+
+ARCH := arm
+CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi-
+KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_TI_AM3517), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE
+CROSS_COMPILE := arm-eabi-
+KSRC := $(shell pwd)/../../../Android/kernel
+ARCH := arm
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12
+ARCH:=mips
+CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu-
+KVER:= 2.6.28.9
+KSRC:= /usr/src/Mstar_kernel/2.6.28.9/
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR), y)
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER -DCONFIG_PREALLOC_RX_SKB_BUFFER
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH
+ARCH:=arm
+CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi-
+KVER:= 3.1.10
+KSRC:= /usr/src/Mstar_kernel/3.1.10/
+endif
+
+ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH := $(SUBARCH)
+CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu-
+KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_JB_X86), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH := $(SUBARCH)
+CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android-
+KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_NV_TK1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_PLATFORM_ANDROID
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+EXTRA_CFLAGS += -DRTW_VENDOR_EXT_SUPPORT
+ARCH := arm
+CROSS_COMPILE := /mnt/newdisk/isaac/nvidia/android_ara_5.1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
+KSRC :=/mnt/newdisk/isaac/nvidia/android_ara_5.1/out/target/product/jetson/obj/kernel/
+MODULE_NAME = wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-none-linux-gnueabi-
+KVER  := 2.6.34.1
+KSRC ?= /usr/src/linux-2.6.34.1
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-linux-
+KVER  := 2.6.24.7_$(ARCH)
+KSRC := /usr/src/kernels/linux-$(KVER)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := arm-none-linux-gnueabi-
+KVER  := 2.6.34.1
+KSRC ?= /usr/src/linux-2.6.34.1
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTD2880B), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B
+ARCH:=
+CROSS_COMPILE:=
+KVER:=
+KSRC:=
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH:=mips
+CROSS_COMPILE:=mipsisa32r2-uclibc-
+KVER:=
+KSRC:= /root/work/kernel_realtek
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH:=mips
+CROSS_COMPILE:=mipsisa32r2-uclibc-
+KVER:=
+KSRC:= /root/work/kernel_realtek
+endif
+
+ifeq ($(CONFIG_PLATFORM_MSTAR389), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389
+ARCH:=mips
+CROSS_COMPILE:= mips-linux-gnu-
+KVER:= 2.6.28.10
+KSRC:= /home/mstar/mstar_linux/2.6.28.9/
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH := mips
+CROSS_COMPILE := mips-openwrt-linux-
+KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9
+endif
+
+ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM
+ARCH := mips
+#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux-
+CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux-
+KSRC ?=/usr/local/Jupiter/linux-2.6.12
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTK_DMP), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM  -DCONFIG_WIRELESS_EXT
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+_PLATFORM_FILES += platform/platform_RTK_DMP_usb.o
+endif
+ARCH:=mips
+CROSS_COMPILE:=mipsel-linux-
+KVER:=
+KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12
+endif
+
+ifeq ($(CONFIG_PLATFORM_MT53XX), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX
+ARCH:= arm
+CROSS_COMPILE:= arm11_mtk_le-
+KVER:= 2.6.27
+KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM
+ARCH := arm
+CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-
+KVER  := 2.6.31
+KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source
+endif
+
+ifeq ($(CONFIG_PLATFORM_FS_MX61), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/share/CusEnv/FreeScale/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC ?= /home/share/CusEnv/FreeScale/FS_kernel_env
+endif
+
+
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X
+ARCH := mips
+CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu-
+KVER  := 2.6.27
+KSRC := /home/cnsd4/project/actions/linux-2.6.27.28
+endif
+
+ifeq ($(CONFIG_PLATFORM_TI_DM365), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX
+EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF
+ARCH := arm
+#CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-
+#KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365
+CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux-
+KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18
+KERNELOUTPUT := ${PRODUCTDIR}/tmp
+KVER  := 2.6.18
+endif
+
+ifeq ($(CONFIG_PLATFORM_MOZART), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART
+ARCH := arm
+CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux-
+KVER  := $(shell uname -r)
+KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17
+KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS
+ARCH := arm
+CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
+KSRC := /usr/src/release_fae_version/kernel25_A7_281x
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+# default setting for Power control
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
+# default setting for Special function
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /home/android_sdk/Rockchip/Rk3188/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
+endif
+EXTRA_CFLAGS += -fno-pic
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-
+#CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-
+KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel
+MODULE_NAME :=wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH := arm
+CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi-
+KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH := arm
+#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104
+CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+KSRC := /media/DATA-1/android-4.0/panda_kernel/omap
+MODULE_NAME := wlan
+endif
+
+ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE
+ARCH ?= mips
+CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu-
+KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel
+endif
+
+ifeq ($(CONFIG_PLATFORM_SZEBOOK), y)
+EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN
+ARCH:=arm
+CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi-
+KVER:= 2.6.31.6
+KSRC:= ../code/linux-2.6.31.6-2020/
+endif
+
+#Add setting for MN10300
+ifeq ($(CONFIG_PLATFORM_MN10300), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MN10300
+ARCH := mn10300
+CROSS_COMPILE := mn10300-linux-
+KVER := 2.6.32.2
+KSRC := /home/winuser/work/Plat_sLD2T_V3010/usr/src/linux-2.6.32.2
+INSTALL_PREFIX :=
+endif
+
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DDCONFIG_P2P_IPS
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default setting for A10-EVB mmc0
+#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o
+endif
+
+ARCH := arm
+#CROSS_COMPILE := arm-none-linux-gnueabi-
+CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi-
+KVER  := 3.0.8
+#KSRC:= ../lichee/linux-3.0/
+KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+# default setting for A31-EVB mmc0
+EXTRA_CFLAGS += -DCONFIG_A31_EVB
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+#Android-JB42
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3
+#ifeq ($(CONFIG_USB_HCI), y)
+#MODULE_NAME := 8188eu_sw
+#endif
+# ==== Cross compile setting for kitkat-a3x_v4.5 =====
+CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android 4.2 SDK ===
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3
+# ==== Cross compile setting for Android 4.3 SDK =====
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4
+# ==== Cross compile setting for kitkat-a20_v4.4 =====
+CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android 4.2 SDK ===
+#CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+#KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4
+# ===Cross compile setting for Android 4.4 SDK ===
+CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+
+# Enable this for Android 5.0
+EXTRA_CFLAGS += -DCONFIG_RADIO_WORK
+
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+# ===Cross compile setting for Android L SDK ===
+CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-
+KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4
+endif
+
+ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201
+EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP
+ARCH := mips
+CROSS_COMPILE := mipsel-linux-gnu-
+KVER  := $(KERNEL_VER)
+KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER)
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DUSB_XMITBUF_ALIGN_SZ=1024 -DUSB_PACKET_OFFSET_SZ=0
+#ARCH, CROSS_COMPILE, KSRC,and  MODDESTDIR are provided by external makefile
+INSTALL_PREFIX :=
+endif
+
+ifeq ($(CONFIG_PLATFORM_HISILICON), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON
+ifeq ($(SUPPORT_CONCURRENT),y)
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+endif
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_P2P_IPS
+ARCH := arm
+ifeq ($(CROSS_COMPILE),)
+       CROSS_COMPILE = arm-hisiv200-linux-
+endif
+MODULE_NAME := rtl8192eu
+ifeq ($(KSRC),)
+       KSRC := ../../../../../../kernel/linux-3.4.y
+endif
+endif
+
+# Platform setting
+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y)
+ifeq ($(CONFIG_ANDROID_2X), y)
+EXTRA_CFLAGS += -DANDROID_2X
+endif
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD
+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ifeq ($(RTL871X), rtl8188e)
+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_sprd_sdio.o
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y)
+ifeq ($(CONFIG_ANDROID_2X), y)
+EXTRA_CFLAGS += -DANDROID_2X
+endif
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD
+EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+ifeq ($(RTL871X), rtl8188e)
+EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+_PLATFORM_FILES += platform/platform_sprd_sdio.o
+endif
+endif
+
+ifeq ($(CONFIG_PLATFORM_ARM_WMT), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o
+endif
+ARCH := arm
+CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le-
+KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/
+MODULE_NAME :=8189es_kk
+endif
+
+ifeq ($(CONFIG_PLATFORM_RTK119X), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+#EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I
+EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT
+# default setting for Android 4.1, 4.2
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+#EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION
+EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION
+
+#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS
+ifeq ($(CONFIG_USB_HCI), y)
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o
+endif
+ifeq ($(CONFIG_SDIO_HCI), y)
+_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o
+endif
+
+ARCH := arm
+
+# ==== Cross compile setting for Android 4.4 SDK =====
+#CROSS_COMPILE := arm-linux-gnueabihf-
+KVER  := 3.10.24
+#KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4
+CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf-
+KSRC := /home/realtek/software_phoenix/linux-kernel
+MODULE_NAME := 8192eu
+
+endif
+
+ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y)
+EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DDCONFIG_P2P_IPS
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX
+EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX
+ARCH ?= arm
+CROSS_COMPILE := arm-linux-gnueabihf-
+KVER := 3.8.0
+KSRC := /Custom/Novatek/TCL/linux-3.8_header
+#KSRC := $(KERNELDIR)
+endif
+
+ifeq ($(CONFIG_MULTIDRV), y)
+
+ifeq ($(CONFIG_SDIO_HCI), y)
+MODULE_NAME := rtw_sdio
+endif
+
+ifeq ($(CONFIG_USB_HCI), y)
+MODULE_NAME := rtw_usb
+endif
+
+ifeq ($(CONFIG_PCI_HCI), y)
+MODULE_NAME := rtw_pci
+endif
+
+
+endif
+
+USER_MODULE_NAME ?=
+ifneq ($(USER_MODULE_NAME),)
+MODULE_NAME := $(USER_MODULE_NAME)
+endif
+
+ifneq ($(KERNELRELEASE),)
+
+rtk_core :=	core/rtw_cmd.o \
+		core/rtw_security.o \
+		core/rtw_debug.o \
+		core/rtw_io.o \
+		core/rtw_ioctl_query.o \
+		core/rtw_ioctl_set.o \
+		core/rtw_ieee80211.o \
+		core/rtw_mlme.o \
+		core/rtw_mlme_ext.o \
+		core/rtw_wlan_util.o \
+		core/rtw_vht.o \
+		core/rtw_pwrctrl.o \
+		core/rtw_rf.o \
+		core/rtw_recv.o \
+		core/rtw_sta_mgt.o \
+		core/rtw_ap.o \
+		core/rtw_xmit.o	\
+		core/rtw_p2p.o \
+		core/rtw_tdls.o \
+		core/rtw_br_ext.o \
+		core/rtw_iol.o \
+		core/rtw_sreset.o \
+		core/rtw_btcoex.o \
+		core/rtw_beamforming.o \
+		core/rtw_odm.o \
+		core/efuse/rtw_efuse.o 
+
+$(MODULE_NAME)-y += $(rtk_core)
+
+$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o
+
+$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o	\
+					core/rtw_wapi_sms4.o
+
+$(MODULE_NAME)-y += $(_OS_INTFS_FILES)
+$(MODULE_NAME)-y += $(_HAL_INTFS_FILES)
+$(MODULE_NAME)-y += $(_OUTSRC_FILES)
+$(MODULE_NAME)-y += $(_PLATFORM_FILES)
+
+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o \
+					core/rtw_mp_ioctl.o
+
+ifeq ($(CONFIG_RTL8723B), y)
+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o
+endif
+ifeq ($(CONFIG_RTL8821A), y)
+$(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o
+endif
+
+obj-$(CONFIG_RTL8189ES) := $(MODULE_NAME).o
+
+else
+
+export CONFIG_RTL8189ES = m
+
+all: modules
+
+modules:
+	$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd)  modules
+
+strip:
+	$(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded
+
+install:
+	install -p -m 644 $(MODULE_NAME).ko  $(MODDESTDIR)
+	/sbin/depmod -a ${KVER}
+
+uninstall:
+	rm -f $(MODDESTDIR)/$(MODULE_NAME).ko
+	/sbin/depmod -a ${KVER}
+
+config_r:
+	@echo "make config"
+	/bin/bash script/Configure script/config.in
+
+
+.PHONY: modules clean
+
+clean:
+	cd hal/phydm/ ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko
+	cd hal/phydm/ ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd hal/led ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko
+	cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko
+	cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko
+	rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order
+	rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~
+	rm -fr .tmp_versions
+endif
+
diff --git a/drivers/net/wireless/rtl8189es/clean b/drivers/net/wireless/rtl8189es/clean
new file mode 100644
index 000000000000..87664218b889
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/clean
@@ -0,0 +1,5 @@
+#!/bin/bash
+rmmod 8192cu
+rmmod 8192ce
+rmmod 8192du
+rmmod 8192de
diff --git a/drivers/net/wireless/rtl8189es/core/efuse/rtw_efuse.c b/drivers/net/wireless/rtl8189es/core/efuse/rtw_efuse.c
new file mode 100644
index 000000000000..d664ef75387e
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/efuse/rtw_efuse.c
@@ -0,0 +1,1672 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_EFUSE_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#include "../hal/efuse/efuse_mask.h"
+
+/*------------------------Define local variable------------------------------*/
+u8	fakeEfuseBank=0;
+u32	fakeEfuseUsedBytes=0;
+u8	fakeEfuseContent[EFUSE_MAX_HW_SIZE]={0};
+u8	fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]={0};
+u8	fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]={0};
+
+u32	BTEfuseUsedBytes=0;
+u8	BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8	BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0};
+u8	BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0};
+
+u32	fakeBTEfuseUsedBytes=0;
+u8	fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8	fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]={0};
+u8	fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]={0};
+
+u8 	maskfileBuffer[32];
+/*------------------------Define local variable------------------------------*/
+
+//------------------------------------------------------------------------------
+#define REG_EFUSE_CTRL		0x0030
+#define EFUSE_CTRL			REG_EFUSE_CTRL		// E-Fuse Control.
+//------------------------------------------------------------------------------
+
+BOOLEAN
+Efuse_Read1ByteFromFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN OUT	u8		*Value	);
+BOOLEAN
+Efuse_Read1ByteFromFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN OUT	u8		*Value	)
+{
+	if(Offset >= EFUSE_MAX_HW_SIZE)
+	{
+		return _FALSE;
+	}
+	//DbgPrint("Read fake content, offset = %d\n", Offset);
+	if(fakeEfuseBank == 0)
+		*Value = fakeEfuseContent[Offset];
+	else
+		*Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset];
+	return _TRUE;
+}
+
+BOOLEAN
+Efuse_Write1ByteToFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN 		u8		Value	);
+BOOLEAN
+Efuse_Write1ByteToFakeContent(
+	IN		PADAPTER	pAdapter,
+	IN		u16		Offset,
+	IN 		u8		Value	)
+{
+	if(Offset >= EFUSE_MAX_HW_SIZE)
+	{
+		return _FALSE;
+	}
+	if(fakeEfuseBank == 0)
+		fakeEfuseContent[Offset] = Value;
+	else
+	{
+		fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value;
+	}
+	return _TRUE;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_PowerSwitch
+ *
+ * Overview:	When we want to enable write operation, we should change to 
+ *				pwr on state. When we stop write, we should switch to 500k mode
+ *				and disable LDO 2.5V.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/17/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID
+Efuse_PowerSwitch(
+	IN	PADAPTER	pAdapter,
+	IN	u8		bWrite,
+	IN	u8		PwrState)
+{
+	pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState);
+}
+
+VOID
+BTEfuse_PowerSwitch(
+	IN	PADAPTER	pAdapter,
+	IN	u8		bWrite,
+	IN	u8		PwrState)
+{
+	if(pAdapter->HalFunc.BTEfusePowerSwitch)
+		pAdapter->HalFunc.BTEfusePowerSwitch(pAdapter, bWrite, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_GetCurrentSize
+ *
+ * Overview:	Get current efuse size!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize(
+	IN PADAPTER		pAdapter,
+	IN u8			efuseType,
+	IN BOOLEAN		bPseudoTest)
+{
+	u16 ret=0;
+
+	ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, bPseudoTest);
+
+	return ret;
+}
+
+/*  11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(IN u8	word_en)
+{
+	u8 word_cnts = 0;
+	if(!(word_en & BIT(0)))	word_cnts++; // 0 : write enable
+	if(!(word_en & BIT(1)))	word_cnts++;
+	if(!(word_en & BIT(2)))	word_cnts++;
+	if(!(word_en & BIT(3)))	word_cnts++;
+	return word_cnts;
+}
+
+//
+//	Description:
+//		Execute E-Fuse read byte operation.
+//		Refered from SD1 Richard.
+//
+//	Assumption:
+//		1. Boot from E-Fuse and successfully auto-load.
+//		2. PASSIVE_LEVEL (USB interface)
+//
+//	Created by Roger, 2008.10.21.
+//
+VOID
+ReadEFuseByte(
+		PADAPTER	Adapter,
+		u16 			_offset, 
+		u8 			*pbuf, 
+		IN BOOLEAN	bPseudoTest) 
+{
+	u32	value32;
+	u8	readbyte;
+	u16	retry;
+	//u32 start=rtw_get_current_time();
+
+	if(bPseudoTest)
+	{
+		Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf);
+		return;
+	}
+	if (IS_HARDWARE_TYPE_8723B(Adapter))
+	{
+		// <20130121, Kordan> For SMIC S55 EFUSE specificatoin.
+		//0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8])
+		PHY_SetMacReg(Adapter, EFUSE_TEST, BIT11, 0);
+	}
+	//Write Address
+	rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff));  		
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL+2);
+	rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));  		
+
+	//Write bit 32 0
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL+3);		
+	rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f));  	
+	
+	//Check bit 32 read-ready
+	retry = 0;
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+	//while(!(((value32 >> 24) & 0xff) & 0x80)  && (retry<10))
+	while(!(((value32 >> 24) & 0xff) & 0x80)  && (retry<10000))
+	{
+		value32 = rtw_read32(Adapter, EFUSE_CTRL);
+		retry++;
+	}
+
+	// 20100205 Joseph: Add delay suggested by SD1 Victor.
+	// This fix the problem that Efuse read error in high temperature condition.
+	// Designer says that there shall be some delay after ready bit is set, or the
+	// result will always stay on last data we read.
+	rtw_udelay_os(50);
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+	
+	*pbuf = (u8)(value32 & 0xff);
+	//DBG_871X("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,rtw_get_passing_time_ms(start));
+	
+}
+
+//
+//	Description:
+//		1. Execute E-Fuse read byte operation according as map offset and 
+//		    save to E-Fuse table.
+//		2. Refered from SD1 Richard.
+//
+//	Assumption:
+//		1. Boot from E-Fuse and successfully auto-load.
+//		2. PASSIVE_LEVEL (USB interface)
+//
+//	Created by Roger, 2008.10.21.
+//
+//	2008/12/12 MH 	1. Reorganize code flow and reserve bytes. and add description.
+//					2. Add efuse utilization collect.
+//	2008/12/22 MH	Read Efuse must check if we write section 1 data again!!! Sec1
+//					write addr must be after sec5.
+//
+
+VOID
+efuse_ReadEFuse(
+	PADAPTER	Adapter,
+	u8		efuseType,
+	u16		_offset,
+	u16 		_size_byte,
+	u8      	*pbuf,
+	IN	BOOLEAN	bPseudoTest
+	);
+VOID
+efuse_ReadEFuse(
+	PADAPTER	Adapter,
+	u8		efuseType,
+	u16		_offset,
+	u16 		_size_byte,
+	u8      	*pbuf,
+	IN	BOOLEAN	bPseudoTest
+	)
+{
+	Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+VOID
+EFUSE_GetEfuseDefinition(
+	IN		PADAPTER	pAdapter,
+	IN		u8		efuseType,
+	IN		u8		type,
+	OUT		void		*pOut,
+	IN		BOOLEAN		bPseudoTest
+	)
+{
+	pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, bPseudoTest);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_Read1Byte
+ *
+ * Overview:	Copy from WMAC fot EFUSE read 1 byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 09/23/2008 	MHC		Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+u8
+EFUSE_Read1Byte(	
+	IN	PADAPTER	Adapter, 
+	IN	u16		Address)
+{
+	u8	data;
+	u8	Bytetemp = {0x00};
+	u8	temp = {0x00};
+	u32	k=0;
+	u16	contentLen=0;
+
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&contentLen, _FALSE);
+
+	if (Address < contentLen)	//E-fuse 512Byte
+	{
+		//Write E-fuse Register address bit0~7
+		temp = Address & 0xFF;	
+		rtw_write8(Adapter, EFUSE_CTRL+1, temp);	
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);	
+		//Write E-fuse Register address bit8~9
+		temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);	
+		rtw_write8(Adapter, EFUSE_CTRL+2, temp);	
+
+		//Write 0x30[31]=0
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		temp = Bytetemp & 0x7F;
+		rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+		//Wait Write-ready (0x30[31]=1)
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		while(!(Bytetemp & 0x80))
+		{				
+			Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+			k++;
+			if(k==1000)
+			{
+				k=0;
+				break;
+			}
+		}
+		data=rtw_read8(Adapter, EFUSE_CTRL);
+		return data;
+	}
+	else
+		return 0xFF;
+	
+}/* EFUSE_Read1Byte */
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_Write1Byte
+ *
+ * Overview:	Copy from WMAC fot EFUSE write 1 byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 09/23/2008 	MHC		Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+
+void	
+EFUSE_Write1Byte(	
+	IN	PADAPTER	Adapter, 
+	IN	u16		Address,
+	IN	u8		Value);
+void	
+EFUSE_Write1Byte(	
+	IN	PADAPTER	Adapter, 
+	IN	u16		Address,
+	IN	u8		Value)
+{
+	u8	Bytetemp = {0x00};
+	u8	temp = {0x00};
+	u32	k=0;
+	u16	contentLen=0;
+
+	//RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", Address, Value));
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&contentLen, _FALSE);
+
+	if( Address < contentLen)	//E-fuse 512Byte
+	{
+		rtw_write8(Adapter, EFUSE_CTRL, Value);
+
+		//Write E-fuse Register address bit0~7
+		temp = Address & 0xFF;	
+		rtw_write8(Adapter, EFUSE_CTRL+1, temp);	
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);	
+		
+		//Write E-fuse Register address bit8~9
+		temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);	
+		rtw_write8(Adapter, EFUSE_CTRL+2, temp);	
+
+		//Write 0x30[31]=1
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		temp = Bytetemp | 0x80;
+		rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+		//Wait Write-ready (0x30[31]=0)
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		while(Bytetemp & 0x80)
+		{
+			Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);			
+			k++;
+			if(k==100)
+			{
+				k=0;
+				break;
+			}
+		}
+	}
+}/* EFUSE_Write1Byte */
+
+
+/*  11/16/2008 MH Read one byte from real Efuse. */
+u8
+efuse_OneByteRead(
+	IN	PADAPTER	pAdapter, 
+	IN	u16			addr,
+	IN	u8			*data,
+	IN	BOOLEAN		bPseudoTest)
+{
+	u32	tmpidx = 0;
+	u8	bResult;
+	u8	readbyte;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+	
+	//DBG_871X("===> EFUSE_OneByteRead(), addr = %x\n", addr);
+	//DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST));
+
+	if(bPseudoTest)
+	{
+		bResult = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data);
+		return bResult;
+	}
+	
+	if(	IS_HARDWARE_TYPE_8723B(pAdapter) ||
+		(IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->VersionID))) ||
+		(IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->VersionID))
+	  )
+	{
+		// <20130121, Kordan> For SMIC EFUSE specificatoin.
+		//0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8])	
+		//PHY_SetMacReg(pAdapter, 0x34, BIT11, 0);
+		rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter,0x34)& (~BIT11) ); 
+	}
+
+	// -----------------e-fuse reg ctrl ---------------------------------
+	//address			
+	rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));		
+	rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03) ) |
+	(rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC ));	
+
+	//rtw_write8(pAdapter, EFUSE_CTRL+3,  0x72);//read cmd	
+	//Write bit 32 0
+	readbyte = rtw_read8(pAdapter, EFUSE_CTRL+3);		
+	rtw_write8(pAdapter, EFUSE_CTRL+3, (readbyte & 0x7f));
+
+	while(!(0x80 &rtw_read8(pAdapter, EFUSE_CTRL+3))&&(tmpidx<1000))
+	{
+		rtw_mdelay_os(1);
+		tmpidx++;
+	}
+	if(tmpidx<100)
+	{			
+		*data=rtw_read8(pAdapter, EFUSE_CTRL);		
+		bResult = _TRUE;
+	}
+	else
+	{
+		*data = 0xff;	
+		bResult = _FALSE;
+		DBG_871X("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult);
+		DBG_871X("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL));
+	}
+
+	return bResult;
+}
+		
+/*  11/16/2008 MH Write one byte to reald Efuse. */
+u8
+efuse_OneByteWrite(
+	IN	PADAPTER	pAdapter,  
+	IN	u16			addr, 
+	IN	u8			data,
+	IN	BOOLEAN		bPseudoTest)
+{
+	u8	tmpidx = 0;
+	u8	bResult=_FALSE;
+	u32 efuseValue = 0;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+	
+	//DBG_871X("===> EFUSE_OneByteWrite(), addr = %x data=%x\n", addr, data);
+	//DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST));
+
+	if(bPseudoTest)
+	{
+		bResult = Efuse_Write1ByteToFakeContent(pAdapter, addr, data);
+		return bResult;
+	}
+
+
+	// -----------------e-fuse reg ctrl ---------------------------------	
+	//address			
+
+	
+	efuseValue = rtw_read32(pAdapter, EFUSE_CTRL);
+	efuseValue |= (BIT21|BIT31);
+	efuseValue &= ~(0x3FFFF);
+	efuseValue |= ((addr<<8 | data) & 0x3FFFF);
+
+	// <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut.
+	if (	IS_HARDWARE_TYPE_8723B(pAdapter) ||
+		(IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->VersionID))) ||
+		(IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->VersionID))
+		) {
+		// <20130121, Kordan> For SMIC EFUSE specificatoin.
+		//0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8])
+		//PHY_SetMacReg(pAdapter, 0x34, BIT11, 1);
+		rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter,0x34)| (BIT11) );
+		rtw_write32(pAdapter, EFUSE_CTRL, 0x90600000|((addr<<8 | data)) );
+	}
+	else
+	{
+		rtw_write32(pAdapter, EFUSE_CTRL, efuseValue);
+	}
+
+	while((0x80 &  rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100) ){
+		rtw_mdelay_os(1);
+		tmpidx++;
+	}
+
+	if(tmpidx<100)
+	{
+		bResult = _TRUE;
+	}
+	else
+	{
+		bResult = _FALSE;
+		DBG_871X("%s: [ERROR] addr=0x%x ,efuseValue=0x%x ,bResult=%d time out 1s !!! \n",
+					__FUNCTION__, addr, efuseValue, bResult);
+		DBG_871X("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL));
+	}
+
+	// disable Efuse program enable
+	if (	IS_HARDWARE_TYPE_8723B(pAdapter) ||
+		(IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->VersionID))) ||
+		(IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->VersionID))
+		) {
+		PHY_SetMacReg(pAdapter, EFUSE_TEST, BIT(11), 0);
+	}
+
+	return bResult;
+}
+
+int
+Efuse_PgPacketRead(	IN	PADAPTER	pAdapter,
+					IN	u8			offset,
+					IN	u8			*data,
+					IN	BOOLEAN		bPseudoTest)
+{
+	int	ret=0;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, bPseudoTest);
+
+	return ret;
+}
+
+int 
+Efuse_PgPacketWrite(IN	PADAPTER	pAdapter, 
+					IN	u8 			offset,
+					IN	u8			word_en,
+					IN	u8			*data,
+					IN	BOOLEAN		bPseudoTest)
+{
+	int ret;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+
+int 
+Efuse_PgPacketWrite_BT(IN	PADAPTER	pAdapter, 
+					IN	u8 			offset,
+					IN	u8			word_en,
+					IN	u8			*data,
+					IN	BOOLEAN		bPseudoTest)
+{
+	int ret;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_WordEnableDataRead
+ *
+ * Overview:	Read allowed word in current efuse section data.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008 	MHC		Create Version 0.
+ * 11/21/2008 	MHC		Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void
+efuse_WordEnableDataRead(IN	u8	word_en,
+							IN	u8	*sourdata,
+							IN	u8	*targetdata)
+{	
+	if (!(word_en&BIT(0)))
+	{
+		targetdata[0] = sourdata[0];
+		targetdata[1] = sourdata[1];
+	}
+	if (!(word_en&BIT(1)))
+	{
+		targetdata[2] = sourdata[2];
+		targetdata[3] = sourdata[3];
+	}
+	if (!(word_en&BIT(2)))
+	{
+		targetdata[4] = sourdata[4];
+		targetdata[5] = sourdata[5];
+	}
+	if (!(word_en&BIT(3)))
+	{
+		targetdata[6] = sourdata[6];
+		targetdata[7] = sourdata[7];
+	}
+}
+
+
+u8
+Efuse_WordEnableDataWrite(	IN	PADAPTER	pAdapter,
+							IN	u16		efuse_addr,
+							IN	u8		word_en, 
+							IN	u8		*data,
+							IN	BOOLEAN		bPseudoTest)
+{
+	u8	ret=0;
+
+	ret =  pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+	
+	return ret;
+}
+
+static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteRead(padapter,address, value, _FALSE);
+}
+
+static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteWrite(padapter,address, *value, _FALSE);
+}
+
+/*
+ * read/wirte raw efuse data
+ */
+u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data)
+{
+	int i = 0;
+	u16	real_content_len = 0, max_available_size = 0;
+	u8 res = _FAIL ;
+	u8 (*rw8)(PADAPTER, u16, u8*);
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&real_content_len, _FALSE);
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE);
+
+	if (start_addr > real_content_len)
+		return _FAIL;
+
+	if (_TRUE == bWrite) {
+		if ((start_addr + cnts) > max_available_size)
+			return _FAIL;
+		rw8 = &efuse_write8;
+	} else
+		rw8 = &efuse_read8;
+
+	Efuse_PowerSwitch(padapter, bWrite, _TRUE);
+
+	// e-fuse one byte read / write
+	for (i = 0; i < cnts; i++) {
+		if (start_addr >= real_content_len) {
+			res = _FAIL;
+			break;
+		}
+
+		res = rw8(padapter, start_addr++, data++);
+		if (_FAIL == res) break;
+	}
+
+	Efuse_PowerSwitch(padapter, bWrite, _FALSE);
+
+	return res;
+}
+//------------------------------------------------------------------------------
+u16 efuse_GetMaxSize(PADAPTER padapter)
+{
+	u16	max_size;
+
+	max_size = 0;
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE);
+	return max_size;
+}
+//------------------------------------------------------------------------------
+u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size)
+{
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+	*size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE);
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+//------------------------------------------------------------------------------
+u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16	mapLen=0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+
+	efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, _FALSE);
+
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16	mapLen=0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, _FALSE, _TRUE);
+
+	efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, _FALSE);
+
+	Efuse_PowerSwitch(padapter, _FALSE, _FALSE);
+
+	return _SUCCESS;
+}
+
+BOOLEAN rtw_file_efuse_IsMasked(
+	PADAPTER	pAdapter,
+	u16		Offset
+	)
+{
+	int r = Offset/16;
+	int c = (Offset%16) / 2;
+	int result = 0;
+	
+	if(pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+
+	//DBG_871X(" %s ,Offset=%x r= %d , c=%d , maskfileBuffer[r]= %x \n",__func__,Offset,r,c,maskfileBuffer[r]);
+	if (c < 4) // Upper double word
+	    result = (maskfileBuffer[r] & (0x10 << c));
+	else
+	    result = (maskfileBuffer[r] & (0x01 << (c-4)));
+	
+	return (result > 0) ? 0 : 1;
+
+}
+
+
+u8 rtw_efuse_file_read(PADAPTER padapter,u8 *filepatch,u8 *buf,u32 len)
+{
+	char *ptmp;
+	char *ptmpbuf=NULL;
+	u32 rtStatus;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	ptmpbuf = rtw_zmalloc(2048);
+
+	if (ptmpbuf == NULL)
+		return _FALSE;
+
+	_rtw_memset(ptmpbuf,'\0',2048);
+	
+	rtStatus = rtw_retrieve_from_file(filepatch, ptmpbuf, 2048);
+
+	if( rtStatus > 100 )
+	{
+		u32 i,j;
+		for(i=0,j=0;j<len;i+=2,j++)
+		{
+			if (( ptmpbuf[i] == ' ' ) && (ptmpbuf[i+1] != '\n' && ptmpbuf[i+1] != '\0')) {
+				i++;
+			}
+			if( (ptmpbuf[i+1] != '\n' && ptmpbuf[i+1] != '\0'))
+			{
+					buf[j] = simple_strtoul(&ptmpbuf[i],&ptmp, 16);
+					DBG_871X(" i=%d,j=%d, %x \n",i,j,buf[j]);
+
+			} else {
+				j--;
+			}
+			
+		}
+
+	} else {
+		DBG_871X(" %s ,filepatch %s , FAIL %d\n", __func__, filepatch, rtStatus);
+		return _FALSE;
+	}
+	rtw_mfree(ptmpbuf, 2048);
+	DBG_871X(" %s ,filepatch %s , done %d\n", __func__, filepatch, rtStatus);
+	return _TRUE;
+}
+
+
+BOOLEAN 
+efuse_IsMasked(
+	PADAPTER	pAdapter,
+	u16		Offset
+	)
+{
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(pAdapter);
+	
+
+	//if (bEfuseMaskOFF(pAdapter))
+	if(pAdapter->registrypriv.boffefusemask)
+		return FALSE;
+		
+#if DEV_BUS_TYPE == RT_USB_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))  
+		return (IS_MASKED(8188E,_MUSB,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))  
+		return (IS_MASKED(8812A,_MUSB,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8821A)
+	//if (IS_HARDWARE_TYPE_8811AU(pAdapter))  
+	//	return (IS_MASKED(8811A,_MUSB,Offset)) ? TRUE : FALSE;
+	if (IS_HARDWARE_TYPE_8821(pAdapter))  
+		return (IS_MASKED(8821A,_MUSB,Offset)) ? TRUE : FALSE;		
+#endif		
+#if defined(CONFIG_RTL8192E)
+	if (IS_HARDWARE_TYPE_8192E(pAdapter))  
+		return (IS_MASKED(8192E,_MUSB,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))  
+		return (IS_MASKED(8723B,_MUSB,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return (IS_MASKED(8814A, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8188F)
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))
+		return (IS_MASKED(8188F, _MUSB, Offset)) ? TRUE : FALSE;
+#endif
+#elif DEV_BUS_TYPE == RT_PCI_INTERFACE
+#if defined(CONFIG_RTL8188E)
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))  
+		return (IS_MASKED(8188E,_MPCIE,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8192E)
+   	if (IS_HARDWARE_TYPE_8192E(pAdapter))	
+		return (IS_MASKED(8192E,_MPCIE,Offset)) ? TRUE : FALSE;
+#endif	
+#if defined(CONFIG_RTL8812A)
+	if (IS_HARDWARE_TYPE_8812(pAdapter))  
+		return (IS_MASKED(8812A,_MPCIE,Offset)) ? TRUE : FALSE;
+#endif	
+#if defined(CONFIG_RTL8821A)
+	if (IS_HARDWARE_TYPE_8821(pAdapter))  
+		return (IS_MASKED(8821A,_MPCIE,Offset)) ? TRUE : FALSE;
+#endif
+#if defined(CONFIG_RTL8723B)
+	if (IS_HARDWARE_TYPE_8723B(pAdapter))  
+		return (IS_MASKED(8723B,_MPCIE,Offset)) ? TRUE : FALSE; 
+#endif
+#if defined(CONFIG_RTL8814A)
+	if (IS_HARDWARE_TYPE_8814A(pAdapter))
+		return (IS_MASKED(8814A, _MPCIE, Offset)) ? TRUE : FALSE;
+#endif
+	//else if (IS_HARDWARE_TYPE_8821B(pAdapter))  
+	//	return (IS_MASKED(8821B,_MPCIE,Offset)) ? TRUE : FALSE; 
+
+#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE
+#ifdef CONFIG_RTL8188E_SDIO
+	if (IS_HARDWARE_TYPE_8188E(pAdapter))  
+		return (IS_MASKED(8188E,_MSDIO,Offset)) ? TRUE : FALSE;
+#endif
+#ifdef CONFIG_RTL8188F_SDIO
+	if (IS_HARDWARE_TYPE_8188F(pAdapter))  
+		return (IS_MASKED(8188F, _MSDIO, Offset)) ? TRUE : FALSE;
+#endif
+#endif
+
+	return FALSE;	
+}
+
+//------------------------------------------------------------------------------
+u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)												\
+	if(!(expr)) {															\
+		printk( "Assertion failed! %s at ......\n", #expr);							\
+		printk( "      ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32	i, j, idx;
+	u8	ret = _SUCCESS;
+	u16	mapLen=0;
+	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); // have to be 8 byte alignment
+	RT_ASSERT_RET((mapLen & 0x7) == 0); // have to be PGPKT_DATA_SIZE alignment for memcpy
+
+	map = rtw_zmalloc(mapLen);
+	if(map == NULL){
+		return _FAIL;
+	}
+	
+	_rtw_memset(map, 0xFF, mapLen);
+	
+	ret = rtw_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL) goto exit;
+
+	if(padapter->registrypriv.boffefusemask==0)
+	{
+		for (i =0; i < cnts; i++)
+		{ 
+			if(padapter->registrypriv.bFileMaskEfuse==_TRUE)
+			{
+				if (rtw_file_efuse_IsMasked(padapter, addr+i))	/*use file efuse mask. */
+						data[i] = map[addr+i];
+			}
+			else
+			{
+				if ( efuse_IsMasked(padapter, addr+i ))
+						data[i] = map[addr+i];
+			}
+			DBG_8192C("%s , data[%d] = %x, map[addr+i]= %x\n", __func__, i, data[i], map[addr+i]);
+		}
+	}
+	Efuse_PowerSwitch(padapter, _TRUE, _TRUE);
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts)
+	{
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i<PGPKT_DATA_SIZE && idx < cnts; i++, idx++)
+		{
+			if (data[idx] != map[addr + idx])
+			{
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+#ifdef CONFIG_RTL8723B					
+				 if( addr + idx == 0x8)
+				 {	
+					if (IS_C_CUT(pHalData->VersionID) || IS_B_CUT(pHalData->VersionID))
+					{
+						if(pHalData->adjuseVoltageVal == 6)
+						{
+								newdata[i] = map[addr + idx];
+							 	DBG_8192C(" %s ,\n adjuseVoltageVal = %d ,newdata[%d] = %x \n",__func__,pHalData->adjuseVoltageVal,i,newdata[i]);	 
+						}
+					}
+				  }
+#endif
+			}
+		}
+
+		if (word_en != 0xF) {
+			ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, _FALSE);
+			DBG_871X("offset=%x \n",offset);
+			DBG_871X("word_en=%x \n",word_en);
+
+			for(i=0;i<PGPKT_DATA_SIZE;i++)
+			{
+				DBG_871X("data=%x \t",newdata[i]);
+			}
+			if (ret == _FAIL) break;
+		}
+
+		offset++;
+	}
+
+	Efuse_PowerSwitch(padapter, _TRUE, _FALSE);
+
+exit:
+
+	rtw_mfree(map, mapLen);
+
+	return ret;
+}
+
+u8 rtw_efuse_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u8	ret = _SUCCESS;
+	u16	mapLen = 0, i = 0;
+	
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+	
+	ret = rtw_efuse_map_read(padapter, addr, cnts , data);
+
+	if (padapter->registrypriv.boffefusemask == 0) {
+
+			for (i = 0; i < cnts; i++) { 
+				if (padapter->registrypriv.bFileMaskEfuse == _TRUE) {
+					if (rtw_file_efuse_IsMasked(padapter, addr+i)) /*use file efuse mask.*/ 
+							data[i] = 0xff;
+				} else {
+					/*DBG_8192C(" %s , data[%d] = %x\n", __func__, i, data[i]);*/
+					if (efuse_IsMasked(padapter, addr+i)) {
+						data[i] = 0xff;
+						/*DBG_8192C(" %s ,mask data[%d] = %x\n", __func__, i, data[i]);*/
+					}
+				}
+			}
+	
+	}
+	return ret;
+
+}
+
+u8 rtw_BT_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data)
+{
+#define RT_ASSERT_RET(expr)												\
+	if(!(expr)) {															\
+		printk( "Assertion failed! %s at ......\n", #expr);							\
+		printk( "      ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__);	\
+		return _FAIL;	\
+	}
+
+	u8	offset, word_en;
+	u8	*map;
+	u8	newdata[PGPKT_DATA_SIZE];
+	s32	i=0, j=0, idx;
+	u8	ret = _SUCCESS;
+	u16	mapLen=0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); // have to be 8 byte alignment
+	RT_ASSERT_RET((mapLen & 0x7) == 0); // have to be PGPKT_DATA_SIZE alignment for memcpy
+
+	map = rtw_zmalloc(mapLen);
+	if(map == NULL){
+		return _FAIL;
+	}
+
+	ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL) goto exit;
+	DBG_871X("OFFSET\tVALUE(hex)\n");
+	for (i=0; i<1024; i+=16) // set 512 because the iwpriv's extra size have limit 0x7FF
+	{
+			DBG_871X("0x%03x\t", i);
+			for (j=0; j<8; j++) {
+				DBG_871X("%02X ", map[i+j]);
+			}
+			DBG_871X("\t");
+			for (; j<16; j++) {
+				DBG_871X("%02X ", map[i+j]);
+			}
+			DBG_871X("\n");
+	}
+	DBG_871X("\n");
+	Efuse_PowerSwitch(padapter, _TRUE, _TRUE);
+
+	idx = 0;
+	offset = (addr >> 3);
+	while (idx < cnts)
+	{
+		word_en = 0xF;
+		j = (addr + idx) & 0x7;
+		_rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE);
+		for (i = j; i<PGPKT_DATA_SIZE && idx < cnts; i++, idx++)
+		{
+			if (data[idx] != map[addr + idx])
+			{
+				word_en &= ~BIT(i >> 1);
+				newdata[i] = data[idx];
+			}
+		}
+
+		if (word_en != 0xF) {
+			DBG_871X("offset=%x \n",offset);
+			DBG_871X("word_en=%x \n",word_en);
+			DBG_871X("%s: data=", __FUNCTION__);
+			for(i=0;i<PGPKT_DATA_SIZE;i++)
+			{
+				DBG_871X("0x%02X ", newdata[i]);
+			}
+			DBG_871X("\n");
+			ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, _FALSE);
+			if (ret == _FAIL) break;
+		}
+
+		offset++;
+	}
+
+	Efuse_PowerSwitch(padapter, _TRUE, _FALSE);
+
+exit:
+
+	rtw_mfree(map, mapLen);
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_ReadAllMap
+ *
+ * Overview:	Read All Efuse content
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/11/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID 
+Efuse_ReadAllMap(
+	IN		PADAPTER	pAdapter, 
+	IN		u8		efuseType,
+	IN OUT	u8		*Efuse,
+	IN		BOOLEAN		bPseudoTest);
+VOID 
+Efuse_ReadAllMap(
+	IN		PADAPTER	pAdapter, 
+	IN		u8		efuseType,
+	IN OUT	u8		*Efuse,
+	IN		BOOLEAN		bPseudoTest)
+{
+	u16	mapLen=0;
+
+	Efuse_PowerSwitch(pAdapter,_FALSE, _TRUE);
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+
+	efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, bPseudoTest);
+
+	Efuse_PowerSwitch(pAdapter,_FALSE, _FALSE);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_ShadowRead1Byte
+ *			efuse_ShadowRead2Byte
+ *			efuse_ShadowRead4Byte
+ *
+ * Overview:	Read from efuse init map by one/two/four bytes !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static VOID
+efuse_ShadowRead1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u8		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+
+}	// EFUSE_ShadowRead1Byte
+
+//---------------Read Two Bytes
+static VOID
+efuse_ShadowRead2Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u16		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+	*Value |= pHalData->efuse_eeprom_data[Offset+1]<<8;
+
+}	// EFUSE_ShadowRead2Byte
+
+//---------------Read Four Bytes
+static VOID
+efuse_ShadowRead4Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN OUT	u32		*Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	*Value = pHalData->efuse_eeprom_data[Offset];
+	*Value |= pHalData->efuse_eeprom_data[Offset+1]<<8;
+	*Value |= pHalData->efuse_eeprom_data[Offset+2]<<16;
+	*Value |= pHalData->efuse_eeprom_data[Offset+3]<<24;
+
+}	// efuse_ShadowRead4Byte
+
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_ShadowWrite1Byte
+ *			efuse_ShadowWrite2Byte
+ *			efuse_ShadowWrite4Byte
+ *
+ * Overview:	Write efuse modify map by one/two/four byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+#ifdef PLATFORM
+static VOID
+efuse_ShadowWrite1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN 	u8		Value);
+#endif //PLATFORM
+static VOID
+efuse_ShadowWrite1Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN 	u8		Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	pHalData->efuse_eeprom_data[Offset] = Value;
+
+}	// efuse_ShadowWrite1Byte
+
+//---------------Write Two Bytes
+static VOID
+efuse_ShadowWrite2Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN 	u16		Value)
+{
+	
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+	
+
+	pHalData->efuse_eeprom_data[Offset] = Value&0x00FF;
+	pHalData->efuse_eeprom_data[Offset+1] = Value>>8;
+
+}	// efuse_ShadowWrite1Byte
+
+//---------------Write Four Bytes
+static VOID
+efuse_ShadowWrite4Byte(
+	IN	PADAPTER	pAdapter,
+	IN	u16		Offset,
+	IN	u32		Value)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+
+	pHalData->efuse_eeprom_data[Offset] = (u8)(Value&0x000000FF);
+	pHalData->efuse_eeprom_data[Offset+1] = (u8)((Value>>8)&0x0000FF);
+	pHalData->efuse_eeprom_data[Offset+2] = (u8)((Value>>16)&0x00FF);
+	pHalData->efuse_eeprom_data[Offset+3] = (u8)((Value>>24)&0xFF);
+
+}	// efuse_ShadowWrite1Byte
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowMapUpdate
+ *
+ * Overview:	Transfer current EFUSE content to shadow init and modify map.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/13/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowMapUpdate(
+	IN PADAPTER	pAdapter,
+	IN u8		efuseType,
+	IN BOOLEAN	bPseudoTest)
+{
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter);
+	u16	mapLen=0;
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest);
+
+	if (pHalData->bautoload_fail_flag == _TRUE)
+	{
+		_rtw_memset(pHalData->efuse_eeprom_data, 0xFF, mapLen);
+	}
+	else
+	{
+		#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE			
+		if(_SUCCESS != retriveAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data)) {
+		#endif
+		
+		Efuse_ReadAllMap(pAdapter, efuseType, pHalData->efuse_eeprom_data, bPseudoTest);
+		
+		#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+			storeAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data);
+		}
+		#endif
+	}
+
+	//PlatformMoveMemory((PVOID)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], 
+	//(PVOID)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen);
+}// EFUSE_ShadowMapUpdate
+
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowRead
+ *
+ * Overview:	Read from efuse init map !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+EFUSE_ShadowRead(
+	IN		PADAPTER	pAdapter,
+	IN		u8		Type,
+	IN		u16		Offset,
+	IN OUT	u32		*Value	)
+{
+	if (Type == 1)
+		efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
+	else if (Type == 2)
+		efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
+	else if (Type == 4)
+		efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
+	
+}	// EFUSE_ShadowRead
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowWrite
+ *
+ * Overview:	Write efuse modify map for later update operation to use!!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008 	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+VOID
+EFUSE_ShadowWrite(
+	IN	PADAPTER	pAdapter,
+	IN	u8		Type,
+	IN	u16		Offset,
+	IN OUT	u32		Value);
+VOID
+EFUSE_ShadowWrite(
+	IN	PADAPTER	pAdapter,
+	IN	u8		Type,
+	IN	u16		Offset,
+	IN OUT	u32		Value)
+{
+#if (MP_DRIVER == 0)
+	return;
+#endif
+	if ( pAdapter->registrypriv.mp_mode == 0)
+		return;
+
+
+	if (Type == 1)
+		efuse_ShadowWrite1Byte(pAdapter, Offset, (u8)Value);
+	else if (Type == 2)
+		efuse_ShadowWrite2Byte(pAdapter, Offset, (u16)Value);
+	else if (Type == 4)
+		efuse_ShadowWrite4Byte(pAdapter, Offset, (u32)Value);
+
+}	// EFUSE_ShadowWrite
+
+VOID
+Efuse_InitSomeVar(
+	IN		PADAPTER	pAdapter
+	);
+VOID
+Efuse_InitSomeVar(
+	IN		PADAPTER	pAdapter
+	)
+{
+	u8 i;
+	
+	_rtw_memset((PVOID)&fakeEfuseContent[0], 0xff, EFUSE_MAX_HW_SIZE);
+	_rtw_memset((PVOID)&fakeEfuseInitMap[0], 0xff, EFUSE_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&fakeEfuseModifiedMap[0], 0xff, EFUSE_MAX_MAP_LEN);
+
+	for(i=0; i<EFUSE_MAX_BT_BANK; i++)
+	{
+		_rtw_memset((PVOID)&BTEfuseContent[i][0], EFUSE_MAX_HW_SIZE, 0xff);
+	}
+	_rtw_memset((PVOID)&BTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&BTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+
+	for(i=0; i<EFUSE_MAX_BT_BANK; i++)
+	{
+		_rtw_memset((PVOID)&fakeBTEfuseContent[i][0], 0xff, EFUSE_MAX_HW_SIZE);
+	}
+	_rtw_memset((PVOID)&fakeBTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+	_rtw_memset((PVOID)&fakeBTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN);
+}
+
+#ifdef PLATFORM_LINUX
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+//#include <rtw_eeprom.h>
+
+ int isAdaptorInfoFileValid(void)
+{
+	return _TRUE;
+}
+
+int storeAdaptorInfoFile(char *path, u8* efuse_data)
+{
+	int ret =_SUCCESS;
+
+	if(path && efuse_data) {
+		ret = rtw_store_to_file(path, efuse_data, EEPROM_MAX_SIZE_512);
+		if(ret == EEPROM_MAX_SIZE)
+			ret = _SUCCESS;
+		else
+			ret = _FAIL;
+	} else {
+		DBG_871X("%s NULL pointer\n",__FUNCTION__);
+		ret =  _FAIL;
+	}
+	return ret;
+}
+
+int retriveAdaptorInfoFile(char *path, u8* efuse_data)
+{
+	int ret = _SUCCESS;
+	mm_segment_t oldfs;
+	struct file *fp;
+	
+	if(path && efuse_data) {
+
+		ret = rtw_retrieve_from_file(path, efuse_data, EEPROM_MAX_SIZE);
+		
+		if(ret == EEPROM_MAX_SIZE)
+			ret = _SUCCESS;
+		else
+			ret = _FAIL;
+
+		#if 0
+		if(isAdaptorInfoFileValid()) {	
+			return 0;
+		} else {
+			return _FAIL;
+		}
+		#endif
+		
+	} else {
+		DBG_871X("%s NULL pointer\n",__FUNCTION__);
+		ret = _FAIL;
+	}
+	return ret;
+}
+#endif /* CONFIG_ADAPTOR_INFO_CACHING_FILE */
+
+#ifdef CONFIG_EFUSE_CONFIG_FILE
+u32 rtw_read_efuse_from_file(const char *path, u8 *buf)
+{
+	u32 i;
+	u8 temp[3];
+	u32 ret = _FAIL;
+
+	struct file *fp;
+	mm_segment_t fs;
+	loff_t pos = 0;
+
+	fp = filp_open(path, O_RDONLY, 0);
+	if (fp == NULL || IS_ERR(fp)) {
+		if (fp != NULL)
+			DBG_871X_LEVEL(_drv_always_, "%s open %s fail, err:%ld\n"
+				, __func__, path, PTR_ERR(fp));
+		else
+			DBG_871X_LEVEL(_drv_always_, "%s open %s fail, fp is NULL\n"
+				, __func__, path);
+
+		goto exit;
+	}
+
+	temp[2] = 0; /* add end of string '\0' */
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	for (i = 0 ; i < HWSET_MAX_SIZE ; i++) {
+		vfs_read(fp, temp, 2, &pos);
+		if (sscanf(temp, "%hhx", &buf[i]) != 1) {
+			if (0)
+				DBG_871X_LEVEL(_drv_err_, "%s sscanf fail\n", __func__);
+			buf[i] = 0xFF;
+		}
+		if ((i % EFUSE_FILE_COLUMN_NUM) == (EFUSE_FILE_COLUMN_NUM - 1)) {
+			/* Filter the lates space char. */
+			vfs_read(fp, temp, 1, &pos);
+			if (strchr(temp, ' ') == NULL) {
+				pos--;
+				vfs_read(fp, temp, 2, &pos);
+			}
+		} else {
+			pos += 1; /* Filter the space character */
+		}
+	}
+
+	set_fs(fs);
+
+	DBG_871X_LEVEL(_drv_always_, "efuse file: %s\n", path);
+#ifdef CONFIG_DEBUG
+	for (i = 0; i < HWSET_MAX_SIZE; i++) {
+		if (i % 16 == 0)
+			DBG_871X_SEL_NL(RTW_DBGDUMP, "0x%03x: ", i);
+
+		DBG_871X_SEL(RTW_DBGDUMP, "%02X%s"
+			, buf[i]
+			, ((i + 1) % 16 == 0) ? "\n" : (((i + 1) % 8 == 0) ? "    " : " ")
+		);
+	}
+	DBG_871X_SEL(RTW_DBGDUMP, "\n");
+#endif
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+u32 rtw_read_macaddr_from_file(const char *path, u8 *buf)
+{
+	struct file *fp;
+	mm_segment_t fs;
+	loff_t pos = 0;
+
+	u8 source_addr[18];
+	u8 *head, *end;
+	int i;
+	u32 ret = _FAIL;
+
+	_rtw_memset(source_addr, 0, 18);
+
+	fp = filp_open(path, O_RDONLY, 0);
+	if (fp == NULL || IS_ERR(fp)) {
+		if (fp != NULL)
+			DBG_871X_LEVEL(_drv_always_, "%s open %s fail, err:%ld\n"
+				, __func__, path, PTR_ERR(fp));
+		else
+			DBG_871X_LEVEL(_drv_always_, "%s open %s fail, fp is NULL\n"
+				, __func__, path);
+
+		goto exit;
+	}
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	vfs_read(fp, source_addr, 18, &pos);
+	source_addr[17] = ':';
+
+	head = end = source_addr;
+	for (i = 0; i < ETH_ALEN; i++) {
+		while (end && (*end != ':'))
+			end++;
+
+		if (end && (*end == ':'))
+			*end = '\0';
+
+		if (sscanf(head, "%hhx", &buf[i]) != 1) {
+			if (0)
+				DBG_871X_LEVEL(_drv_err_, "%s sscanf fail\n", __func__);
+			buf[i] = 0xFF;
+		}
+
+		if (end) {
+			end++;
+			head = end;
+		}
+	}
+
+	set_fs(fs);
+
+	DBG_871X_LEVEL(_drv_always_, "wifi_mac file: %s\n", path);
+#ifdef CONFIG_DEBUG
+	DBG_871X(MAC_FMT"\n", MAC_ARG(buf));
+#endif
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+#endif /* CONFIG_EFUSE_CONFIG_FILE */
+
+#endif /* PLATFORM_LINUX */
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_ap.c b/drivers/net/wireless/rtl8189es/core/rtw_ap.c
new file mode 100644
index 000000000000..ea446c717509
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_ap.c
@@ -0,0 +1,4222 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_AP_C_
+
+#include <drv_types.h>
+
+
+#ifdef CONFIG_AP_MODE
+
+extern unsigned char	RTW_WPA_OUI[];
+extern unsigned char 	WMM_OUI[];
+extern unsigned char	WPS_OUI[];
+extern unsigned char	P2P_OUI[];
+extern unsigned char	WFD_OUI[];
+
+void init_mlme_ap_info(_adapter *padapter)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;	
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	
+
+	_rtw_spinlock_init(&pmlmepriv->bcn_update_lock);	
+
+	//for ACL 
+	_rtw_init_queue(&pacl_list->acl_node_q);
+
+	//pmlmeext->bstart_bss = _FALSE;
+
+	start_ap_mode(padapter);
+}
+
+void free_mlme_ap_info(_adapter *padapter)
+{
+	_irqL irqL;
+	struct sta_info *psta=NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	//stop_ap_mode(padapter);
+
+	pmlmepriv->update_bcn = _FALSE;
+	pmlmeext->bstart_bss = _FALSE;	
+	
+	rtw_sta_flush(padapter, _TRUE);
+
+	pmlmeinfo->state = _HW_STATE_NOLINK_;
+
+	//free_assoc_sta_resources
+	rtw_free_all_stainfo(padapter);
+
+	//free bc/mc sta_info
+	psta = rtw_get_bcmc_stainfo(padapter);	
+	//_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		
+	rtw_free_stainfo(padapter, psta);
+	//_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	
+
+	_rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+	
+}
+
+static void update_BCNTIM(_adapter *padapter)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	unsigned char *pie = pnetwork_mlmeext->IEs;
+
+/*
+	//DBG_871X("%s\n", __FUNCTION__);
+	
+	//update TIM IE
+	//if(pstapriv->tim_bitmap)
+*/
+	if (_TRUE) {
+		u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+		u16 tim_bitmap_le;
+		uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;	
+	
+		tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+		p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+		if (p != NULL && tim_ielen > 0) {
+			tim_ielen += 2;
+			
+			premainder_ie = p + tim_ielen;
+
+			tim_ie_offset = (sint)(p -pie);
+			
+			remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+
+			/*append TIM IE from dst_ie offset*/
+			dst_ie = p;
+		} else {
+			tim_ielen = 0;
+
+			/*calculate head_len*/
+			offset = _FIXED_IE_LENGTH_;
+
+			/* get ssid_ie len */
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+			if (p != NULL)
+				offset += tmp_len+2;
+
+			/*get supported rates len*/
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));	
+			if (p !=  NULL) 
+			{			
+				offset += tmp_len+2;
+			}
+
+			/*DS Parameter Set IE, len=3*/
+			offset += 3;
+
+			premainder_ie = pie + offset;
+
+			remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;	
+
+			/*append TIM IE from offset*/
+			dst_ie = pie + offset;
+			
+		}
+		
+		if (remainder_ielen > 0) {
+			pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+			if(pbackup_remainder_ie && premainder_ie)
+				_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+		}		
+		
+		*dst_ie++=_TIM_IE_;
+
+		if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fe))			
+			tim_ielen = 5;
+		else
+			tim_ielen = 4;
+
+		*dst_ie++ = tim_ielen;
+		
+		*dst_ie++ = 0;/*DTIM count*/
+		*dst_ie++ = 1;/*DTIM period*/
+		
+		if (pstapriv->tim_bitmap & BIT(0))/*for bc/mc frames*/
+			*dst_ie++ = BIT(0);/*bitmap ctrl */
+		else
+			*dst_ie++ = 0;
+
+		if (tim_ielen == 4) {
+			u8 pvb = 0;
+			
+			if (pstapriv->tim_bitmap & 0x00fe)
+				pvb = (u8)tim_bitmap_le;
+			else if (pstapriv->tim_bitmap & 0xff00)			
+				pvb = (u8)(tim_bitmap_le >> 8);
+			else
+				pvb = (u8)tim_bitmap_le;
+
+			*dst_ie++ = pvb;
+			
+		} else if (tim_ielen == 5) {
+			_rtw_memcpy(dst_ie, &tim_bitmap_le, 2);
+			dst_ie += 2;				
+		}	
+		
+		/*copy remainder IE*/
+		if (pbackup_remainder_ie) {
+			_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+			rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+		}	
+
+		offset =  (uint)(dst_ie - pie);
+		pnetwork_mlmeext->IELength = offset + remainder_ielen;
+	
+	}
+}
+
+void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len)
+{
+	PNDIS_802_11_VARIABLE_IEs	pIE;
+	u8	bmatch = _FALSE;
+	u8	*pie = pnetwork->IEs;
+	u8	*p=NULL, *dst_ie=NULL, *premainder_ie=NULL, *pbackup_remainder_ie=NULL;
+	u32	i, offset, ielen, ie_offset, remainder_ielen = 0;
+
+	for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;)
+	{
+		pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i);
+
+		if (pIE->ElementID > index)
+		{
+			break;
+		}
+		else if(pIE->ElementID == index) // already exist the same IE
+		{
+			p = (u8 *)pIE;
+			ielen = pIE->Length;
+			bmatch = _TRUE;
+			break;
+		}
+
+		p = (u8 *)pIE;
+		ielen = pIE->Length;
+		i += (pIE->Length + 2);
+	}
+
+	if (p != NULL && ielen>0)
+	{
+		ielen += 2;
+		
+		premainder_ie = p+ielen;
+
+		ie_offset = (sint)(p -pie);
+		
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		if(bmatch)
+			dst_ie = p;
+		else
+			dst_ie = (p+ielen);
+	}
+
+	if(dst_ie == NULL)
+		return;
+
+	if(remainder_ielen>0)
+	{
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if(pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	*dst_ie++=index;
+	*dst_ie++=len;
+
+	_rtw_memcpy(dst_ie, data, len);
+	dst_ie+=len;
+
+	//copy remainder IE
+	if(pbackup_remainder_ie)
+	{
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset =  (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index)
+{
+	u8 *p, *dst_ie=NULL, *premainder_ie=NULL, *pbackup_remainder_ie=NULL;
+	uint offset, ielen, ie_offset, remainder_ielen = 0;
+	u8	*pie = pnetwork->IEs;
+
+	p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, pnetwork->IELength - _FIXED_IE_LENGTH_);
+	if (p != NULL && ielen>0)
+	{
+		ielen += 2;
+		
+		premainder_ie = p+ielen;
+
+		ie_offset = (sint)(p -pie);
+		
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		dst_ie = p;
+	}
+	else {
+		return;
+	}
+
+	if(remainder_ielen>0)
+	{
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if(pbackup_remainder_ie && premainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	//copy remainder IE
+	if(pbackup_remainder_ie)
+	{
+		_rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	}
+
+	offset =  (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+
+u8 chk_sta_is_alive(struct sta_info *psta);
+u8 chk_sta_is_alive(struct sta_info *psta)
+{
+	u8 ret = _FALSE;
+	#ifdef DBG_EXPIRATION_CHK
+	DBG_871X("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n"
+		, MAC_ARG(psta->hwaddr)
+		, psta->rssi_stat.UndecoratedSmoothedPWDB
+		//, STA_RX_PKTS_ARG(psta)
+		, STA_RX_PKTS_DIFF_ARG(psta)
+		, psta->expire_to
+		, psta->state&WIFI_SLEEP_STATE?"PS, ":""
+		, psta->state&WIFI_STA_ALIVE_CHK_STATE?"SAC, ":""
+		, psta->sleepq_len
+	);
+	#endif
+
+	//if(sta_last_rx_pkts(psta) == sta_rx_pkts(psta))
+	if((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
+	{
+		#if 0
+		if(psta->state&WIFI_SLEEP_STATE)
+			ret = _TRUE;
+		#endif
+	}
+	else
+	{
+		ret = _TRUE;
+	}
+
+	sta_update_last_rx_pkts(psta);
+
+	return ret;
+}
+
+void	expire_timeout_chk(_adapter *padapter)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 updated = _FALSE;
+	struct sta_info *psta=NULL;	
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	
+	phead = &pstapriv->auth_list;
+	plist = get_next(phead);
+	
+	//check auth_queue
+	#ifdef DBG_EXPIRATION_CHK
+	if (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+		DBG_871X(FUNC_NDEV_FMT" auth_list, cnt:%u\n"
+			, FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt);
+	}
+	#endif
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)	
+	{
+		psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
+
+		plist = get_next(plist);
+
+
+#ifdef CONFIG_ATMEL_RC_PATCH
+		if (_TRUE == _rtw_memcmp((void *)(pstapriv->atmel_rc_pattern), (void *)(psta->hwaddr), ETH_ALEN))
+			continue;
+		if (psta->flag_atmel_rc)
+			continue;
+#endif
+		if(psta->expire_to>0)
+		{
+			psta->expire_to--;
+			if (psta->expire_to == 0)
+			{
+				rtw_list_delete(&psta->auth_list);
+				pstapriv->auth_list_cnt--;
+				
+				DBG_871X("auth expire %02X%02X%02X%02X%02X%02X\n",
+					psta->hwaddr[0],psta->hwaddr[1],psta->hwaddr[2],psta->hwaddr[3],psta->hwaddr[4],psta->hwaddr[5]);
+				
+				_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+				
+				//_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	
+				rtw_free_stainfo(padapter, psta);
+				//_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);	
+				
+				_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+			}	
+		}	
+		
+	}
+
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	psta = NULL;
+	
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	//check asoc_queue
+	#ifdef DBG_EXPIRATION_CHK
+	if (rtw_end_of_queue_search(phead, plist) == _FALSE) {
+		DBG_871X(FUNC_NDEV_FMT" asoc_list, cnt:%u\n"
+			, FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt);
+	}
+	#endif
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+	{
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+#ifdef CONFIG_ATMEL_RC_PATCH
+		DBG_871X("%s:%d  psta=%p, %02x,%02x||%02x,%02x  \n\n", __func__,  __LINE__,
+			psta,pstapriv->atmel_rc_pattern[0], pstapriv->atmel_rc_pattern[5], psta->hwaddr[0], psta->hwaddr[5]);
+		if (_TRUE == _rtw_memcmp((void *)pstapriv->atmel_rc_pattern, (void *)(psta->hwaddr), ETH_ALEN))
+			continue;		
+		if (psta->flag_atmel_rc)
+			continue;
+		DBG_871X("%s: debug line:%d \n", __func__, __LINE__);
+#endif
+#ifdef CONFIG_AUTO_AP_MODE
+		if(psta->isrc)
+			continue;
+#endif
+		if (chk_sta_is_alive(psta) || !psta->expire_to) {
+			psta->expire_to = pstapriv->expire_to;
+			psta->keep_alive_trycnt = 0;
+			#ifdef CONFIG_TX_MCAST2UNI
+			psta->under_exist_checking = 0;
+			#endif	// CONFIG_TX_MCAST2UNI
+		} else {
+			psta->expire_to--;
+		}
+
+#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+#ifdef CONFIG_80211N_HT
+#ifdef CONFIG_TX_MCAST2UNI
+		if ( (psta->flags & WLAN_STA_HT) && (psta->htpriv.agg_enable_bitmap || psta->under_exist_checking) ) {
+			// check sta by delba(addba) for 11n STA 
+			// ToDo: use CCX report to check for all STAs
+			//DBG_871X("asoc check by DELBA/ADDBA! (pstapriv->expire_to=%d s)(psta->expire_to=%d s), [%02x, %d]\n", pstapriv->expire_to*2, psta->expire_to*2, psta->htpriv.agg_enable_bitmap, psta->under_exist_checking);
+			
+				if ( psta->expire_to <= (pstapriv->expire_to - 50 ) ) {
+				DBG_871X("asoc expire by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to-psta->expire_to)*2);
+				psta->under_exist_checking = 0;
+				psta->expire_to = 0;
+			} else if ( psta->expire_to <= (pstapriv->expire_to - 3) && (psta->under_exist_checking==0)) {
+				DBG_871X("asoc check by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to-psta->expire_to)*2);
+				psta->under_exist_checking = 1;
+				//tear down TX AMPDU
+				send_delba(padapter, 1, psta->hwaddr);// // originator
+				psta->htpriv.agg_enable_bitmap = 0x0;//reset
+				psta->htpriv.candidate_tid_bitmap = 0x0;//reset
+			}
+		}
+#endif //CONFIG_TX_MCAST2UNI
+#endif //CONFIG_80211N_HT
+#endif //CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+
+		if (psta->expire_to <= 0)
+		{
+			struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+			if (padapter->registrypriv.wifi_spec == 1)
+			{
+				psta->expire_to = pstapriv->expire_to;
+				continue;
+			}
+
+#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+#ifdef CONFIG_80211N_HT
+
+#define KEEP_ALIVE_TRYCNT (3)
+
+			if(psta->keep_alive_trycnt > 0 && psta->keep_alive_trycnt <= KEEP_ALIVE_TRYCNT)
+			{				
+				if(psta->state & WIFI_STA_ALIVE_CHK_STATE)
+					psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+				else
+					psta->keep_alive_trycnt = 0;
+				
+			}
+			else if((psta->keep_alive_trycnt > KEEP_ALIVE_TRYCNT) && !(psta->state & WIFI_STA_ALIVE_CHK_STATE))
+			{
+				psta->keep_alive_trycnt = 0;
+			}			
+			if((psta->htpriv.ht_option==_TRUE) && (psta->htpriv.ampdu_enable==_TRUE)) 
+			{
+				uint priority = 1; //test using BK
+				u8 issued=0;				
+		
+				//issued = (psta->htpriv.agg_enable_bitmap>>priority)&0x1;
+				issued |= (psta->htpriv.candidate_tid_bitmap>>priority)&0x1;
+
+				if(0==issued)
+				{
+					if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE))
+					{
+						psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
+
+						if (psta->state & WIFI_SLEEP_STATE) 
+							psta->expire_to = 2; // 2x2=4 sec
+						else
+							psta->expire_to = 1; // 2 sec
+					
+						psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+					
+						//add_ba_hdl(padapter, (u8*)paddbareq_parm);
+
+						DBG_871X("issue addba_req to check if sta alive, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt);
+
+						issue_addba_req(padapter, psta->hwaddr, (u8)priority);
+		
+						_set_timer(&psta->addba_retry_timer, ADDBA_TO);
+						
+						psta->keep_alive_trycnt++;						
+
+						continue;
+					}			
+				}					
+			}
+			if(psta->keep_alive_trycnt > 0 && psta->state & WIFI_STA_ALIVE_CHK_STATE)
+			{
+				psta->keep_alive_trycnt = 0;
+				psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+				DBG_871X("change to another methods to check alive if staion is at ps mode\n");
+			}	
+			
+#endif //CONFIG_80211N_HT
+#endif //CONFIG_ACTIVE_KEEP_ALIVE_CHECK	
+			if (psta->state & WIFI_SLEEP_STATE) {
+				if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+					//to check if alive by another methods if staion is at ps mode.					
+					psta->expire_to = pstapriv->expire_to;
+					psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+					//DBG_871X("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr));
+
+					//to update bcn with tim_bitmap for this station
+					pstapriv->tim_bitmap |= BIT(psta->aid);
+					update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
+
+					if(!pmlmeext->active_keep_alive_check)
+						continue;
+				}
+			}
+			#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+			if (pmlmeext->active_keep_alive_check) {
+				int stainfo_offset;
+
+				stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+				if (stainfo_offset_valid(stainfo_offset)) {
+					chk_alive_list[chk_alive_num++] = stainfo_offset;
+				}
+
+				continue;
+			}
+			#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+			updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+		}	
+		else
+		{
+			/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+			if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt)
+				&& padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME/pstapriv->asoc_list_cnt)/2)
+			){
+				DBG_871X("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__
+					, MAC_ARG(psta->hwaddr)
+					, psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt);
+				wakeup_sta_to_xmit(padapter, psta);
+			}
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+if (chk_alive_num) {
+
+	u8 backup_oper_channel=0;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	/* switch to correct channel of current network  before issue keep-alive frames */
+	if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+		backup_oper_channel = rtw_get_oper_ch(padapter);
+		SelectChannel(padapter, pmlmeext->cur_channel);
+	}
+
+	/* issue null data to check sta alive*/
+	for (i = 0; i < chk_alive_num; i++) {
+		int ret = _FAIL;
+
+		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+#ifdef CONFIG_ATMEL_RC_PATCH
+		if (_TRUE == _rtw_memcmp(  pstapriv->atmel_rc_pattern, psta->hwaddr, ETH_ALEN))
+			continue;
+		if (psta->flag_atmel_rc)
+			continue;
+#endif
+		if(!(psta->state &_FW_LINKED))
+			continue;		
+	
+		if (psta->state & WIFI_SLEEP_STATE)
+			ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50);
+		else
+			ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50);
+
+		psta->keep_alive_trycnt++;
+		if (ret == _SUCCESS)
+		{
+			DBG_871X("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr));
+			psta->expire_to = pstapriv->expire_to;
+			psta->keep_alive_trycnt = 0;
+			continue;
+		}
+		else if (psta->keep_alive_trycnt <= 3)
+		{
+			DBG_871X("ack check for asoc expire, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt);
+			psta->expire_to = 1;
+			continue;
+		}
+
+		psta->keep_alive_trycnt = 0;
+		DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		if (rtw_is_list_empty(&psta->asoc_list)==_FALSE) {
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);
+		}
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	}
+
+	if (backup_oper_channel>0) /* back to the original operation channel */
+		SelectChannel(padapter, backup_oper_channel);
+}
+#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */
+
+	associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+}
+
+void add_RATid(_adapter *padapter, struct sta_info *psta, u8 rssi_level)
+{	
+	int i;
+	u8 rf_type;
+	unsigned char sta_band = 0, shortGIrate = _FALSE;
+	u64 tx_ra_bitmap = 0;
+	struct ht_priv	*psta_ht = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+
+#ifdef CONFIG_80211N_HT
+	if(psta)
+		psta_ht = &psta->htpriv;
+	else
+		return;
+#endif //CONFIG_80211N_HT
+
+	if(!(psta->state & _FW_LINKED))
+		return;
+
+#if 0//gtest
+	if(get_rf_mimo_mode(padapter) == RTL8712_RF_2T2R)
+	{
+		//is this a 2r STA?
+		if((pstat->tx_ra_bitmap & 0x0ff00000) != 0 && !(priv->pshare->has_2r_sta & BIT(pstat->aid)))
+		{
+			priv->pshare->has_2r_sta |= BIT(pstat->aid);
+			if(rtw_read16(padapter, 0x102501f6) != 0xffff)
+			{
+				rtw_write16(padapter, 0x102501f6, 0xffff);
+				reset_1r_sta_RA(priv, 0xffff);
+				Switch_1SS_Antenna(priv, 3);
+			}
+		}
+		else// bg or 1R STA? 
+		{ 
+			if((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && pstat->ht_cap_len && priv->pshare->has_2r_sta == 0)
+			{
+				if(rtw_read16(padapter, 0x102501f6) != 0x7777)
+				{ // MCS7 SGI
+					rtw_write16(padapter, 0x102501f6,0x7777);
+					reset_1r_sta_RA(priv, 0x7777);
+					Switch_1SS_Antenna(priv, 2);
+				}
+			}
+		}
+		
+	}
+
+	if ((pstat->rssi_level < 1) || (pstat->rssi_level > 3)) 
+	{
+		if (pstat->rssi >= priv->pshare->rf_ft_var.raGoDownUpper)
+			pstat->rssi_level = 1;
+		else if ((pstat->rssi >= priv->pshare->rf_ft_var.raGoDown20MLower) ||
+			((priv->pshare->is_40m_bw) && (pstat->ht_cap_len) &&
+			(pstat->rssi >= priv->pshare->rf_ft_var.raGoDown40MLower) &&
+			(pstat->ht_cap_buf.ht_cap_info & cpu_to_le16(_HTCAP_SUPPORT_CH_WDTH_))))
+			pstat->rssi_level = 2;
+		else
+			pstat->rssi_level = 3;
+	}
+
+	// rate adaptive by rssi
+	if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) && pstat->ht_cap_len)
+	{
+		if ((get_rf_mimo_mode(priv) == MIMO_1T2R) || (get_rf_mimo_mode(priv) == MIMO_1T1R))
+		{
+			switch (pstat->rssi_level) {
+				case 1:
+					pstat->tx_ra_bitmap &= 0x100f0000;
+					break;
+				case 2:
+					pstat->tx_ra_bitmap &= 0x100ff000;
+					break;
+				case 3:
+					if (priv->pshare->is_40m_bw)
+						pstat->tx_ra_bitmap &= 0x100ff005;
+					else
+						pstat->tx_ra_bitmap &= 0x100ff001;
+
+					break;
+			}
+		}
+		else 
+		{
+			switch (pstat->rssi_level) {
+				case 1:
+					pstat->tx_ra_bitmap &= 0x1f0f0000;
+					break;
+				case 2:
+					pstat->tx_ra_bitmap &= 0x1f0ff000;
+					break;
+				case 3:
+					if (priv->pshare->is_40m_bw)
+						pstat->tx_ra_bitmap &= 0x000ff005;
+					else
+						pstat->tx_ra_bitmap &= 0x000ff001;
+
+					break;
+			}
+
+			// Don't need to mask high rates due to new rate adaptive parameters
+			//if (pstat->is_broadcom_sta)		// use MCS12 as the highest rate vs. Broadcom sta
+			//	pstat->tx_ra_bitmap &= 0x81ffffff;
+
+			// NIC driver will report not supporting MCS15 and MCS14 in asoc req
+			//if (pstat->is_rtl8190_sta && !pstat->is_2t_mimo_sta)
+			//	pstat->tx_ra_bitmap &= 0x83ffffff;		// if Realtek 1x2 sta, don't use MCS15 and MCS14
+		}
+	}
+	else if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) && isErpSta(pstat))
+	{
+		switch (pstat->rssi_level) {
+			case 1:
+				pstat->tx_ra_bitmap &= 0x00000f00;
+				break;
+			case 2:
+				pstat->tx_ra_bitmap &= 0x00000ff0;
+				break;
+			case 3:
+				pstat->tx_ra_bitmap &= 0x00000ff5;
+				break;
+		}
+	}
+	else 
+	{
+		pstat->tx_ra_bitmap &= 0x0000000d;
+	}
+
+	// disable tx short GI when station cannot rx MCS15(AP is 2T2R)
+	// disable tx short GI when station cannot rx MCS7 (AP is 1T2R or 1T1R)
+	// if there is only 1r STA and we are 2T2R, DO NOT mask SGI rate
+	if ((!(pstat->tx_ra_bitmap & 0x8000000) && (priv->pshare->has_2r_sta > 0) && (get_rf_mimo_mode(padapter) == RTL8712_RF_2T2R)) ||
+		 (!(pstat->tx_ra_bitmap & 0x80000) && (get_rf_mimo_mode(padapter) != RTL8712_RF_2T2R)))
+	{
+		pstat->tx_ra_bitmap &= ~BIT(28);	
+	}
+#endif
+
+	rtw_hal_update_sta_rate_mask(padapter, psta);
+	tx_ra_bitmap = psta->ra_mask;
+
+	shortGIrate = query_ra_short_GI(psta);
+
+	if ( pcur_network->Configuration.DSConfig > 14 ) {
+		
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_5N ;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11A;
+
+		// 5G band
+		#ifdef CONFIG_80211AC_VHT
+		if (psta->vhtpriv.vht_option)  {
+			sta_band = WIRELESS_11_5AC;
+		}		
+		#endif
+		
+	} else {
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_24N;
+
+		if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11G;
+
+		if (tx_ra_bitmap & 0x0f)
+			sta_band |= WIRELESS_11B;
+	}
+
+	psta->wireless_mode = sta_band;
+	psta->raid = rtw_hal_networktype_to_raid(padapter, psta);
+	
+	if (psta->aid < NUM_STA)
+	{
+		u8	arg[4] = {0};
+
+		arg[0] = psta->mac_id;
+		arg[1] = psta->raid;
+		arg[2] = shortGIrate;
+		arg[3] = psta->init_rate;
+
+		DBG_871X("%s=> mac_id:%d , raid:%d , shortGIrate=%d, tx_ra_bitmap:0x%016llx, networkType:0x%02x\n", 
+			__FUNCTION__, psta->mac_id, psta->raid, shortGIrate, tx_ra_bitmap, psta->wireless_mode);
+			
+		rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level);
+	}
+	else 
+	{
+		DBG_871X("station aid %d exceed the max number\n", psta->aid);
+	}
+
+}
+
+void update_bmc_sta(_adapter *padapter)
+{
+	_irqL	irqL;
+	unsigned char	network_type;
+	int supportRateNum = 0;
+	u64 tx_ra_bitmap = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);	
+	WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;	
+	struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
+
+	if(psta)
+	{
+		psta->aid = 0;//default set to 0
+
+		pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+		psta->qos_option = 0;
+#ifdef CONFIG_80211N_HT	
+		psta->htpriv.ht_option = _FALSE;
+#endif //CONFIG_80211N_HT
+
+		psta->ieee8021x_blocked = 0;
+
+		_rtw_memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+		//psta->dot118021XPrivacy = _NO_PRIVACY_;//!!! remove it, because it has been set before this.
+
+		//prepare for add_RATid		
+		supportRateNum = rtw_get_rateset_len((u8*)&pcur_network->SupportedRates);
+		network_type = rtw_check_network_type((u8*)&pcur_network->SupportedRates, supportRateNum, pcur_network->Configuration.DSConfig);
+		if (IsSupportedTxCCK(network_type)) {
+			network_type = WIRELESS_11B;
+		}
+		else if (network_type == WIRELESS_INVALID) { // error handling
+			if ( pcur_network->Configuration.DSConfig > 14 )
+				network_type = WIRELESS_11A;
+			else
+				network_type = WIRELESS_11B;
+		}
+		update_sta_basic_rate(psta, network_type);
+		psta->wireless_mode = network_type;
+
+		rtw_hal_update_sta_rate_mask(padapter, psta);
+		tx_ra_bitmap = psta->ra_mask;
+
+		psta->raid = rtw_hal_networktype_to_raid(padapter,psta);
+
+		//ap mode
+		rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE);
+
+		//if(pHalData->fw_ractrl == _TRUE)
+		{
+			u8	arg[4] = {0};
+
+			arg[0] = psta->mac_id;
+			arg[1] = psta->raid;
+			arg[2] = 0;
+			arg[3] = psta->init_rate;
+
+			DBG_871X("%s=> mac_id:%d , raid:%d , bitmap=0x%016llx\n", 
+				__FUNCTION__ , psta->mac_id, psta->raid , tx_ra_bitmap);
+
+			rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0);
+		}
+
+		rtw_sta_media_status_rpt(padapter, psta, 1);
+
+		_enter_critical_bh(&psta->lock, &irqL);
+		psta->state = _FW_LINKED;
+		_exit_critical_bh(&psta->lock, &irqL);
+
+	}
+	else
+	{
+		DBG_871X("add_RATid_bmc_sta error!\n");
+	}
+		
+}
+
+//notes:
+//AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode 
+//MAC_ID = AID+1 for sta in ap/adhoc mode 
+//MAC_ID = 1 for bc/mc for sta/ap/adhoc
+//MAC_ID = 0 for bssid for sta/ap/adhoc
+//CAM_ID = //0~3 for default key, cmd_id=macid + 3, macid=aid+1;
+
+void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta)
+{	
+	_irqL	irqL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+#ifdef CONFIG_80211N_HT
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+	struct ht_priv	*phtpriv_sta = &psta->htpriv;
+#endif //CONFIG_80211N_HT
+	u8	cur_ldpc_cap=0, cur_stbc_cap=0, cur_beamform_cap=0;
+	//set intf_tag to if1
+	//psta->intf_tag = 0;
+
+        DBG_871X("%s\n",__FUNCTION__);
+
+	//psta->mac_id = psta->aid+4;
+	//psta->mac_id = psta->aid+1;//alloc macid when call rtw_alloc_stainfo(),
+		                                       //release macid when call rtw_free_stainfo()
+
+	//ap mode
+	rtw_hal_set_odm_var(padapter,HAL_ODM_STA_INFO,psta,_TRUE);
+	
+	if(psecuritypriv->dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)
+		psta->ieee8021x_blocked = _TRUE;
+	else
+		psta->ieee8021x_blocked = _FALSE;
+	
+
+	//update sta's cap
+	
+	//ERP
+	VCS_update(padapter, psta);
+#ifdef CONFIG_80211N_HT	
+	//HT related cap
+	if(phtpriv_sta->ht_option)
+	{
+		//check if sta supports rx ampdu
+		phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+		phtpriv_sta->rx_ampdu_min_spacing = (phtpriv_sta->ht_cap.ampdu_params_info&IEEE80211_HT_CAP_AMPDU_DENSITY)>>2;
+	
+		// bwmode
+		if((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH))
+		{			
+			psta->bw_mode = CHANNEL_WIDTH_40;
+		}
+		else
+		{			
+			psta->bw_mode = CHANNEL_WIDTH_20;
+		}
+
+		if (psta->ht_40mhz_intolerant)
+			psta->bw_mode = CHANNEL_WIDTH_20;
+		
+		if(pmlmeext->cur_bwmode < psta->bw_mode)
+		{
+			psta->bw_mode = pmlmeext->cur_bwmode;
+		}
+
+		phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+
+
+		//check if sta support s Short GI 20M 
+		if((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+		{
+			phtpriv_sta->sgi_20m = _TRUE;
+		}
+		
+		//check if sta support s Short GI 40M 
+		if((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40))
+		{
+			if(psta->bw_mode == CHANNEL_WIDTH_40) //according to psta->bw_mode
+				phtpriv_sta->sgi_40m = _TRUE;
+			else
+				phtpriv_sta->sgi_40m = _FALSE;
+		}
+
+		psta->qos_option = _TRUE;
+
+		// B0 Config LDPC Coding Capability
+		if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) && 
+			GET_HT_CAP_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap)))
+		{
+			SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX));
+			DBG_871X("Enable HT Tx LDPC for STA(%d)\n",psta->aid);
+		}
+
+		// B7 B8 B9 Config STBC setting
+		if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) &&
+			GET_HT_CAP_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap)))
+		{
+			SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX) );
+			DBG_871X("Enable HT Tx STBC for STA(%d)\n",psta->aid);
+		}
+
+#ifdef CONFIG_BEAMFORMING
+		// Config Tx beamforming setting
+		if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && 
+			GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP((u8 *)(&phtpriv_sta->ht_cap)))
+		{
+			SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE);
+		}
+
+		if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) &&
+			GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP((u8 *)(&phtpriv_sta->ht_cap)))
+		{
+			SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE);
+		}
+
+		if (cur_beamform_cap) {
+			DBG_871X("Client STA(%d) HT Beamforming Cap = 0x%02X\n", psta->aid, cur_beamform_cap);
+		}
+#endif //CONFIG_BEAMFORMING
+	}
+	else
+	{
+		phtpriv_sta->ampdu_enable = _FALSE;
+		
+		phtpriv_sta->sgi_20m = _FALSE;
+		phtpriv_sta->sgi_40m = _FALSE;
+		psta->bw_mode = CHANNEL_WIDTH_20;
+		phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	}
+
+	phtpriv_sta->ldpc_cap = cur_ldpc_cap;
+	phtpriv_sta->stbc_cap = cur_stbc_cap;
+	phtpriv_sta->beamform_cap = cur_beamform_cap;
+
+	//Rx AMPDU
+	send_delba(padapter, 0, psta->hwaddr);// recipient
+	
+	//TX AMPDU
+	send_delba(padapter, 1, psta->hwaddr);// // originator
+	phtpriv_sta->agg_enable_bitmap = 0x0;//reset
+	phtpriv_sta->candidate_tid_bitmap = 0x0;//reset
+#endif //CONFIG_80211N_HT
+
+#ifdef CONFIG_80211AC_VHT
+	update_sta_vht_info_apmode(padapter, psta);
+#endif
+
+	update_ldpc_stbc_cap(psta);
+
+	//todo: init other variables
+	
+	_rtw_memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+
+	//add ratid
+	//add_RATid(padapter, psta);//move to ap_sta_info_defer_update()
+
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state |= _FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+	
+
+}
+
+static void update_ap_info(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+#ifdef CONFIG_80211N_HT
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+#endif //CONFIG_80211N_HT
+
+	psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+	psta->bssratelen = rtw_get_rateset_len(pnetwork->SupportedRates);
+	_rtw_memcpy(psta->bssrateset, pnetwork->SupportedRates, psta->bssratelen);
+
+#ifdef CONFIG_80211N_HT	
+	//HT related cap
+	if(phtpriv_ap->ht_option)
+	{
+		//check if sta supports rx ampdu
+		//phtpriv_ap->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+		//check if sta support s Short GI 20M
+		if((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20))
+		{
+			phtpriv_ap->sgi_20m = _TRUE;
+		}
+		//check if sta support s Short GI 40M
+		if((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40))
+		{
+			phtpriv_ap->sgi_40m = _TRUE;
+		}
+
+		psta->qos_option = _TRUE;
+	}
+	else
+	{
+		phtpriv_ap->ampdu_enable = _FALSE;
+		
+		phtpriv_ap->sgi_20m = _FALSE;
+		phtpriv_ap->sgi_40m = _FALSE;
+	}
+
+	psta->bw_mode = pmlmeext->cur_bwmode;
+	phtpriv_ap->ch_offset = pmlmeext->cur_ch_offset;
+
+	phtpriv_ap->agg_enable_bitmap = 0x0;//reset
+	phtpriv_ap->candidate_tid_bitmap = 0x0;//reset
+
+	_rtw_memcpy(&psta->htpriv, &pmlmepriv->htpriv, sizeof(struct ht_priv));
+
+#ifdef CONFIG_80211AC_VHT
+	_rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv));
+#endif //CONFIG_80211AC_VHT
+
+#endif //CONFIG_80211N_HT
+
+	psta->state |= WIFI_AP_STATE; /* Aries, add,fix bug of flush_cam_entry at STOP AP mode , 0724 */
+}
+
+static void rtw_set_hw_wmm_param(_adapter *padapter)
+{
+	u8	ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
+	u8	acm_mask;
+	u16	TXOP;
+	u32	acParm, i;
+	u32	edca[4], inx[4];
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	struct registry_priv	 *pregpriv = &padapter->registrypriv;
+
+	acm_mask = 0;
+
+	if (IsSupported5G(pmlmeext->cur_wireless_mode) || 
+		(pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	if (pmlmeinfo->WMM_enable == 0) {
+		padapter->mlmepriv.acm_mask = 0;
+
+		AIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+		if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) {
+			ECWMin = 4;
+			ECWMax = 10;
+		} else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+			ECWMin = 5;
+			ECWMax = 10;
+		} else {
+			ECWMin = 4;
+			ECWMax = 10;
+		}
+
+		TXOP = 0;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 0x2f;
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+		
+	} else {
+		edca[0] = edca[1] = edca[2] = edca[3] = 0;
+
+		/*TODO:*/
+		acm_mask = 0;
+		padapter->mlmepriv.acm_mask = acm_mask;
+
+		/*
+		//BK
+		//AIFS = AIFSN * slot time + SIFS - r2t phy delay
+		*/
+		AIFS = (7 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 10;
+		TXOP = 0;		
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+		edca[XMIT_BK_QUEUE] = acParm;
+		DBG_871X("WMM(BK): %x\n", acParm);
+		
+		/* BE */
+		AIFS = (3 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 4;
+		ECWMax = 6;
+		TXOP = 0;		
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+		edca[XMIT_BE_QUEUE] = acParm;
+		DBG_871X("WMM(BE): %x\n", acParm);
+
+		/* VI */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 3;
+		ECWMax = 4;
+		TXOP = 94;		
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+		edca[XMIT_VI_QUEUE] = acParm;
+		DBG_871X("WMM(VI): %x\n", acParm);
+
+		/* VO */
+		AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime;
+		ECWMin = 2;
+		ECWMax = 3;
+		TXOP = 47;		
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+		rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+		edca[XMIT_VO_QUEUE] = acParm;
+		DBG_871X("WMM(VO): %x\n", acParm);
+
+		
+		if (padapter->registrypriv.acm_method == 1)
+			rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask));
+		else
+			padapter->mlmepriv.acm_mask = acm_mask;
+
+		inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+		if (pregpriv->wifi_spec == 1) {
+			u32	j, tmp, change_inx = _FALSE;
+
+			/* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+			for (i = 0 ; i < 4 ; i++) {
+				for (j = i+1 ; j < 4 ; j++) {
+					/* compare CW and AIFS */
+					if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
+						change_inx = _TRUE;
+					} else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+						/* compare TXOP */
+						if ((edca[j] >> 16) > (edca[i] >> 16))
+							change_inx = _TRUE;
+					}
+				
+					if (change_inx) {
+						tmp = edca[i];
+						edca[i] = edca[j];
+						edca[j] = tmp;
+
+						tmp = inx[i];
+						inx[i] = inx[j];
+						inx[j] = tmp;
+
+						change_inx = _FALSE;
+					}
+				}
+			}
+		}
+
+		for (i = 0 ; i < 4 ; i++) {
+			pxmitpriv->wmm_para_seq[i] = inx[i];
+			DBG_871X("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+		}
+		
+	}
+	
+}
+
+static void update_hw_ht_param(_adapter *padapter)
+{
+	unsigned char		max_AMPDU_len;
+	unsigned char		min_MPDU_spacing;
+	struct registry_priv	 *pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	
+	DBG_871X("%s\n", __FUNCTION__);
+	
+
+	//handle A-MPDU parameter field
+	/* 	
+		AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+		AMPDU_para [4:2]:Min MPDU Start Spacing	
+	*/
+	max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;	
+	
+	min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;	
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+	//
+	// Config SM Power Save setting
+	//
+	pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+	if(pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+	{
+		/*u8 i;
+		//update the MCS rates
+		for (i = 0; i < 16; i++)
+		{
+			pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+		}*/
+		DBG_871X("%s(): WLAN_HT_CAP_SM_PS_STATIC\n",__FUNCTION__);
+	}
+
+	//
+	// Config current HT Protection mode.
+	//
+	//pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
+
+}
+
+static void rtw_ap_check_scan(_adapter *padapter)
+{
+	_irqL	irqL;
+	_list		*plist, *phead;
+	u32	delta_time, lifetime;
+	struct	wlan_network	*pnetwork = NULL;
+	WLAN_BSSID_EX *pbss = NULL;	
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);	
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	u8 do_scan = _FALSE;
+
+	lifetime = SCANQUEUE_LIFETIME; /* 20 sec */
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	if (rtw_end_of_queue_search(phead, get_next(phead)) == _TRUE)
+		if (padapter->registrypriv.wifi_spec)
+			do_scan = _TRUE;
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+	if (padapter->registrypriv.acs_auto_scan) {
+		do_scan = _TRUE;
+		rtw_acs_start(padapter, _TRUE);
+	}
+#endif
+		
+	if (_TRUE == do_scan) {
+		DBG_871X("%s : drv scans by itself and wait_completed\n", __func__);
+		rtw_drv_scan_by_self(padapter);
+		rtw_scan_wait_completed(padapter);
+	}
+	
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+	if (padapter->registrypriv.acs_auto_scan)
+		rtw_acs_start(padapter, _FALSE);
+#endif	
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		
+		if (rtw_end_of_queue_search(phead, plist) == _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		
+		if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
+			&& rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == _TRUE
+			&& _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))) {		
+			delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned);
+			
+			if (delta_time < lifetime) {
+
+				uint ie_len = 0;	
+				u8 *pbuf = NULL;
+				u8 *ie = NULL;
+		
+				pbss = &pnetwork->network;
+				ie = pbss->IEs;
+		
+				/*check if HT CAP INFO IE exists or not*/
+				pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss->IELength - _BEACON_IE_OFFSET_));
+				if (pbuf == NULL) {
+					/* HT CAP INFO IE don't exist, it is b/g mode bss.*/
+				
+					if (pmlmepriv->olbc == _FALSE)
+						pmlmepriv->olbc = _TRUE;
+
+					if (pmlmepriv->olbc_ht == _FALSE)
+						pmlmepriv->olbc_ht = _TRUE;
+				}						
+			}			
+		}
+
+		plist = get_next(plist);	
+		
+	}
+	
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	pmlmepriv->num_sta_no_ht = 0; /* reset to 0 after ap do scanning*/
+	
+}
+
+void rtw_start_bss_hdl_after_chbw_decided(_adapter *adapter)
+{
+	WLAN_BSSID_EX *pnetwork = &(adapter->mlmepriv.cur_network.network);
+	struct sta_info *sta = NULL;
+
+	/* update cur_wireless_mode */
+	update_wireless_mode(adapter);
+
+	/* update RRSR and RTS_INIT_RATE register after set channel and bandwidth */
+	UpdateBrateTbl(adapter, pnetwork->SupportedRates);
+	rtw_hal_set_hwreg(adapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+	/* update capability after cur_wireless_mode updated */
+	update_capinfo(adapter, rtw_get_capability(pnetwork));
+
+	/* update bc/mc sta_info */
+	update_bmc_sta(adapter);
+
+	/* update AP's sta info */
+	sta = rtw_get_stainfo(&adapter->stapriv, pnetwork->MacAddress);
+	if (!sta) {
+		DBG_871X(FUNC_ADPT_FMT" !sta for macaddr="MAC_FMT"\n", FUNC_ADPT_ARG(adapter), MAC_ARG(pnetwork->MacAddress));
+		rtw_warn_on(1);
+		return;
+	}
+
+	update_ap_info(adapter, sta);
+}
+
+void start_bss_network(_adapter *padapter, struct createbss_parm *parm)
+{
+#define DUMP_ADAPTERS_STATUS 0
+
+	u8 val8;
+	u16 bcn_interval;
+	u32	acparm;
+	struct registry_priv	 *pregpriv = &padapter->registrypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv* psecuritypriv=&(padapter->securitypriv);	
+	WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; /* used as input */
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network);
+	u8 req_ch, req_bw, req_offset;
+	bool ch_setting_changed = _FALSE;
+	u8 ch_to_set = 0, bw_to_set, offset_to_set;
+
+	if (parm->req_ch == 0) {
+		/* change to unspecificed ch, bw, offset, get from IE */
+		goto get_cbhw_from_ie;
+	} else if (parm->req_ch > 0) {
+		/* change ch, bw, offset */
+		req_ch = parm->req_ch;
+		req_bw = parm->req_bw;
+		req_offset = parm->req_offset;
+		goto change_chbw;
+	}
+
+	bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;	
+
+	//check if there is wps ie, 
+	//if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd,
+	//and at first time the security ie ( RSN/WPA IE) will not include in beacon.
+	if(NULL == rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+	{
+		pmlmeext->bstart_bss = _TRUE;
+	}
+
+	//todo: update wmm, ht cap
+	//pmlmeinfo->WMM_enable;
+	//pmlmeinfo->HT_enable;
+	if(pmlmepriv->qospriv.qos_option)
+		pmlmeinfo->WMM_enable = _TRUE;
+#ifdef CONFIG_80211N_HT
+	if(pmlmepriv->htpriv.ht_option)
+	{
+		pmlmeinfo->WMM_enable = _TRUE;
+		pmlmeinfo->HT_enable = _TRUE;
+		//pmlmeinfo->HT_info_enable = _TRUE;
+		//pmlmeinfo->HT_caps_enable = _TRUE;
+
+		update_hw_ht_param(padapter);
+	}
+#endif //#CONFIG_80211N_HT
+
+#ifdef CONFIG_80211AC_VHT
+	if(pmlmepriv->vhtpriv.vht_option) {
+		pmlmeinfo->VHT_enable = _TRUE;
+		update_hw_vht_param(padapter);
+	}
+#endif //CONFIG_80211AC_VHT
+
+	if(pmlmepriv->cur_network.join_res != _TRUE) //setting only at  first time
+	{
+		//WEP Key will be set before this function, do not clear CAM.
+		if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+			flush_all_cam_entry(padapter);	//clear CAM
+	}	
+
+	//set MSR to AP_Mode		
+	Set_MSR(padapter, _HW_STATE_AP_);	
+		
+	//Set BSSID REG
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+	//Set EDCA param reg
+#ifdef CONFIG_CONCURRENT_MODE
+	acparm = 0x005ea42b;
+#else
+	acparm = 0x002F3217; // VO
+#endif
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+	acparm = 0x005E4317; // VI
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+	//acparm = 0x00105320; // BE
+	acparm = 0x005ea42b;
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+	acparm = 0x0000A444; // BK
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+	//Set Security
+	val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf;
+	rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+	//Beacon Control related register
+	rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, NULL);
+
+#if 0
+	if(pmlmepriv->cur_network.join_res != _TRUE) //setting only at  first time
+	{
+		//u32 initialgain;
+
+		//initialgain = 0x1e;
+
+
+		//disable dynamic functions, such as high power, DIG
+		/*rtw_phydm_ability_backup(padapter);*/
+		/*rtw_phydm_func_disable_all(padapter);*/
+		
+		//turn on all dynamic functions	
+		/* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE);*/
+
+		/*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/
+	
+	}
+#endif
+
+get_cbhw_from_ie:
+	rtw_ies_get_chbw(pnetwork->IEs + sizeof(NDIS_802_11_FIXED_IEs)
+		, pnetwork->IELength - sizeof(NDIS_802_11_FIXED_IEs)
+		, &req_ch, &req_bw, &req_offset);
+
+change_chbw:
+	rtw_warn_on(req_ch == 0);
+
+	ch_setting_changed = rtw_ap_chbw_decision(padapter, req_ch, req_bw, req_offset
+		, &ch_to_set, &bw_to_set, &offset_to_set);
+
+	//let pnetwork_mlmeext == pnetwork_mlme.
+	_rtw_memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+	rtw_start_bss_hdl_after_chbw_decided(padapter);
+
+	#if defined(CONFIG_DFS_MASTER)
+	rtw_dfs_master_status_apply(padapter, MLME_AP_STARTED);
+	#endif
+
+	if (ch_to_set != 0)
+		set_channel_bwmode(padapter, ch_to_set, offset_to_set, bw_to_set);
+
+	if (DUMP_ADAPTERS_STATUS) {
+		DBG_871X(FUNC_ADPT_FMT" done\n", FUNC_ADPT_ARG(padapter));
+		dump_adapters_status(RTW_DBGDUMP , adapter_to_dvobj(padapter));
+	}
+
+	if (_TRUE == pmlmeext->bstart_bss
+		&& !check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)
+		&& !check_fwstate(pmlmepriv, WIFI_OP_CH_SWITCHING)
+		#ifdef CONFIG_CONCURRENT_MODE
+		&& !check_buddy_fwstate(padapter, WIFI_SITE_MONITOR)
+		#endif
+	) {
+
+	       if ((pmlmepriv->olbc == _TRUE) || (pmlmepriv->olbc_ht == _TRUE)) {
+
+			/* AP is not starting a 40 MHz BSS in presence of an 802.11g BSS. */
+
+			pmlmepriv->ht_op_mode &= (~HT_INFO_OPERATION_MODE_OP_MODE_MASK);
+			pmlmepriv->ht_op_mode |= OP_MODE_MAY_BE_LEGACY_STAS;
+			update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+		}
+
+		update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
+
+		#if !defined(CONFIG_INTERRUPT_BASED_TXBCN)
+		#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
+		/* other case will  tx beacon when bcn interrupt coming in. */
+		if (send_beacon(padapter) == _FAIL)
+			DBG_871X("issue_beacon, fail!\n");
+		#endif 
+		#endif /* !defined(CONFIG_INTERRUPT_BASED_TXBCN) */
+	}
+
+	/*Set EDCA param reg after update cur_wireless_mode & update_capinfo*/
+	if (pregpriv->wifi_spec == 1)
+		rtw_set_hw_wmm_param(padapter);
+	
+	/*pmlmeext->bstart_bss = _TRUE;*/
+}
+
+int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf,  int len)
+{
+	int ret=_SUCCESS;
+	u8 *p;
+	u8 *pHT_caps_ie=NULL;
+	u8 *pHT_info_ie=NULL;
+	u16 cap, ht_cap=_FALSE;
+	uint ie_len = 0;
+	int group_cipher, pairwise_cipher;	
+	u8	channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+	int supportRateNum = 0;
+	u8 OUI1[] = {0x00, 0x50, 0xf2,0x01};
+	u8 wps_oui[4]={0x0,0x50,0xf2,0x04};
+	u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};	
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;	
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;	
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *ie = pbss_network->IEs;
+	u8 vht_cap=_FALSE;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/* SSID */
+	/* Supported rates */
+	/* DS Params */
+	/* WLAN_EID_COUNTRY */
+	/* ERP Information element */
+	/* Extended supported rates */
+	/* WPA/WPA2 */
+	/* Wi-Fi Wireless Multimedia Extensions */
+	/* ht_capab, ht_oper */
+	/* WPS IE */
+
+	DBG_871X("%s, len=%d\n", __FUNCTION__, len);
+
+	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
+		return _FAIL;
+
+
+	if(len>MAX_IE_SZ)
+		return _FAIL;
+	
+	pbss_network->IELength = len;
+
+	_rtw_memset(ie, 0, MAX_IE_SZ);
+	
+	_rtw_memcpy(ie, pbuf, pbss_network->IELength);
+
+
+	if(pbss_network->InfrastructureMode!=Ndis802_11APMode)
+		return _FAIL;
+
+
+	rtw_ap_check_scan(padapter);
+	
+
+	pbss_network->Rssi = 0;
+
+	_rtw_memcpy(pbss_network->MacAddress, adapter_mac_addr(padapter), ETH_ALEN);
+	
+	//beacon interval
+	p = rtw_get_beacon_interval_from_ie(ie);//ie + 8;	// 8: TimeStamp, 2: Beacon Interval 2:Capability
+	//pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p);
+	pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+	
+	//capability
+	//cap = *(unsigned short *)rtw_get_capability_from_ie(ie);
+	//cap = le16_to_cpu(cap);
+	cap = RTW_GET_LE16(ie);
+
+	//SSID
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength -_BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+	{
+		_rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
+		_rtw_memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+		pbss_network->Ssid.SsidLength = ie_len;
+		#ifdef CONFIG_P2P
+		_rtw_memcpy(padapter->wdinfo.p2p_group_ssid, pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength);
+		padapter->wdinfo.p2p_group_ssid_len = pbss_network->Ssid.SsidLength;
+		#endif
+	}
+
+	//chnnel
+	channel = 0;
+	pbss_network->Configuration.Length = 0;
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+		channel = *(p + 2);
+
+	pbss_network->Configuration.DSConfig = channel;
+
+	
+	_rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
+	// get supported rates
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));	
+	if (p !=  NULL) 
+	{
+		_rtw_memcpy(supportRate, p+2, ie_len);	
+		supportRateNum = ie_len;
+	}
+	
+	//get ext_supported rates
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);	
+	if (p !=  NULL)
+	{
+		_rtw_memcpy(supportRate+supportRateNum, p+2, ie_len);
+		supportRateNum += ie_len;
+	
+	}
+
+	network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
+
+	rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
+
+
+	//parsing ERP_IE
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+	{
+		ERP_IE_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p);
+	}
+
+	//update privacy/security
+	if (cap & BIT(4))
+		pbss_network->Privacy = 1;
+	else
+		pbss_network->Privacy = 0;
+
+	psecuritypriv->wpa_psk = 0;
+
+	//wpa2
+	group_cipher = 0; pairwise_cipher = 0;
+	psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;	
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));		
+	if(p && ie_len>0)
+	{
+		if(rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS)
+		{
+			psecuritypriv->dot11AuthAlgrthm= dot11AuthAlgrthm_8021X;
+			
+			psecuritypriv->dot8021xalg = 1;//psk,  todo:802.1x
+			psecuritypriv->wpa_psk |= BIT(1);
+
+			psecuritypriv->wpa2_group_cipher = group_cipher;
+			psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+#if 0
+			switch(group_cipher)
+			{
+				case WPA_CIPHER_NONE:				
+				psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+				break;
+				case WPA_CIPHER_WEP40:				
+				psecuritypriv->wpa2_group_cipher = _WEP40_;
+				break;
+				case WPA_CIPHER_TKIP:				
+				psecuritypriv->wpa2_group_cipher = _TKIP_;
+				break;
+				case WPA_CIPHER_CCMP:				
+				psecuritypriv->wpa2_group_cipher = _AES_;				
+				break;
+				case WPA_CIPHER_WEP104:					
+				psecuritypriv->wpa2_group_cipher = _WEP104_;
+				break;
+			}
+
+			switch(pairwise_cipher)
+			{
+				case WPA_CIPHER_NONE:			
+				psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+				break;
+				case WPA_CIPHER_WEP40:			
+				psecuritypriv->wpa2_pairwise_cipher = _WEP40_;
+				break;
+				case WPA_CIPHER_TKIP:				
+				psecuritypriv->wpa2_pairwise_cipher = _TKIP_;
+				break;
+				case WPA_CIPHER_CCMP:			
+				psecuritypriv->wpa2_pairwise_cipher = _AES_;
+				break;
+				case WPA_CIPHER_WEP104:					
+				psecuritypriv->wpa2_pairwise_cipher = _WEP104_;
+				break;
+			}
+#endif			
+		}
+		
+	}
+
+	//wpa
+	ie_len = 0;
+	group_cipher = 0; pairwise_cipher = 0;
+	psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;	
+	for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2))
+	{
+		p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));		
+		if ((p) && (_rtw_memcmp(p+2, OUI1, 4)))
+		{
+			if(rtw_parse_wpa_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS)
+			{
+				psecuritypriv->dot11AuthAlgrthm= dot11AuthAlgrthm_8021X;
+				
+				psecuritypriv->dot8021xalg = 1;//psk,  todo:802.1x
+
+				psecuritypriv->wpa_psk |= BIT(0);
+
+				psecuritypriv->wpa_group_cipher = group_cipher;
+				psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;
+
+#if 0
+				switch(group_cipher)
+				{
+					case WPA_CIPHER_NONE:					
+					psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+					break;
+					case WPA_CIPHER_WEP40:					
+					psecuritypriv->wpa_group_cipher = _WEP40_;
+					break;
+					case WPA_CIPHER_TKIP:					
+					psecuritypriv->wpa_group_cipher = _TKIP_;
+					break;
+					case WPA_CIPHER_CCMP:					
+					psecuritypriv->wpa_group_cipher = _AES_;				
+					break;
+					case WPA_CIPHER_WEP104:					
+					psecuritypriv->wpa_group_cipher = _WEP104_;
+					break;
+				}
+
+				switch(pairwise_cipher)
+				{
+					case WPA_CIPHER_NONE:					
+					psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+					break;
+					case WPA_CIPHER_WEP40:					
+					psecuritypriv->wpa_pairwise_cipher = _WEP40_;
+					break;
+					case WPA_CIPHER_TKIP:					
+					psecuritypriv->wpa_pairwise_cipher = _TKIP_;
+					break;
+					case WPA_CIPHER_CCMP:					
+					psecuritypriv->wpa_pairwise_cipher = _AES_;
+					break;
+					case WPA_CIPHER_WEP104:					
+					psecuritypriv->wpa_pairwise_cipher = _WEP104_;
+					break;
+				}
+#endif				
+			}
+
+			break;
+			
+		}
+			
+		if ((p == NULL) || (ie_len == 0))
+		{
+				break;
+		}
+		
+	}
+
+	//wmm
+	ie_len = 0;
+	pmlmepriv->qospriv.qos_option = 0;
+	if(pregistrypriv->wmm_enable)
+	{
+		for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2))
+		{			
+			p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));	
+			if((p) && _rtw_memcmp(p+2, WMM_PARA_IE, 6)) 
+			{
+				pmlmepriv->qospriv.qos_option = 1;	
+
+				*(p+8) |= BIT(7);//QoS Info, support U-APSD
+				
+				/* disable all ACM bits since the WMM admission control is not supported */
+				*(p + 10) &= ~BIT(4); /* BE */
+				*(p + 14) &= ~BIT(4); /* BK */
+				*(p + 18) &= ~BIT(4); /* VI */
+				*(p + 22) &= ~BIT(4); /* VO */
+				
+				break;				
+			}
+			
+			if ((p == NULL) || (ie_len == 0))
+			{
+				break;
+			}			
+		}		
+	}
+#ifdef CONFIG_80211N_HT
+	//parsing HT_CAP_IE
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+	{
+		u8 rf_type=0;
+		HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor=MAX_AMPDU_FACTOR_64K;
+		struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+		if (0) {
+			DBG_871X(FUNC_ADPT_FMT" HT_CAP_IE from upper layer:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, p+2, ie_len);
+		}
+
+		pHT_caps_ie=p;
+
+		ht_cap = _TRUE;
+		network_type |= WIRELESS_11_24N;
+
+		rtw_ht_use_default_setting(padapter);
+
+		/* Update HT Capabilities Info field */
+		if (pmlmepriv->htpriv.sgi_20m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_20);
+
+		if (pmlmepriv->htpriv.sgi_40m == _FALSE)
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_40);
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX))
+		{
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_LDPC_CODING);
+		}
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX))
+		{
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_TX_STBC);
+		}		
+
+		if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX))
+		{
+			pht_cap->cap_info &= ~(IEEE80211_HT_CAP_RX_STBC_3R);
+		}
+
+		/* Update A-MPDU Parameters field */
+		pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR|IEEE80211_HT_CAP_AMPDU_DENSITY);
+
+		if((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+			(psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+		{
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+		}	
+		else
+		{
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);	
+		}	
+
+		rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+		pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); //set  Max Rx AMPDU size  to 64K
+		
+		_rtw_memcpy(&(pmlmeinfo->HT_caps), pht_cap, sizeof(struct HT_caps_element));
+
+		/* Update Supported MCS Set field */
+		{
+			int i;
+
+			rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+			/* RX MCS Bitmask */
+			switch(rf_type)
+			{
+				case RF_1T1R:
+				case RF_1T2R: //?
+					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_1R);
+					break;
+				case RF_2T2R:
+					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_2R);
+					break;
+				case RF_3T3R:
+					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_3R);
+					break;
+				default:
+					DBG_871X("[warning] rf_type %d is not expected\n", rf_type);
+			}
+			for (i = 0; i < 10; i++)
+				*(HT_CAP_ELE_RX_MCS_MAP(pht_cap)+i) &= padapter->mlmeextpriv.default_supported_mcs_set[i];
+		}
+
+#ifdef CONFIG_BEAMFORMING
+		// Use registry value to enable HT Beamforming.
+		// ToDo: use configure file to set these capability.
+		pht_cap->tx_BF_cap_info = 0;
+
+		// HT Beamformer
+		if(TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE))
+		{
+			// Transmit NDP Capable
+			SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(pht_cap, 1);
+			// Explicit Compressed Steering Capable
+			SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pht_cap, 1);
+			// Compressed Steering Number Antennas
+			SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, 1);
+		}
+
+		// HT Beamformee
+		if(TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
+		{
+			// Receive NDP Capable
+			SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(pht_cap, 1);
+			// Explicit Compressed Beamforming Feedback Capable
+			SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pht_cap, 2);
+		}
+#endif //CONFIG_BEAMFORMING
+
+		_rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+
+		if (0) {
+			DBG_871X(FUNC_ADPT_FMT" HT_CAP_IE driver masked:\n", FUNC_ADPT_ARG(padapter));
+			dump_ht_cap_ie_content(RTW_DBGDUMP, p+2, ie_len);
+		}
+	}
+
+	//parsing HT_INFO_IE
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+	{
+		pHT_info_ie=p;
+	}
+#endif //CONFIG_80211N_HT
+	switch(network_type)
+	{
+		case WIRELESS_11B:
+			pbss_network->NetworkTypeInUse = Ndis802_11DS;
+			break;	
+		case WIRELESS_11G:
+		case WIRELESS_11BG:
+             case WIRELESS_11G_24N:
+		case WIRELESS_11BG_24N:
+			pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+			break;
+		case WIRELESS_11A:
+			pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+			break;
+		default :
+			pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+			break;
+	}
+	
+	pmlmepriv->cur_network.network_type = network_type;
+
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->htpriv.ht_option = _FALSE;
+
+	if( (psecuritypriv->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) ||
+		      (psecuritypriv->wpa_pairwise_cipher&WPA_CIPHER_TKIP))
+	{	
+		//todo:
+		//ht_cap = _FALSE;
+	}
+		      
+	//ht_cap	
+	if(pregistrypriv->ht_enable && ht_cap==_TRUE)
+	{		
+		pmlmepriv->htpriv.ht_option = _TRUE;
+		pmlmepriv->qospriv.qos_option = 1;
+
+		if(pregistrypriv->ampdu_enable==1)
+		{
+			pmlmepriv->htpriv.ampdu_enable = _TRUE;
+		}
+
+		HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie);
+		
+		HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie);
+	}
+#endif
+
+#ifdef CONFIG_80211AC_VHT
+
+	//Parsing VHT CAP IE
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if(p && ie_len>0)
+	{	
+		vht_cap = _TRUE; 
+	}
+	//Parsing VHT OPERATION IE
+	
+
+	pmlmepriv->vhtpriv.vht_option = _FALSE;
+	// if channel in 5G band, then add vht ie .
+	if ((pbss_network->Configuration.DSConfig > 14) && 
+		(pmlmepriv->htpriv.ht_option == _TRUE) &&
+		(pregistrypriv->vht_enable)) 
+	{
+		if(vht_cap == _TRUE)
+		{
+			pmlmepriv->vhtpriv.vht_option = _TRUE;
+		}
+		else if(pregistrypriv->vht_enable == 2) // auto enabled
+		{
+			u8	cap_len, operation_len;
+
+			rtw_vht_use_default_setting(padapter);
+
+			{
+				/* VHT Operation mode notifiy bit in Extended IE (127) */
+				uint len = 0;
+				
+				SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1);
+				pmlmepriv->ext_capab_ie_len = 10;
+				rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
+				pbss_network->IELength += pmlmepriv->ext_capab_ie_len;
+			}
+			
+			// VHT Capabilities element
+			cap_len = rtw_build_vht_cap_ie(padapter, pbss_network->IEs + pbss_network->IELength);
+			pbss_network->IELength += cap_len;
+
+			// VHT Operation element
+			operation_len = rtw_build_vht_operation_ie(padapter, pbss_network->IEs + pbss_network->IELength, pbss_network->Configuration.DSConfig);
+			pbss_network->IELength += operation_len;
+
+			pmlmepriv->vhtpriv.vht_option = _TRUE;
+		}		
+	}
+#endif //CONFIG_80211AC_VHT
+
+	pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX  *)pbss_network);
+
+	rtw_ies_get_chbw(pbss_network->IEs + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_
+		, &pmlmepriv->ori_ch, &pmlmepriv->ori_bw, &pmlmepriv->ori_offset);
+	rtw_warn_on(pmlmepriv->ori_ch == 0);
+
+{
+	/* alloc sta_info for ap itself */
+
+	struct sta_info *sta;
+
+	sta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+	if (!sta) {
+		sta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+		if (sta == NULL) 
+			return _FAIL;
+	}
+}
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK);
+
+	rtw_indicate_connect( padapter);
+
+	pmlmepriv->cur_network.join_res = _TRUE;//for check if already set beacon
+		
+	//update bc/mc sta_info
+	//update_bmc_sta(padapter);
+
+	return ret;
+
+}
+
+void rtw_set_macaddr_acl(_adapter *padapter, int mode)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+	DBG_871X("%s, mode=%d\n", __func__, mode);
+
+	pacl_list->mode = mode;
+}
+
+int rtw_acl_add_sta(_adapter *padapter, u8 *addr)
+{
+	_irqL irqL;
+	_list	*plist, *phead;
+	u8 added = _FALSE;
+	int i, ret=0;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	_queue	*pacl_node_q =&pacl_list->acl_node_q;	
+
+	DBG_871X("%s(acl_num=%d)=" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr));	
+
+	if((NUM_ACL-1) < pacl_list->num)
+		return (-1);	
+
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+		
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+	{
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if(_rtw_memcmp(paclnode->addr, addr, ETH_ALEN))
+		{
+			if(paclnode->valid == _TRUE)
+			{
+				added = _TRUE;
+				DBG_871X("%s, sta has been added\n", __func__);
+				break;
+			}
+		}		
+	}
+	
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+
+	if(added == _TRUE)
+		return ret;
+	
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	for(i=0; i< NUM_ACL; i++)
+	{
+		paclnode = &pacl_list->aclnode[i];
+
+		if(paclnode->valid == _FALSE)
+		{
+			_rtw_init_listhead(&paclnode->list);
+	
+			_rtw_memcpy(paclnode->addr, addr, ETH_ALEN);
+		
+			paclnode->valid = _TRUE;
+
+			rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q));
+	
+			pacl_list->num++;
+
+			break;
+		}
+	}
+
+	DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num);
+	
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	return ret;
+}
+
+int rtw_acl_remove_sta(_adapter *padapter, u8 *addr)
+{
+	_irqL irqL;
+	_list	*plist, *phead;
+	int i, ret=0;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	_queue	*pacl_node_q =&pacl_list->acl_node_q;
+	u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };	//Baddr is used for clearing acl_list
+
+	DBG_871X("%s(acl_num=%d)=" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr));	
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+		
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+	{
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if(_rtw_memcmp(paclnode->addr, addr, ETH_ALEN) || _rtw_memcmp(baddr, addr, ETH_ALEN))
+		{
+			if(paclnode->valid == _TRUE)
+			{
+				paclnode->valid = _FALSE;
+
+				rtw_list_delete(&paclnode->list);
+				
+				pacl_list->num--;
+			}
+		}		
+	}
+	
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num);
+	
+	return ret;
+
+}
+
+u8 rtw_ap_set_pairwise_key(_adapter *padapter, struct sta_info *psta)
+{
+	struct cmd_obj*			ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;	
+	u8	res=_SUCCESS;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if ( ph2c == NULL){
+		res= _FAIL;
+		goto exit;
+	}
+
+	psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if(psetstakey_para==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+		res=_FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+
+	psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
+
+	_rtw_memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN);	
+	
+	_rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+
+exit:
+
+	return res;
+	
+}
+
+static int rtw_ap_set_key(_adapter *padapter, u8 *key, u8 alg, int keyid, u8 set_tx)
+{
+	u8 keylen;
+	struct cmd_obj* pcmd;
+	struct setkey_parm *psetkeyparm;
+	struct cmd_priv	*pcmdpriv=&(padapter->cmdpriv);	
+	int res=_SUCCESS;
+
+	//DBG_871X("%s\n", __FUNCTION__);
+	
+	pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(pcmd==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	psetkeyparm=(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm));
+	if(psetkeyparm==NULL){
+		rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+		
+	psetkeyparm->keyid=(u8)keyid;
+	if (is_wep_enc(alg))
+		padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid);
+
+	psetkeyparm->algorithm = alg;
+
+	psetkeyparm->set_tx = set_tx;
+
+	switch(alg)
+	{
+		case _WEP40_:					
+			keylen = 5;
+			break;
+		case _WEP104_:
+			keylen = 13;			
+			break;
+		case _TKIP_:
+		case _TKIP_WTMIC_:
+		case _AES_:
+		default:
+			keylen = 16;
+	}
+
+	_rtw_memcpy(&(psetkeyparm->key[0]), key, keylen);
+	
+	pcmd->cmdcode = _SetKey_CMD_;
+	pcmd->parmbuf = (u8 *)psetkeyparm;   
+	pcmd->cmdsz =  (sizeof(struct setkey_parm));  
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+
+	_rtw_init_listhead(&pcmd->list);
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+	return res;
+}
+
+int rtw_ap_set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, 1);
+}
+
+int rtw_ap_set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx)
+{
+	u8 alg;
+
+	switch(keylen)
+	{
+		case 5:
+			alg =_WEP40_;			
+			break;
+		case 13:
+			alg =_WEP104_;			
+			break;
+		default:
+			alg =_NO_PRIVACY_;			
+	}
+
+	DBG_871X("%s\n", __FUNCTION__);
+
+	return rtw_ap_set_key(padapter, key, alg, keyid, set_tx);
+}
+
+u8 rtw_ap_bmc_frames_hdl(_adapter *padapter)
+{
+#define HIQ_XMIT_COUNTS (6)
+	_irqL irqL;
+	struct sta_info *psta_bmc;
+	_list	*xmitframe_plist, *xmitframe_phead;
+	struct xmit_frame *pxmitframe = NULL;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct sta_priv  *pstapriv = &padapter->stapriv;
+	bool update_tim = _FALSE;
+
+
+	if (padapter->registrypriv.wifi_spec != 1)
+		return H2C_SUCCESS;
+
+	
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if (!psta_bmc)
+		return H2C_SUCCESS;
+
+
+	_enter_critical_bh(&pxmitpriv->lock, &irqL);
+
+	if ((pstapriv->tim_bitmap & BIT(0)) && (psta_bmc->sleepq_len > 0)) {
+		int tx_counts = 0;
+		
+		_update_beacon(padapter, _TIM_IE_, NULL, _FALSE, "update TIM with TIB=1");
+
+		DBG_871X("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len);
+
+		xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+		xmitframe_plist = get_next(xmitframe_phead);
+
+		while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) {
+			pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+			xmitframe_plist = get_next(xmitframe_plist);
+
+			rtw_list_delete(&pxmitframe->list);
+
+			psta_bmc->sleepq_len--;
+			tx_counts++;
+			
+			if (psta_bmc->sleepq_len > 0)
+				pxmitframe->attrib.mdata = 1;
+			else
+				pxmitframe->attrib.mdata = 0;
+
+			if (tx_counts == HIQ_XMIT_COUNTS)
+				pxmitframe->attrib.mdata = 0;
+			
+			pxmitframe->attrib.triggered = 1;
+
+			if (xmitframe_hiq_filter(pxmitframe) == _TRUE)
+				pxmitframe->attrib.qsel = QSLT_HIGH;/*HIQ*/
+
+			rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
+
+			if (tx_counts == HIQ_XMIT_COUNTS)
+				break;
+			
+		}
+
+	} else {
+		if (psta_bmc->sleepq_len == 0) {
+			
+			/*DBG_871X("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len);*/
+			
+			if (pstapriv->tim_bitmap & BIT(0))
+				update_tim = _TRUE;
+
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			if (update_tim == _TRUE) {
+				DBG_871X("clear TIB\n");
+				_update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty");
+			}			
+		}
+	}
+
+	_exit_critical_bh(&pxmitpriv->lock, &irqL);
+
+/*
+	//HIQ Check
+	rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+
+	while (_FALSE == empty && rtw_get_passing_time_ms(start) < 3000)
+	{
+		rtw_msleep_os(100);
+		rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+	}
+
+
+	printk("check if hiq empty=%d\n", empty);
+*/
+
+	return H2C_SUCCESS;
+}
+
+#ifdef CONFIG_NATIVEAP_MLME
+
+static void associated_stainfo_update(_adapter *padapter, struct sta_info *psta, u32 sta_info_type)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	DBG_871X("%s: "MAC_FMT", updated_type=0x%x\n", __func__, MAC_ARG(psta->hwaddr), sta_info_type);
+	
+	if (sta_info_type & STA_INFO_UPDATE_BW) {
+
+		if ((psta->flags & WLAN_STA_HT) && !psta->ht_20mhz_set) {
+			if (pmlmepriv->sw_to_20mhz) {
+				psta->bw_mode = CHANNEL_WIDTH_20;
+				/*psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;*/
+				psta->htpriv.sgi_40m = _FALSE;				
+			} else {
+				/*TODO: Switch back to 40MHZ?80MHZ*/
+			}
+		}		
+	}
+
+/*
+	if (sta_info_type & STA_INFO_UPDATE_RATE) {
+		
+	}
+*/	
+
+	if (sta_info_type & STA_INFO_UPDATE_PROTECTION_MODE)
+		VCS_update(padapter, psta);
+	
+/*
+	if (sta_info_type & STA_INFO_UPDATE_CAP) {
+		
+	}
+
+	if (sta_info_type & STA_INFO_UPDATE_HT_CAP) {
+		
+	}
+
+	if (sta_info_type & STA_INFO_UPDATE_VHT_CAP) {
+		
+	}	
+*/
+
+}
+
+static void update_bcn_ext_capab_ie(_adapter *padapter)
+{
+	sint ie_len = 0;
+	unsigned char	*pbuf;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	u8 *ie = pnetwork->IEs; 
+	u8 null_extcap_data[8] = {0};
+	
+	pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (pbuf && ie_len > 0)
+		rtw_remove_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_);
+
+	if ((pmlmepriv->ext_capab_ie_len > 0) && 
+		(_rtw_memcmp(pmlmepriv->ext_capab_ie_data, null_extcap_data, sizeof(null_extcap_data)) == _FALSE))
+		rtw_add_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_, pmlmepriv->ext_capab_ie_data, pmlmepriv->ext_capab_ie_len);
+	
+}
+
+static void update_bcn_fixed_ie(_adapter *padapter)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_erpinfo_ie(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	DBG_871X("%s, ERP_enable=%d\n", __FUNCTION__, pmlmeinfo->ERP_enable);
+
+	if(!pmlmeinfo->ERP_enable)
+		return;
+
+	//parsing ERP_IE
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if(p && len>0)
+	{
+		PNDIS_802_11_VARIABLE_IEs pIE = (PNDIS_802_11_VARIABLE_IEs)p;
+
+		if (pmlmepriv->num_sta_non_erp == 1)
+			pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION);
+
+		if(pmlmepriv->num_sta_no_short_preamble > 0)
+			pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE);
+	
+		ERP_IE_handler(padapter, pIE);
+	}
+	
+}
+
+static void update_bcn_htcap_ie(_adapter *padapter)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_htinfo_ie(_adapter *padapter)
+{	
+	/*
+	u8 beacon_updated = _FALSE;
+	u32 sta_info_update_type = STA_INFO_UPDATE_NONE;	
+	*/
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;	
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE) 
+		return;
+
+	if (pmlmeinfo->HT_info_enable != 1)
+		return;
+
+
+	DBG_871X("%s current operation mode=0x%X\n",
+		   __FUNCTION__, pmlmepriv->ht_op_mode);
+
+	DBG_871X("num_sta_40mhz_intolerant(%d), 20mhz_width_req(%d), intolerant_ch_rpt(%d), olbc(%d)\n", 
+					pmlmepriv->num_sta_40mhz_intolerant, pmlmepriv->ht_20mhz_width_req, pmlmepriv->ht_intolerant_ch_reported, pmlmepriv->olbc);
+
+	/*parsing HT_INFO_IE, currently only update ht_op_mode - pht_info->infos[1] & pht_info->infos[2] for wifi logo test*/
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && len > 0) {
+		struct HT_info_element *pht_info = NULL;
+		
+		pht_info = (struct HT_info_element *)(p + 2);		
+
+		/* for STA Channel Width/Secondary Channel Offset*/
+		if ((pmlmepriv->sw_to_20mhz == 0) && (pmlmeext->cur_channel <= 14)) {
+			if ((pmlmepriv->num_sta_40mhz_intolerant > 0) || (pmlmepriv->ht_20mhz_width_req == _TRUE) 
+				|| (pmlmepriv->ht_intolerant_ch_reported == _TRUE) || (pmlmepriv->olbc == _TRUE)) {
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, 0);
+				SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 0);
+
+				pmlmepriv->sw_to_20mhz = 1;
+				/*
+				sta_info_update_type |= STA_INFO_UPDATE_BW;
+				beacon_updated = _TRUE;
+				*/
+	
+				DBG_871X("%s:switching to 20Mhz\n", __FUNCTION__);	
+
+				/*TODO : cur_bwmode/cur_ch_offset switches to 20Mhz*/
+			}
+		} else {
+
+			if ((pmlmepriv->num_sta_40mhz_intolerant == 0) && (pmlmepriv->ht_20mhz_width_req == _FALSE) 
+				&& (pmlmepriv->ht_intolerant_ch_reported == _FALSE) && (pmlmepriv->olbc == _FALSE)) {
+
+				if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_40) {
+					
+					SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 1);
+
+					SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, 
+					(pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ? 
+						HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE : HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW);
+					
+					pmlmepriv->sw_to_20mhz = 0;
+					/*
+					sta_info_update_type |= STA_INFO_UPDATE_BW;
+					beacon_updated = _TRUE;
+					*/
+					
+					DBG_871X("%s:switching back to 40Mhz\n", __FUNCTION__);	
+				}
+			}
+		}
+
+		/* to update  ht_op_mode*/
+		*(u16 *)(pht_info->infos + 1) = cpu_to_le16(pmlmepriv->ht_op_mode);
+		
+	}	
+
+	/*associated_clients_update(padapter, beacon_updated, sta_info_update_type);*/
+
+}
+
+static void update_bcn_rsn_ie(_adapter *padapter)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wpa_ie(_adapter *padapter)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+}
+
+static void update_bcn_wmm_ie(_adapter *padapter)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+	
+}
+
+static void update_bcn_wps_ie(_adapter *padapter)
+{
+	u8 *pwps_ie=NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie=NULL;
+	uint wps_ielen=0, wps_offset, remainder_ielen;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network);
+	unsigned char *ie = pnetwork->IEs;
+	u32 ielen = pnetwork->IELength;
+
+
+	DBG_871X("%s\n", __FUNCTION__);
+
+	pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+	
+	if(pwps_ie==NULL || wps_ielen==0)
+		return;
+
+	pwps_ie_src = pmlmepriv->wps_beacon_ie;
+	if(pwps_ie_src == NULL)
+		return;
+
+	wps_offset = (uint)(pwps_ie-ie);
+
+	premainder_ie = pwps_ie + wps_ielen;
+
+	remainder_ielen = ielen - wps_offset - wps_ielen;
+
+	if(remainder_ielen>0)
+	{
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if(pbackup_remainder_ie)
+			_rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	wps_ielen = (uint)pwps_ie_src[1];//to get ie data len
+	if((wps_offset+wps_ielen+2+remainder_ielen)<=MAX_IE_SZ)
+	{
+		_rtw_memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+		pwps_ie += (wps_ielen+2);
+
+		if(pbackup_remainder_ie)
+			_rtw_memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+		//update IELength
+		pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+	}
+
+	if(pbackup_remainder_ie)
+		rtw_mfree(pbackup_remainder_ie, remainder_ielen);
+	
+	// deal with the case without set_tx_beacon_cmd() in update_beacon() 
+#if defined( CONFIG_INTERRUPT_BASED_TXBCN ) || defined( CONFIG_PCI_HCI )
+	if( (pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+	{
+		u8 sr = 0;
+		rtw_get_wps_attr_content(pwps_ie_src,  wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8*)(&sr), NULL);
+	
+		if( sr ) {
+			set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			DBG_871X("%s, set WIFI_UNDER_WPS\n", __func__);
+		}
+	}
+#endif
+}
+
+static void update_bcn_p2p_ie(_adapter *padapter)
+{
+
+}
+
+static void update_bcn_vendor_spec_ie(_adapter *padapter, u8*oui)
+{
+	DBG_871X("%s\n", __FUNCTION__);
+
+	if(_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+	{
+		update_bcn_wpa_ie(padapter);
+	}
+	else if(_rtw_memcmp(WMM_OUI, oui, 4))
+	{
+		update_bcn_wmm_ie(padapter);
+	}
+	else if(_rtw_memcmp(WPS_OUI, oui, 4))
+	{
+		update_bcn_wps_ie(padapter);
+	}
+	else if(_rtw_memcmp(P2P_OUI, oui, 4))
+	{
+		update_bcn_p2p_ie(padapter);
+	}
+	else
+	{
+		DBG_871X("unknown OUI type!\n");
+ 	}
+	
+	
+}
+
+void _update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx, const char *tag)
+{
+	_irqL irqL;
+	struct mlme_priv *pmlmepriv;
+	struct mlme_ext_priv	*pmlmeext;
+	//struct mlme_ext_info	*pmlmeinfo;
+	
+	//DBG_871X("%s\n", __FUNCTION__);
+
+	if(!padapter)
+		return;
+
+	pmlmepriv = &(padapter->mlmepriv);
+	pmlmeext = &(padapter->mlmeextpriv);
+	//pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if(_FALSE == pmlmeext->bstart_bss)
+		return;
+
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	switch(ie_id)
+	{
+		case 0xFF:
+
+			update_bcn_fixed_ie(padapter);//8: TimeStamp, 2: Beacon Interval 2:Capability
+			
+			break;
+	
+		case _TIM_IE_:
+			
+			update_BCNTIM(padapter);
+			
+			break;
+
+		case _ERPINFO_IE_:
+
+			update_bcn_erpinfo_ie(padapter);
+
+			break;
+
+		case _HT_CAPABILITY_IE_:
+
+			update_bcn_htcap_ie(padapter);
+			
+			break;
+
+		case _RSN_IE_2_:
+
+			update_bcn_rsn_ie(padapter);
+
+			break;
+			
+		case _HT_ADD_INFO_IE_:
+
+			update_bcn_htinfo_ie(padapter);
+			
+			break;
+	
+		case _EXT_CAP_IE_:
+
+			update_bcn_ext_capab_ie(padapter);
+
+			break;
+	
+		case _VENDOR_SPECIFIC_IE_:
+
+			update_bcn_vendor_spec_ie(padapter, oui);
+			
+			break;
+			
+		default:
+			break;
+	}
+
+	pmlmepriv->update_bcn = _TRUE;
+	
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);		
+	
+#ifndef CONFIG_INTERRUPT_BASED_TXBCN 
+#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
+	if(tx)
+	{
+		//send_beacon(padapter);//send_beacon must execute on TSR level
+		if (0)
+			DBG_871X(FUNC_ADPT_FMT" ie_id:%u - %s\n", FUNC_ADPT_ARG(padapter), ie_id, tag);
+		set_tx_beacon_cmd(padapter);
+	}
+#else
+	{	
+		//PCI will issue beacon when BCN interrupt occurs.		
+	}
+#endif
+#endif //!CONFIG_INTERRUPT_BASED_TXBCN
+	
+}
+
+#ifdef CONFIG_80211N_HT
+
+void rtw_process_public_act_bsscoex(_adapter *padapter, u8 *pframe, uint frame_len)
+{
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);	
+	uint frame_body_len = frame_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+	if (psta == NULL) 
+		return;
+
+
+	category = frame_body[0];
+	action = frame_body[1];
+
+	if (frame_body_len > 0) {
+		if ((frame_body[2] == EID_BSSCoexistence) && (frame_body[3] > 0)) {			
+			u8 ie_data = frame_body[4];
+
+			if (ie_data & RTW_WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+				if (psta->ht_40mhz_intolerant == 0) {				
+					psta->ht_40mhz_intolerant = 1;
+					pmlmepriv->num_sta_40mhz_intolerant++;
+					beacon_updated = _TRUE;
+				}	
+			} else if (ie_data & RTW_WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ)	{				
+				if (pmlmepriv->ht_20mhz_width_req == _FALSE) {				
+					pmlmepriv->ht_20mhz_width_req = _TRUE;			
+					beacon_updated = _TRUE;
+				}	
+			} else
+				beacon_updated = _FALSE;
+		}		
+	}
+
+	if (frame_body_len > 8) {
+		/* if EID_BSSIntolerantChlReport ie exists */
+		if ((frame_body[5] == EID_BSSIntolerantChlReport) && (frame_body[6] > 0)) {
+			/*todo:*/
+			if (pmlmepriv->ht_intolerant_ch_reported == _FALSE) {				
+				pmlmepriv->ht_intolerant_ch_reported = _TRUE;			
+				beacon_updated = _TRUE;
+			}
+		}			
+	}
+
+	if (beacon_updated) {
+		
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE);
+	
+		associated_stainfo_update(padapter, psta, STA_INFO_UPDATE_BW);
+	}
+
+	
+	
+}
+
+void rtw_process_ht_action_smps(_adapter *padapter, u8 *ta, u8 ctrl_field)
+{
+	u8 e_field, m_field;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta = rtw_get_stainfo(pstapriv, ta);
+	if (psta == NULL) 
+		return;
+
+	e_field = (ctrl_field & BIT(0)) ? 1 : 0;
+	m_field = (ctrl_field & BIT(1)) ? 1 : 0;	
+
+	if (e_field) {
+
+		/* enable */
+		/* 0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/
+		 
+		if (m_field) /*mode*/
+			psta->htpriv.smps_cap = 1;
+		else
+			psta->htpriv.smps_cap = 0;
+	} else {
+		/*disable*/
+		psta->htpriv.smps_cap = 3;
+	}
+
+	rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta);
+
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+	in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+	however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+	(currently non-GF HT station is considered as non-HT STA also)
+*/
+static int rtw_ht_operation_update(_adapter *padapter)
+{
+	u16 cur_op_mode, new_op_mode;
+	int op_mode_changes = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+
+	if (pmlmepriv->htpriv.ht_option == _FALSE) 
+		return 0;
+	
+	/*if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+		return 0;*/
+
+	DBG_871X("%s current operation mode=0x%X\n",
+		   __FUNCTION__, pmlmepriv->ht_op_mode);
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+	    && pmlmepriv->num_sta_ht_no_gf) {
+		pmlmepriv->ht_op_mode |=
+			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+		   pmlmepriv->num_sta_ht_no_gf == 0) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	}
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+	    (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) {
+		pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+		   (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	}
+
+	/* Note: currently we switch to the MIXED op mode if HT non-greenfield
+	 * station is associated. Probably it's a theoretical case, since
+	 * it looks like all known HT STAs support greenfield.
+	 */
+	new_op_mode = 0;
+	if (pmlmepriv->num_sta_no_ht /*||
+	    (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)*/)
+		new_op_mode = OP_MODE_MIXED;
+	else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH)
+		 && pmlmepriv->num_sta_ht_20mhz)
+		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+	else if (pmlmepriv->olbc_ht)
+		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+	else
+		new_op_mode = OP_MODE_PURE;
+
+	cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+	if (cur_op_mode != new_op_mode) {
+		pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+		pmlmepriv->ht_op_mode |= new_op_mode;
+		op_mode_changes++;
+	}
+
+	DBG_871X("%s new operation mode=0x%X changes=%d\n",
+		   __FUNCTION__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+	
+}
+
+#endif /* CONFIG_80211N_HT */
+
+void associated_clients_update(_adapter *padapter, u8 updated, u32 sta_info_type)
+{
+	//update associcated stations cap.
+	if(updated == _TRUE)
+	{
+		_irqL irqL;
+		_list	*phead, *plist;
+		struct sta_info *psta=NULL;	
+		struct sta_priv *pstapriv = &padapter->stapriv;
+			
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		
+		phead = &pstapriv->asoc_list;
+		plist = get_next(phead);
+		
+		//check asoc_queue
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)	
+		{
+			psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		
+			plist = get_next(plist);
+
+			associated_stainfo_update(padapter, psta, sta_info_type);			
+		}
+
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	}		
+
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(_adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+	
+#if 0
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    !psta->no_short_preamble_set) {
+		psta->no_short_preamble_set = 1;
+		pmlmepriv->num_sta_no_short_preamble++;
+		if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && 
+		     (pmlmepriv->num_sta_no_short_preamble == 1))
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+
+	if(!(psta->flags & WLAN_STA_SHORT_PREAMBLE))	
+	{
+		if(!psta->no_short_preamble_set)
+		{
+			psta->no_short_preamble_set = 1;
+			
+			pmlmepriv->num_sta_no_short_preamble++;
+			
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && 
+		     		(pmlmepriv->num_sta_no_short_preamble == 1))
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, 0xFF, NULL, _TRUE);
+			}	
+			
+		}
+	}
+	else
+	{
+		if(psta->no_short_preamble_set)
+		{
+			psta->no_short_preamble_set = 0;
+			
+			pmlmepriv->num_sta_no_short_preamble--;
+			
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && 
+		     		(pmlmepriv->num_sta_no_short_preamble == 0))
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, 0xFF, NULL, _TRUE);
+			}	
+			
+		}
+	}
+
+#if 0
+	if (psta->flags & WLAN_STA_NONERP && !psta->nonerp_set) {
+		psta->nonerp_set = 1;
+		pmlmepriv->num_sta_non_erp++;
+		if (pmlmepriv->num_sta_non_erp == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+	if(psta->flags & WLAN_STA_NONERP)
+	{
+		if(!psta->nonerp_set)
+		{
+			psta->nonerp_set = 1;
+			
+			pmlmepriv->num_sta_non_erp++;
+			
+			if (pmlmepriv->num_sta_non_erp == 1)
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE);
+			}	
+		}
+		
+	}
+	else
+	{
+		if(psta->nonerp_set)
+		{
+			psta->nonerp_set = 0;
+			
+			pmlmepriv->num_sta_non_erp--;
+			
+			if (pmlmepriv->num_sta_non_erp == 0)
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE);
+			}	
+		}
+		
+	}
+
+
+#if 0
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT) &&
+	    !psta->no_short_slot_time_set) {
+		psta->no_short_slot_time_set = 1;
+		pmlmepriv->num_sta_no_short_slot_time++;
+		if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+		    (pmlmepriv->num_sta_no_short_slot_time == 1))
+			ieee802_11_set_beacons(hapd->iface);
+	}
+#endif
+
+	if(!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT))
+	{
+		if(!psta->no_short_slot_time_set)
+		{
+			psta->no_short_slot_time_set = 1;
+			
+			pmlmepriv->num_sta_no_short_slot_time++;
+			
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+		   		 (pmlmepriv->num_sta_no_short_slot_time == 1))
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, 0xFF, NULL, _TRUE);
+			}			
+			
+		}
+	}
+	else
+	{
+		if(psta->no_short_slot_time_set)
+		{
+			psta->no_short_slot_time_set = 0;
+			
+			pmlmepriv->num_sta_no_short_slot_time--;
+			
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+		   		 (pmlmepriv->num_sta_no_short_slot_time == 0))
+			{
+				beacon_updated = _TRUE;
+				update_beacon(padapter, 0xFF, NULL, _TRUE);
+			}			
+		}
+	}	
+	
+#ifdef CONFIG_80211N_HT
+
+	if (psta->flags & WLAN_STA_HT) 
+	{
+		u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info);
+			
+		DBG_871X("HT: STA " MAC_FMT " HT Capabilities "
+			   "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab);
+
+		if (psta->no_ht_set) {
+			psta->no_ht_set = 0;
+			pmlmepriv->num_sta_no_ht--;
+		}
+		
+		if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+			if (!psta->no_ht_gf_set) {
+				psta->no_ht_gf_set = 1;
+				pmlmepriv->num_sta_ht_no_gf++;
+			}
+			DBG_871X("%s STA " MAC_FMT " - no "
+				   "greenfield, num of non-gf stations %d\n",
+				   __FUNCTION__, MAC_ARG(psta->hwaddr),
+				   pmlmepriv->num_sta_ht_no_gf);
+		}
+		
+		if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
+			if (!psta->ht_20mhz_set) {
+				psta->ht_20mhz_set = 1;
+				pmlmepriv->num_sta_ht_20mhz++;
+			}
+			DBG_871X("%s STA " MAC_FMT " - 20 MHz HT, "
+				   "num of 20MHz HT STAs %d\n",
+				   __FUNCTION__, MAC_ARG(psta->hwaddr),
+				   pmlmepriv->num_sta_ht_20mhz);
+		}
+		
+
+		if (ht_capab & RTW_IEEE80211_HT_CAP_40MHZ_INTOLERANT) {
+
+			if (!psta->ht_40mhz_intolerant) {
+				psta->ht_40mhz_intolerant = 1;
+				pmlmepriv->num_sta_40mhz_intolerant++;
+				DBG_871X("%s STA " MAC_FMT " - HT_CAP_40MHZ_INTOLERANT is set\n" ,
+				   __FUNCTION__, MAC_ARG(psta->hwaddr));
+				beacon_updated = _TRUE;
+			}
+				
+/*
+			if (pmlmepriv->ht_40mhz_intolerant == _FALSE) {
+				
+				pmlmepriv->ht_40mhz_intolerant = _TRUE;				
+			
+				DBG_871X("%s STA " MAC_FMT " - HT_CAP_40MHZ_INTOLERANT is set\n" ,
+				   __FUNCTION__, MAC_ARG(psta->hwaddr));
+
+				beacon_updated = _TRUE;
+			}
+*/			
+
+			/*update ext_capab_ie_len & ext_capab_ie_data for beacon, probersp, assocrsp.*/
+			if (pmlmepriv->ext_capab_ie_len == 0)
+				pmlmepriv->ext_capab_ie_len = 1;
+			SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 1);
+
+			update_beacon(padapter, _EXT_CAP_IE_, NULL, _FALSE);
+		}		
+		
+	} 
+	else 
+	{
+		if (!psta->no_ht_set) {
+			psta->no_ht_set = 1;
+			pmlmepriv->num_sta_no_ht++;
+		}
+		if(pmlmepriv->htpriv.ht_option == _TRUE) {		
+			DBG_871X("%s STA " MAC_FMT
+				   " - no HT, num of non-HT stations %d\n",
+				   __FUNCTION__, MAC_ARG(psta->hwaddr),
+				   pmlmepriv->num_sta_no_ht);
+		}
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE);
+		/*beacon_updated = _TRUE;*/
+	}	
+	
+#endif /* CONFIG_80211N_HT */
+
+	//update associcated stations cap.
+	associated_clients_update(padapter,  beacon_updated, STA_INFO_UPDATE_ALL);
+
+	DBG_871X("%s, updated=%d\n", __func__, beacon_updated);
+
+}
+
+u8 bss_cap_update_on_sta_leave(_adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+	if(!psta)
+		return beacon_updated;
+
+	if (psta->no_short_preamble_set) {
+		psta->no_short_preamble_set = 0;
+		pmlmepriv->num_sta_no_short_preamble--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+		    && pmlmepriv->num_sta_no_short_preamble == 0)
+		{
+			beacon_updated = _TRUE;
+			update_beacon(padapter, 0xFF, NULL, _TRUE);
+		}	
+	}	
+
+	if (psta->nonerp_set) {
+		psta->nonerp_set = 0;		
+		pmlmepriv->num_sta_non_erp--;
+		if (pmlmepriv->num_sta_non_erp == 0)
+		{
+			beacon_updated = _TRUE;
+			update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE);
+		}	
+	}
+
+	if (psta->no_short_slot_time_set) {
+		psta->no_short_slot_time_set = 0;
+		pmlmepriv->num_sta_no_short_slot_time--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+		    && pmlmepriv->num_sta_no_short_slot_time == 0)
+		{
+			beacon_updated = _TRUE;
+			update_beacon(padapter, 0xFF, NULL, _TRUE);
+		}	
+	}
+	
+#ifdef CONFIG_80211N_HT
+
+	if (psta->no_ht_gf_set) {
+		psta->no_ht_gf_set = 0;
+		pmlmepriv->num_sta_ht_no_gf--;
+	}
+
+	if (psta->no_ht_set) {
+		psta->no_ht_set = 0;
+		pmlmepriv->num_sta_no_ht--;
+	}
+
+	if (psta->ht_20mhz_set) {
+		psta->ht_20mhz_set = 0;
+		pmlmepriv->num_sta_ht_20mhz--;
+	}
+
+	if (psta->ht_40mhz_intolerant) {
+		psta->ht_40mhz_intolerant = 0;
+		pmlmepriv->num_sta_40mhz_intolerant--;
+
+		/*update ext_capab_ie_len & ext_capab_ie_data for beacon, probersp, assocrsp.*/
+		if ((pmlmepriv->ext_capab_ie_len > 0) && (pmlmepriv->num_sta_40mhz_intolerant == 0)) {
+			SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 0);
+			update_beacon(padapter, _EXT_CAP_IE_, NULL, _FALSE);
+		}
+		
+		beacon_updated = _TRUE;
+
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE);
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE);
+	}
+	
+#endif /* CONFIG_80211N_HT */
+
+	/* update associated stations cap.
+	associated_clients_update(padapter,  beacon_updated, STA_INFO_UPDATE_ALL); //move it to avoid deadlock
+	*/
+	
+	DBG_871X("%s, updated=%d\n", __func__, beacon_updated);
+
+	return beacon_updated;
+
+}
+
+u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason, bool enqueue)
+{
+	_irqL irqL;
+	u8 beacon_updated = _FALSE;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if(!psta)
+		return beacon_updated;
+
+	if (active == _TRUE)
+	{
+#ifdef CONFIG_80211N_HT
+		//tear down Rx AMPDU
+		send_delba(padapter, 0, psta->hwaddr);// recipient
+	
+		//tear down TX AMPDU
+		send_delba(padapter, 1, psta->hwaddr);// // originator
+		
+#endif //CONFIG_80211N_HT
+
+		issue_deauth(padapter, psta->hwaddr, reason);
+	}
+
+#ifdef CONFIG_BEAMFORMING
+	beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_LEAVE, psta->hwaddr, ETH_ALEN, 1);
+#endif
+
+	psta->htpriv.agg_enable_bitmap = 0x0;//reset
+	psta->htpriv.candidate_tid_bitmap = 0x0;//reset
+
+	//clear cam entry / key
+	rtw_clearstakey_cmd(padapter, psta, enqueue);
+
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state &= ~_FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+	#ifdef CONFIG_IOCTL_CFG80211
+	if (1) {
+		#ifdef COMPAT_KERNEL_RELEASE
+		rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason);
+		#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+		rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason);
+		#else //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+		/* will call rtw_cfg80211_indicate_sta_disassoc() in cmd_thread for old API context */
+		#endif //(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+	} else
+	#endif //CONFIG_IOCTL_CFG80211
+	{
+		rtw_indicate_sta_disassoc_event(padapter, psta);
+	}
+
+	report_del_sta_event(padapter, psta->hwaddr, reason, enqueue);
+
+	beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
+
+	//_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);					
+	rtw_free_stainfo(padapter, psta);
+	//_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	
+
+	return beacon_updated;
+
+}
+
+int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	int ret=0;	
+	struct sta_info *psta = NULL;	
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+	if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	DBG_871X(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	
+	/* for each sta in asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)	
+	{		
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
+		psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+	return ret;
+}
+
+int rtw_sta_flush(_adapter *padapter, bool enqueue)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	int ret = 0;
+	struct sta_info *psta = NULL;	
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
+	u8 flush_num = 0;
+	char flush_list[NUM_STA];
+	int i;
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	/* pick sta from sta asoc_queue */
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		rtw_list_delete(&psta->asoc_list);
+		pstapriv->asoc_list_cnt--;
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset))
+			flush_list[flush_num++] = stainfo_offset;
+		else
+			rtw_warn_on(1);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	/* call ap_free_sta() for each sta picked */
+	for (i = 0; i < flush_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, flush_list[i]);
+		ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, enqueue);
+	}
+
+	issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+	associated_clients_update(padapter, _TRUE, STA_INFO_UPDATE_ALL);
+
+	return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(_adapter *padapter, struct sta_info *psta)
+{	
+	int flags = psta->flags;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	
+				
+	//update wmm cap.
+	if(WLAN_STA_WME&flags)
+		psta->qos_option = 1;
+	else
+		psta->qos_option = 0;
+
+	if(pmlmepriv->qospriv.qos_option == 0)	
+		psta->qos_option = 0;
+
+		
+#ifdef CONFIG_80211N_HT		
+	//update 802.11n ht cap.
+	if(WLAN_STA_HT&flags)
+	{
+		psta->htpriv.ht_option = _TRUE;
+		psta->qos_option = 1;	
+
+		psta->htpriv.smps_cap = (psta->htpriv.ht_cap.cap_info & IEEE80211_HT_CAP_SM_PS)>>2;
+	}
+	else		
+	{
+		psta->htpriv.ht_option = _FALSE;
+	}
+		
+	if(pmlmepriv->htpriv.ht_option == _FALSE)	
+		psta->htpriv.ht_option = _FALSE;
+#endif
+
+#ifdef CONFIG_80211AC_VHT
+	//update 802.11AC vht cap.
+	if(WLAN_STA_VHT&flags)
+	{
+		psta->vhtpriv.vht_option = _TRUE;
+	}
+	else		
+	{
+		psta->vhtpriv.vht_option = _FALSE;
+	}
+
+	if(pmlmepriv->vhtpriv.vht_option == _FALSE)
+		psta->vhtpriv.vht_option = _FALSE;
+#endif	
+
+
+	update_sta_info_apmode(padapter, psta);
+		
+
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if(psta->state & _FW_LINKED)
+	{
+		pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+	
+		//add ratid
+		add_RATid(padapter, psta, 0);//DM_RATR_STA_INIT
+	}	
+}
+/* restore hw setting from sw data structures */
+void rtw_ap_restore_network(_adapter *padapter)
+{
+	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_priv * pstapriv = &padapter->stapriv;
+	struct sta_info *psta;
+	struct security_priv* psecuritypriv=&(padapter->securitypriv);
+	_irqL irqL;
+	_list	*phead, *plist;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+	rtw_setopmode_cmd(padapter, Ndis802_11APMode,_FALSE);
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	rtw_startbss_cmd(padapter, RTW_CMDF_DIRECTLY);
+
+	if((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+		(padapter->securitypriv.dot11PrivacyAlgrthm == _AES_))
+	{
+		/* restore group key, WEP keys is restored in ips_leave() */
+		rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0,_FALSE);
+	}
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+		int stainfo_offset;
+
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+		if (stainfo_offset_valid(stainfo_offset)) {
+			chk_alive_list[chk_alive_num++] = stainfo_offset;
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	for (i = 0; i < chk_alive_num; i++) {
+		psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+		if (psta == NULL) {
+			DBG_871X(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter));
+		} else if (psta->state &_FW_LINKED) {
+			rtw_sta_media_status_rpt(padapter, psta, 1);
+			Update_RA_Entry(padapter, psta);
+			//pairwise key
+			/* per sta pairwise key and settings */
+			if(	(padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+				(padapter->securitypriv.dot11PrivacyAlgrthm == _AES_))
+			{
+				rtw_setstakey_cmd(padapter, psta, UNICAST_KEY,_FALSE);
+			}			
+		}
+	}
+
+}
+
+void start_ap_mode(_adapter *padapter)
+{
+	int i;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	
+	pmlmepriv->update_bcn = _FALSE;
+	
+	/*init_mlme_ap_info(padapter);*/
+	
+	pmlmeext->bstart_bss = _FALSE;
+
+	pmlmepriv->num_sta_non_erp = 0;
+
+	pmlmepriv->num_sta_no_short_slot_time = 0;
+
+	pmlmepriv->num_sta_no_short_preamble = 0;
+
+	pmlmepriv->num_sta_ht_no_gf = 0;
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->num_sta_no_ht = 0;
+#endif //CONFIG_80211N_HT
+	pmlmeinfo->HT_info_enable = 0;
+	pmlmeinfo->HT_caps_enable = 0;
+	pmlmeinfo->HT_enable = 0;
+	
+	pmlmepriv->num_sta_ht_20mhz = 0;
+	pmlmepriv->num_sta_40mhz_intolerant = 0;
+	pmlmepriv->olbc = _FALSE;
+	pmlmepriv->olbc_ht = _FALSE;
+	
+#ifdef CONFIG_80211N_HT
+	pmlmepriv->ht_20mhz_width_req = _FALSE;
+	pmlmepriv->ht_intolerant_ch_reported = _FALSE;
+	pmlmepriv->ht_op_mode = 0;
+	pmlmepriv->sw_to_20mhz = 0;
+#endif
+
+	_rtw_memset(pmlmepriv->ext_capab_ie_data, 0, sizeof(pmlmepriv->ext_capab_ie_data));
+	pmlmepriv->ext_capab_ie_len = 0;
+
+	for (i = 0 ;  i < NUM_STA ; i++)
+		pstapriv->sta_aid[i] = NULL;
+
+/* to avoid memory leak issue, don't set to NULL directly
+	pmlmepriv->wps_beacon_ie = NULL;	
+	pmlmepriv->wps_probe_resp_ie = NULL;
+	pmlmepriv->wps_assoc_resp_ie = NULL;
+	
+	pmlmepriv->p2p_beacon_ie = NULL;
+	pmlmepriv->p2p_probe_resp_ie = NULL;
+*/
+	
+	//for ACL 
+	_rtw_init_listhead(&(pacl_list->acl_node_q.queue));
+	pacl_list->num = 0;
+	pacl_list->mode = 0;
+	for(i = 0; i < NUM_ACL; i++)
+	{		
+		_rtw_init_listhead(&pacl_list->aclnode[i].list);
+		pacl_list->aclnode[i].valid = _FALSE;
+	}
+
+}
+
+void stop_ap_mode(_adapter *padapter)
+{
+	_irqL irqL;
+	_list	*phead, *plist;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_info *psta=NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;	
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	_queue	*pacl_node_q =&pacl_list->acl_node_q;	
+
+	pmlmepriv->update_bcn = _FALSE;
+	pmlmeext->bstart_bss = _FALSE;
+	padapter->netif_up = _FALSE;
+	//_rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+	
+	//reset and init security priv , this can refine with rtw_reset_securitypriv
+	_rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv));
+	padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+	padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+	#ifdef CONFIG_DFS_MASTER
+	rtw_dfs_master_status_apply(padapter, MLME_AP_STOPPED);
+	#endif
+
+	/* free scan queue */
+	rtw_free_network_queue(padapter, _TRUE);
+
+	//for ACL
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);		
+	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+	{
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if(paclnode->valid == _TRUE)
+		{
+			paclnode->valid = _FALSE;
+
+			rtw_list_delete(&paclnode->list);
+				
+			pacl_list->num--;		
+		}		
+	}	
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+	
+	DBG_871X("%s, free acl_node_queue, num=%d\n", __func__, pacl_list->num);
+	
+	rtw_sta_flush(padapter, _TRUE);
+
+	//free_assoc_sta_resources	
+	rtw_free_all_stainfo(padapter);
+	
+	psta = rtw_get_bcmc_stainfo(padapter);
+	//_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);		
+	rtw_free_stainfo(padapter, psta);
+	//_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	
+	rtw_init_bcmc_stainfo(padapter);	
+
+	rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+#ifdef CONFIG_BT_COEXIST
+	rtw_btcoex_MediaStatusNotify(padapter, 0); //disconnect 
+#endif	
+
+}
+
+#endif //CONFIG_NATIVEAP_MLME
+
+void rtw_ap_update_bss_chbw(_adapter *adapter, WLAN_BSSID_EX *bss, u8 ch, u8 bw, u8 offset)
+{
+#define UPDATE_VHT_CAP 1
+#define UPDATE_HT_CAP 1
+
+#ifdef CONFIG_80211AC_VHT
+	{
+		struct vht_priv	*vhtpriv = &adapter->mlmepriv.vhtpriv;
+		u8 *vht_cap_ie, *vht_op_ie;
+		int vht_cap_ielen, vht_op_ielen;
+		u8	center_freq;
+
+		vht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTCapability, &vht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		vht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTOperation, &vht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		center_freq = rtw_get_center_ch(ch, bw, offset);
+
+		/* update vht cap ie */
+		if (vht_cap_ie && vht_cap_ielen) {
+			#if UPDATE_VHT_CAP
+			/* if ((bw == CHANNEL_WIDTH_160 || bw == CHANNEL_WIDTH_80_80) && pvhtpriv->sgi_160m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvht_cap_ie + 2, 1);
+			else */
+				SET_VHT_CAPABILITY_ELE_SHORT_GI160M(vht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_80 && vhtpriv->sgi_80m)
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 1);
+			else
+				SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 0);
+			#endif
+		}
+
+		/* update vht op ie */
+		if (vht_op_ie && vht_op_ielen) {
+			if (bw < CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else if (bw == CHANNEL_WIDTH_80) {
+				SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 1);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, center_freq);
+				SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0);
+			} else {
+				DBG_871X_LEVEL(_drv_err_, FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(adapter), bw);
+				rtw_warn_on(1);
+			}
+		}
+	}
+#endif /* CONFIG_80211AC_VHT */
+#ifdef CONFIG_80211N_HT
+	{
+		struct ht_priv	*htpriv = &adapter->mlmepriv.htpriv;
+		u8 *ht_cap_ie, *ht_op_ie;
+		int ht_cap_ielen, ht_op_ielen;
+
+		ht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTCapability, &ht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+		ht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTInfo, &ht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+
+		/* update ht cap ie */
+		if (ht_cap_ie && ht_cap_ielen) {
+			#if UPDATE_HT_CAP
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 0);
+
+			if (bw >= CHANNEL_WIDTH_40 && htpriv->sgi_40m)
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 0);
+
+			if (htpriv->sgi_20m)
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 1);
+			else
+				SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 0);
+			#endif
+		}
+
+		/* update ht op ie */
+		if (ht_op_ie && ht_op_ielen) {
+			SET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2, ch);
+			switch (offset) {
+			case HAL_PRIME_CHNL_OFFSET_LOWER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCA);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_UPPER:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCB);
+				break;
+			case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+			default:
+				SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCN);
+				break;
+			}
+
+			if (bw >= CHANNEL_WIDTH_40)
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 1);
+			else
+				SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 0);
+		}
+	}
+#endif /* CONFIG_80211N_HT */
+
+{
+	u8 *p;
+	int ie_len;
+	u8 old_ch = bss->Configuration.DSConfig;
+	bool change_band = _FALSE;
+
+	if ((ch <= 14 && old_ch >= 36) || (ch >= 36 && old_ch <= 14))
+		change_band = _TRUE;
+
+	/* update channel in IE */
+	p = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)));
+	if (p && ie_len > 0)
+		*(p + 2) = ch;
+
+	bss->Configuration.DSConfig = ch;
+
+	/* band is changed, update ERP, support rate, ext support rate IE */
+	if (change_band == _TRUE)
+		change_band_update_ie(adapter, bss, ch);
+}
+
+}
+
+bool rtw_ap_chbw_decision(_adapter *adapter, u8 req_ch, u8 req_bw, u8 req_offset
+	, u8 *ch, u8 *bw, u8 *offset)
+{
+	u8 dec_ch, dec_bw, dec_offset;
+	u8 u_ch = 0, u_offset, u_bw;
+	bool changed = _FALSE;
+	struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+	u8 sta_num;
+	u8 ld_sta_num;
+	u8 lg_sta_num;
+	u8 ap_num;
+	u8 ld_ap_num;
+	bool set_u_ch = _FALSE, set_dec_ch = _FALSE;
+
+	dec_ch = req_ch;
+	dec_bw = req_bw;
+	dec_offset = req_offset;
+	
+	rtw_dev_iface_status_no_self(adapter, &sta_num, &ld_sta_num, &lg_sta_num, &ap_num, &ld_ap_num);
+	DBG_871X(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num%u, ap_num:%u\n"
+		, FUNC_ADPT_ARG(adapter), ld_sta_num, lg_sta_num, ap_num);
+
+	if (ld_sta_num || ap_num) {
+		/* has linked STA or AP mode, follow */
+
+		rtw_warn_on(!rtw_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		DBG_871X(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		DBG_871X(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_regsty_adjust_chbw(&adapter->registrypriv, u_ch, &dec_bw, &dec_offset);
+
+		rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset
+			, &u_ch, &u_bw, &u_offset);
+
+		rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+			, dec_ch, dec_bw, dec_offset);
+
+		set_u_ch = _TRUE;
+	} else if (lg_sta_num) {
+		/* has linking STA */
+
+		rtw_warn_on(!rtw_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset));
+
+		DBG_871X(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+		DBG_871X(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+
+		rtw_regsty_adjust_chbw(&adapter->registrypriv, dec_ch, &dec_bw, &dec_offset);
+		
+		if (rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) {
+
+			rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset
+					, &u_ch, &u_bw, &u_offset);
+
+			rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+				, dec_ch, dec_bw, dec_offset);
+
+			set_u_ch = _TRUE;
+		} else {
+			/* set this for possible ch change when join down*/
+			set_fwstate(&adapter->mlmepriv, WIFI_OP_CH_SWITCHING);
+		}
+	} else {
+		/* single AP mode */
+
+		DBG_871X(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset);
+		rtw_regsty_adjust_chbw(&adapter->registrypriv, dec_ch, &dec_bw, &dec_offset);
+
+		#if defined(CONFIG_DFS_MASTER)
+		/* check NOL */
+		if (rtw_chset_is_ch_non_ocp(mlmeext->channel_set, dec_ch, dec_bw, dec_offset)) {
+			/* choose 5G DFS channel for debug */
+			if (adapter_to_rfctl(adapter)->dbg_dfs_master_choose_dfs_ch_first
+				&& rtw_choose_available_chbw(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G|RTW_CHF_NON_DFS) == _TRUE) {
+				DBG_871X(FUNC_ADPT_FMT" choose 5G DFS channel for debug\n", FUNC_ADPT_ARG(adapter));
+			} else 
+			/* choose from 5G no DFS */
+			if (rtw_choose_available_chbw(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G|RTW_CHF_DFS) == _FALSE) {
+				/* including 5G DFS, not long CAC */
+				if (rtw_choose_available_chbw(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G|RTW_CHF_LONG_CAC) == _FALSE) {
+					/* including 5G DFS, long CAC */
+					if (rtw_choose_available_chbw(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G) == _FALSE) {
+						/* including 2.4G channel */
+						if (rtw_choose_available_chbw(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_5G) == _FALSE) {
+							DBG_871X(FUNC_ADPT_FMT" no available ch\n", FUNC_ADPT_ARG(adapter));
+							rtw_warn_on(1);
+						}
+					}
+				}
+			}
+		}
+		#endif /* defined(CONFIG_DFS_MASTER) */
+
+		rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network)
+				, dec_ch, dec_bw, dec_offset);
+
+		set_dec_ch = _TRUE;
+	}
+
+	if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY)
+		#ifdef CONFIG_CONCURRENT_MODE
+		|| check_buddy_fwstate(adapter, _FW_UNDER_SURVEY)
+		#endif
+	) {
+		/* scanning, leave ch setting to scan state machine */
+		set_u_ch = set_dec_ch = _FALSE;
+	}
+
+	if (mlmeext->cur_channel != dec_ch
+		|| mlmeext->cur_bwmode != dec_bw
+		|| mlmeext->cur_ch_offset != dec_offset)
+		changed = _TRUE;
+
+	if (changed == _TRUE && rtw_linked_check(adapter) == _TRUE) {
+		#ifdef CONFIG_SPCT_CH_SWITCH
+		if (1)
+			rtw_ap_inform_ch_switch(adapter, dec_ch, dec_offset);
+		else
+		#endif
+			rtw_sta_flush(adapter, _FALSE);
+	}
+
+	mlmeext->cur_channel = dec_ch;
+	mlmeext->cur_bwmode = dec_bw;
+	mlmeext->cur_ch_offset = dec_offset;
+
+	if (u_ch != 0)
+		DBG_871X(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset);
+
+	DBG_871X(FUNC_ADPT_FMT" dec: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset);
+
+	if (set_u_ch == _TRUE) {
+		*ch = u_ch;
+		*bw = u_bw;
+		*offset = u_offset;
+	} else if (set_dec_ch == _TRUE) {
+		*ch = dec_ch;
+		*bw = dec_bw;
+		*offset = dec_offset;
+	}	
+
+	return changed;
+}
+
+#endif //CONFIG_AP_MODE
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_beamforming.c b/drivers/net/wireless/rtl8189es/core/rtw_beamforming.c
new file mode 100644
index 000000000000..db08296191da
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_beamforming.c
@@ -0,0 +1,1010 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_BEAMFORMING_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#ifdef CONFIG_BEAMFORMING
+
+struct beamforming_entry	*beamforming_get_entry_by_addr(struct mlme_priv *pmlmepriv, u8* ra,u8* idx)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	
+	for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
+	{
+		if(	pBeamInfo->beamforming_entry[i].bUsed && 
+			(_rtw_memcmp(ra,pBeamInfo->beamforming_entry[i].mac_addr, ETH_ALEN)))
+		{
+			*idx = i;
+			return &(pBeamInfo->beamforming_entry[i]);
+		}
+	}
+
+	return NULL;
+}
+
+BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(PVOID pmlmepriv ,u8 mac_id)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO((struct mlme_priv *)pmlmepriv);
+	BEAMFORMING_CAP		BeamformEntryCap = BEAMFORMING_CAP_NONE;
+	
+	for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
+	{
+		if(	pBeamInfo->beamforming_entry[i].bUsed && 
+			(mac_id == pBeamInfo->beamforming_entry[i].mac_id))
+		{
+			BeamformEntryCap =  pBeamInfo->beamforming_entry[i].beamforming_entry_cap;
+			i = BEAMFORMING_ENTRY_NUM;
+		}
+	}
+
+	return BeamformEntryCap;
+}
+
+struct beamforming_entry	*beamforming_get_free_entry(struct mlme_priv *pmlmepriv, u8* idx)
+{
+	u8	i = 0;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
+	{
+		if(pBeamInfo->beamforming_entry[i].bUsed == _FALSE)
+		{
+			*idx = i;
+			return &(pBeamInfo->beamforming_entry[i]);
+		}	
+	}
+	return NULL;
+}
+
+
+struct beamforming_entry	*beamforming_add_entry(PADAPTER adapter, u8* ra, u16 aid,
+	u16 mac_id, CHANNEL_WIDTH bw, BEAMFORMING_CAP beamfrom_cap, u8* idx)
+{
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_entry	*pEntry = beamforming_get_free_entry(pmlmepriv, idx);
+
+	if(pEntry != NULL)
+	{	
+		pEntry->bUsed = _TRUE;
+		pEntry->aid = aid;
+		pEntry->mac_id = mac_id;
+		pEntry->sound_bw = bw;
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+		{
+			u16	BSSID = ((*(adapter_mac_addr(adapter) + 5) & 0xf0) >> 4) ^ 
+				(*(adapter_mac_addr(adapter) + 5) & 0xf); /* BSSID[44:47] xor BSSID[40:43] */
+			pEntry->p_aid = (aid + BSSID * 32) & 0x1ff;		// (dec(A) + dec(B)*32) mod 512
+		}		
+		else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
+		{
+			pEntry->p_aid = 0;
+		}
+		else
+		{
+			pEntry->p_aid =  ra[5];						// BSSID[39:47]
+			pEntry->p_aid = (pEntry->p_aid << 1) | (ra[4] >> 7 );
+		}
+		_rtw_memcpy(pEntry->mac_addr, ra, ETH_ALEN);
+		pEntry->bSound = _FALSE;
+
+		//3 TODO SW/FW sound period
+		pEntry->sound_period = 200;
+		pEntry->beamforming_entry_cap = beamfrom_cap;
+		pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+
+		pEntry->LogSeq = 0xff;
+		pEntry->LogRetryCnt = 0;
+		pEntry->LogSuccessCnt = 0;
+		pEntry->LogStatusFailCnt = 0;
+
+		return pEntry;
+	}
+	else
+		return NULL;
+}
+
+BOOLEAN	beamforming_remove_entry(struct mlme_priv *pmlmepriv, u8* ra, u8* idx)
+{
+	struct beamforming_entry	*pEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
+
+	if(pEntry != NULL)
+	{	
+		pEntry->bUsed = _FALSE;
+		pEntry->beamforming_entry_cap = BEAMFORMING_CAP_NONE;
+		pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+		return _TRUE;
+	}
+	else
+		return _FALSE;
+}
+
+/* Used for BeamformingStart_V1  */
+void	beamforming_dym_ndpa_rate(PADAPTER adapter)
+{
+	u16	NDPARate = MGN_6M;
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(adapter);
+	
+	if(pHalData->MinUndecoratedPWDBForDM > 30) // link RSSI > 30%
+		NDPARate = MGN_24M;
+	else
+		NDPARate = MGN_6M;
+
+	//BW = CHANNEL_WIDTH_20;
+	NDPARate = NDPARate << 8;
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_RATE, (u8 *)&NDPARate);
+}
+
+void beamforming_dym_period(PADAPTER Adapter)
+{
+	u8	Idx;
+	BOOLEAN	bChangePeriod = _FALSE;
+	u16	SoundPeriod_SW, SoundPeriod_FW;
+	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(Adapter);
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(Adapter);
+	struct beamforming_entry	*pBeamformEntry;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(( &Adapter->mlmepriv));
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+	
+	//3 TODO  per-client throughput caculation.
+
+	if(pdvobjpriv->traffic_stat.cur_tx_tp + pdvobjpriv->traffic_stat.cur_rx_tp > 2)
+	{
+		SoundPeriod_SW = 32*20;
+		SoundPeriod_FW = 2;
+	}	
+	else
+	{
+		SoundPeriod_SW = 32*2000;
+		SoundPeriod_FW = 200;
+	}	
+
+	for(Idx = 0; Idx < BEAMFORMING_ENTRY_NUM; Idx++)
+	{
+		pBeamformEntry = pBeamInfo->beamforming_entry+Idx;
+		if(pBeamformEntry->bDefaultCSI)
+		{
+			SoundPeriod_SW = 32*2000;
+			SoundPeriod_FW = 200;
+		}
+
+		if(pBeamformEntry->beamforming_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT |BEAMFORMER_CAP_VHT_SU))
+		{
+			if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
+			{				
+				if(pBeamformEntry->sound_period != SoundPeriod_FW)
+				{
+					pBeamformEntry->sound_period = SoundPeriod_FW;
+					bChangePeriod = _TRUE;	// Only FW sounding need to send H2C packet to change sound period. 
+				}
+			}
+			else if(pBeamformEntry->sound_period != SoundPeriod_SW)
+			{
+				pBeamformEntry->sound_period = SoundPeriod_SW;
+			}
+		}
+	}
+
+	if(bChangePeriod)
+		rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx);
+}
+
+u32	beamforming_get_report_frame(PADAPTER	 Adapter, union recv_frame *precv_frame)
+{
+	u32	ret = _SUCCESS;
+	struct beamforming_entry	*pBeamformEntry = NULL;
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	u32	frame_len = precv_frame->u.hdr.len;
+	u8	*ta;
+	u8	idx, offset;
+	
+	//DBG_871X("beamforming_get_report_frame\n");
+
+	//Memory comparison to see if CSI report is the same with previous one
+	ta = GetAddr2Ptr(pframe);
+	pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
+	if(pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
+		offset = 31; //24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
+	else if(pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
+		offset = 34; //24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)
+	else
+		return ret;
+
+	//DBG_871X("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);
+
+	if(_rtw_memcmp(pBeamformEntry->PreCsiReport + offset, pframe+offset, frame_len-offset) == _FALSE)
+	{
+		pBeamformEntry->DefaultCsiCnt = 0;
+		//DBG_871X("%s CSI report is NOT the same with previos one\n", __FUNCTION__);
+	}
+	else
+	{
+		pBeamformEntry->DefaultCsiCnt ++;
+		//DBG_871X("%s CSI report is the SAME with previos one\n", __FUNCTION__);
+	}
+	_rtw_memcpy(&pBeamformEntry->PreCsiReport, pframe, frame_len);
+
+	pBeamformEntry->bDefaultCSI = _FALSE;
+
+	if(pBeamformEntry->DefaultCsiCnt > 20)
+		pBeamformEntry->bDefaultCSI = _TRUE;
+	else
+		pBeamformEntry->bDefaultCSI = _FALSE;
+	
+	return ret;
+}
+
+void	beamforming_get_ndpa_frame(PADAPTER	 Adapter, union recv_frame *precv_frame)
+{
+	u8	*ta;
+	u8	idx, Sequence;
+	u8	*pframe = precv_frame->u.hdr.rx_data;
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_entry	*pBeamformEntry = NULL;
+
+	//DBG_871X("beamforming_get_ndpa_frame\n");
+
+	if(IS_HARDWARE_TYPE_8812(Adapter) == _FALSE)
+		return;
+	else if(GetFrameSubType(pframe) != WIFI_NDPA)
+		return;
+
+	ta = GetAddr2Ptr(pframe);
+	// Remove signaling TA. 
+	ta[0] = ta[0] & 0xFE; 
+	
+	pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx);
+
+	if(pBeamformEntry == NULL)
+		return;
+	else if(!(pBeamformEntry->beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU))
+		return;
+	else if(pBeamformEntry->LogSuccessCnt > 1)
+		return;
+
+	Sequence = (pframe[16]) >> 2;
+
+	if(pBeamformEntry->LogSeq != Sequence)
+	{
+		/* Previous frame doesn't retry when meet new sequence number */
+		if(pBeamformEntry->LogSeq != 0xff && pBeamformEntry->LogRetryCnt == 0)
+			pBeamformEntry->LogSuccessCnt++;
+		
+		pBeamformEntry->LogSeq = Sequence;
+		pBeamformEntry->LogRetryCnt = 0;
+	}	
+	else
+	{
+		if(pBeamformEntry->LogRetryCnt == 3)
+			beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_CLK, NULL, 0, 1);
+
+		pBeamformEntry->LogRetryCnt++;
+	}
+
+	DBG_871X("%s LogSeq %d LogRetryCnt %d LogSuccessCnt %d\n", 
+			__FUNCTION__, pBeamformEntry->LogSeq, pBeamformEntry->LogRetryCnt, pBeamformEntry->LogSuccessCnt);
+}
+
+BOOLEAN	issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8	ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	aSifsTime = 0;
+
+	if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL)
+	{
+		return _FALSE;
+	}
+
+	//update attribute
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+
+	if (qidx == BCN_QUEUE_INX)
+		pattrib->qsel = QSLT_BEACON;
+	pattrib->rate = MGN_MCS8;
+	pattrib->bwmode = bw;
+	pattrib->order = 1;
+	pattrib->subtype = WIFI_ACTION_NOACK;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	SetOrderBit(pframe);
+	SetFrameSubType(pframe, WIFI_ACTION_NOACK);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	if( pmlmeext->cur_wireless_mode == WIRELESS_11B)
+		aSifsTime = 10;
+	else
+		aSifsTime = 16;
+
+	duration = 2*aSifsTime + 40;
+	
+	if(bw == CHANNEL_WIDTH_40)
+		duration+= 87;
+	else	
+		duration+= 180;
+
+	SetDuration(pframe, duration);
+
+	//HT control field
+	SET_HT_CTRL_CSI_STEERING(pframe+24, 3);
+	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1);
+
+	_rtw_memcpy(pframe+28, ActionHdr, 4);
+
+	pattrib->pktlen = 32;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+BOOLEAN	beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx)
+{
+	return issue_ht_ndpa_packet(Adapter, ra, bw, qidx);
+}
+
+BOOLEAN	issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
+{
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv		*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct rtw_ndpa_sta_info	sta_info;
+	u8	*pframe;
+	u16	*fctrl;
+	u16	duration = 0;
+	u8	sequence = 0, aSifsTime = 0;
+
+	if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL)
+	{
+		return _FALSE;
+	}
+
+	//update attribute
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(Adapter, pattrib);
+
+	if (qidx == BCN_QUEUE_INX)
+		pattrib->qsel = QSLT_BEACON;
+	pattrib->rate = MGN_VHT2SS_MCS0;
+	pattrib->bwmode = bw;
+	pattrib->subtype = WIFI_NDPA;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr*)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+
+	SetFrameSubType(pframe, WIFI_NDPA);
+
+	_rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN);
+	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN);
+
+	if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode))
+		aSifsTime = 16;
+	else
+		aSifsTime = 10;
+
+	duration = 2*aSifsTime + 44;
+	
+	if(bw == CHANNEL_WIDTH_80)
+		duration += 40;
+	else if(bw == CHANNEL_WIDTH_40)
+		duration+= 87;
+	else	
+		duration+= 180;
+
+	SetDuration(pframe, duration);
+
+	sequence = pBeamInfo->sounding_sequence<< 2;
+	if (pBeamInfo->sounding_sequence >= 0x3f)
+		pBeamInfo->sounding_sequence = 0;
+	else
+		pBeamInfo->sounding_sequence++;
+
+	_rtw_memcpy(pframe+16, &sequence,1);
+
+	if(((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+		aid = 0;		
+
+	sta_info.aid = aid;
+	sta_info.feedback_type = 0;
+	sta_info.nc_index= 0;
+	
+	_rtw_memcpy(pframe+17, (u8 *)&sta_info, 2);
+
+	pattrib->pktlen = 19;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(Adapter, pmgntframe);
+
+	return _TRUE;
+}
+
+BOOLEAN	beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx)
+{
+	return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx);
+}
+
+BOOLEAN	beamfomring_bSounding(struct beamforming_info *pBeamInfo)
+{
+	BOOLEAN		bSounding = _FALSE;
+
+	if(( beamforming_get_beamform_cap(pBeamInfo) & BEAMFORMER_CAP) == 0)
+		bSounding = _FALSE;
+	else 
+		bSounding = _TRUE;
+
+	return bSounding;
+}
+
+u8	beamforming_sounding_idx(struct beamforming_info *pBeamInfo)
+{
+	u8	idx = 0;
+	u8	i;
+
+	for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
+	{
+		if (pBeamInfo->beamforming_entry[i].bUsed &&
+			(_FALSE == pBeamInfo->beamforming_entry[i].bSound))
+		{
+			idx = i;
+			break;
+		}
+	}
+
+	return idx;
+}
+
+SOUNDING_MODE	beamforming_sounding_mode(struct beamforming_info *pBeamInfo, u8 idx)
+{
+	struct beamforming_entry	BeamEntry = pBeamInfo->beamforming_entry[idx];
+	SOUNDING_MODE	mode;
+
+	if(BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU)
+	{
+		mode = SOUNDING_FW_VHT_TIMER;
+	}
+	else if(BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
+	{
+		mode = SOUNDING_FW_HT_TIMER;
+	}
+	else
+	{
+		mode = SOUNDING_STOP_All_TIMER;
+	}
+
+	return mode;
+}
+
+u16	beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
+{
+	u16						sounding_time = 0xffff;
+	struct beamforming_entry	BeamEntry = pBeamInfo->beamforming_entry[idx];
+
+	sounding_time = BeamEntry.sound_period;
+
+	return sounding_time;
+}
+
+CHANNEL_WIDTH	beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx)
+{
+	CHANNEL_WIDTH				sounding_bw = CHANNEL_WIDTH_20;
+	struct beamforming_entry		BeamEntry = pBeamInfo->beamforming_entry[idx];
+
+	sounding_bw = BeamEntry.sound_bw;
+
+	return sounding_bw;
+}
+
+BOOLEAN	beamforming_select_beam_entry(struct beamforming_info *pBeamInfo)
+{
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+	pSoundInfo->sound_idx = beamforming_sounding_idx(pBeamInfo);
+
+	if(pSoundInfo->sound_idx < BEAMFORMING_ENTRY_NUM)
+		pSoundInfo->sound_mode = beamforming_sounding_mode(pBeamInfo, pSoundInfo->sound_idx);
+	else
+		pSoundInfo->sound_mode = SOUNDING_STOP_All_TIMER;
+	
+	if(SOUNDING_STOP_All_TIMER == pSoundInfo->sound_mode)
+	{
+		return _FALSE;
+	}
+	else
+	{
+		pSoundInfo->sound_bw = beamforming_sounding_bw(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx );
+		pSoundInfo->sound_period = beamforming_sounding_time(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx );
+		return _TRUE;
+	}
+}
+
+BOOLEAN	beamforming_start_fw(PADAPTER adapter, u8 idx)
+{
+	u8						*RA = NULL;
+	struct beamforming_entry	*pEntry;
+	BOOLEAN					ret = _TRUE;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	pEntry = &(pBeamInfo->beamforming_entry[idx]);
+	if(pEntry->bUsed == _FALSE)
+	{
+		DBG_871X("Skip Beamforming, no entry for Idx =%d\n", idx);
+		return _FALSE;
+	}
+
+	pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING;
+	pEntry->bSound = _TRUE;
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
+
+	return _TRUE;
+}
+
+void	beamforming_end_fw(PADAPTER adapter)
+{
+	u8	idx = 0;
+
+	rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx);
+
+	DBG_871X("%s\n", __FUNCTION__);
+}
+
+BOOLEAN	beamforming_start_period(PADAPTER adapter)
+{
+	BOOLEAN	ret = _TRUE;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+	beamforming_dym_ndpa_rate(adapter);
+
+	beamforming_select_beam_entry(pBeamInfo);
+
+	if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
+	{
+		ret = beamforming_start_fw(adapter, pSoundInfo->sound_idx);
+	}
+	else
+	{
+		ret = _FALSE;
+	}
+
+	DBG_871X("%s Idx %d Mode %d BW %d Period %d\n", __FUNCTION__, 
+			pSoundInfo->sound_idx, pSoundInfo->sound_mode, pSoundInfo->sound_bw, pSoundInfo->sound_period);
+
+	return ret;
+}
+
+void	beamforming_end_period(PADAPTER adapter)
+{
+	u8						idx = 0;
+	struct beamforming_entry	*pBeamformEntry;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct sounding_info		*pSoundInfo = &(pBeamInfo->sounding_info);
+
+
+	if(pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER)
+	{		
+		beamforming_end_fw(adapter);
+	}
+}
+
+void	beamforming_notify(PADAPTER adapter)
+{
+	BOOLEAN		bSounding = _FALSE;
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(&(adapter->mlmepriv));
+
+	bSounding = beamfomring_bSounding(pBeamInfo);
+	
+	if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_IDLE)
+	{
+		if(bSounding)
+		{			
+			if(beamforming_start_period(adapter) == _TRUE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
+		}
+	}
+	else if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_START)
+	{
+		if(bSounding)
+		{
+			if(beamforming_start_period(adapter) == _FALSE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
+		}
+		else
+		{
+			beamforming_end_period(adapter);
+			pBeamInfo->beamforming_state = BEAMFORMING_STATE_END;
+		}
+	}
+	else if(pBeamInfo->beamforming_state == BEAMFORMING_STATE_END)
+	{
+		if(bSounding)
+		{
+			if(beamforming_start_period(adapter) == _TRUE)
+				pBeamInfo->beamforming_state = BEAMFORMING_STATE_START;
+		}
+	}
+	else
+	{
+		DBG_871X("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->beamforming_state);
+	}
+
+	DBG_871X("%s BeamformState %d bSounding %d\n", __FUNCTION__, pBeamInfo->beamforming_state, bSounding);
+}
+
+BOOLEAN	beamforming_init_entry(PADAPTER	adapter, struct sta_info *psta, u8* idx)
+{
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct ht_priv		*phtpriv = &(pmlmepriv->htpriv);
+#ifdef CONFIG_80211AC_VHT	
+	struct vht_priv		*pvhtpriv = &(pmlmepriv->vhtpriv);
+#endif
+	struct mlme_ext_priv	*pmlmeext = &(adapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct beamforming_entry	*pBeamformEntry = NULL;
+	u8	*ra; 
+	u16	aid, mac_id;
+	u8	wireless_mode;
+	CHANNEL_WIDTH	bw = CHANNEL_WIDTH_20;
+	BEAMFORMING_CAP	beamform_cap = BEAMFORMING_CAP_NONE;
+
+	// The current setting does not support Beaforming
+	if (0 == phtpriv->beamform_cap 
+#ifdef CONFIG_80211AC_VHT
+		&& 0 == pvhtpriv->beamform_cap
+#endif
+		) {
+		DBG_871X("The configuration disabled Beamforming! Skip...\n");
+		return _FALSE;
+	}
+
+	aid = psta->aid;
+	ra = psta->hwaddr;
+	mac_id = psta->mac_id;
+	wireless_mode = psta->wireless_mode;
+	bw = psta->bw_mode;
+
+	if (IsSupportedHT(wireless_mode) || IsSupportedVHT(wireless_mode)) {
+		//3 // HT
+		u8	cur_beamform;
+
+		cur_beamform = psta->htpriv.beamform_cap;
+
+		// We are Beamformee because the STA is Beamformer
+		if(TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE))
+			beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMEE_CAP_HT_EXPLICIT);
+
+		// We are Beamformer because the STA is Beamformee
+		if(TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE))
+			beamform_cap =(BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT);
+#ifdef CONFIG_80211AC_VHT
+		if (IsSupportedVHT(wireless_mode)) {
+			//3 // VHT
+			cur_beamform = psta->vhtpriv.beamform_cap;
+
+			// We are Beamformee because the STA is Beamformer
+			if(TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMER_ENABLE))
+				beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMEE_CAP_VHT_SU);
+			// We are Beamformer because the STA is Beamformee
+			if(TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMEE_ENABLE))
+				beamform_cap =(BEAMFORMING_CAP)(beamform_cap |BEAMFORMER_CAP_VHT_SU);
+		}
+#endif //CONFIG_80211AC_VHT
+
+		if(beamform_cap == BEAMFORMING_CAP_NONE)
+			return _FALSE;
+		
+		DBG_871X("Beamforming Config Capability = 0x%02X\n", beamform_cap);
+
+		pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx);
+		if (pBeamformEntry == NULL) {
+			pBeamformEntry = beamforming_add_entry(adapter, ra, aid, mac_id, bw, beamform_cap, idx);
+			if(pBeamformEntry == NULL)
+				return _FALSE;
+			else
+				pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
+		} else {
+			// Entry has been created. If entry is initialing or progressing then errors occur.
+			if (pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && 
+				pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) {
+				DBG_871X("Error State of Beamforming");
+				return _FALSE;
+			} else {
+				pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING;
+			}
+		}
+
+		pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED;
+
+		DBG_871X("%s Idx %d\n", __FUNCTION__, *idx);
+	} else {
+		return _FALSE;
+	}
+
+	return _SUCCESS;
+}
+
+void	beamforming_deinit_entry(PADAPTER adapter, u8* ra)
+{
+	u8	idx = 0;
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	
+	if(beamforming_remove_entry(pmlmepriv, ra, &idx) == _TRUE)
+	{
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
+	}
+
+	DBG_871X("%s Idx %d\n", __FUNCTION__, idx);
+}
+
+void	beamforming_reset(PADAPTER adapter)
+{
+	u8	idx = 0;
+	struct mlme_priv			*pmlmepriv = &(adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+
+	for(idx = 0; idx < BEAMFORMING_ENTRY_NUM; idx++)
+	{
+		if(pBeamInfo->beamforming_entry[idx].bUsed == _TRUE)
+		{
+			pBeamInfo->beamforming_entry[idx].bUsed = _FALSE;
+			pBeamInfo->beamforming_entry[idx].beamforming_entry_cap = BEAMFORMING_CAP_NONE;
+			pBeamInfo->beamforming_entry[idx].beamforming_entry_state= BEAMFORMING_ENTRY_STATE_UNINITIALIZE;
+			rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx);
+		}
+	}
+
+	DBG_871X("%s\n", __FUNCTION__);
+}
+
+void beamforming_sounding_fail(PADAPTER Adapter)
+{
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct beamforming_entry	*pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
+
+	pEntry->bSound = _FALSE;
+	rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx);
+	beamforming_deinit_entry(Adapter, pEntry->mac_addr);
+}
+
+void	beamforming_check_sounding_success(PADAPTER Adapter,BOOLEAN status)
+{
+	struct mlme_priv			*pmlmepriv = &(Adapter->mlmepriv);
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv);
+	struct beamforming_entry	*pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]);
+
+	if(status == 1)
+	{
+		pEntry->LogStatusFailCnt = 0;
+	}	
+	else
+	{
+		pEntry->LogStatusFailCnt++;
+		DBG_871X("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt);
+	}
+	if(pEntry->LogStatusFailCnt > 20)
+	{
+		DBG_871X("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__);
+		//pEntry->bSound = _FALSE;
+		//rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx);
+		//beamforming_deinit_entry(Adapter, pEntry->mac_addr);
+		beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_FAIL, NULL, 0, 1);
+	}
+}
+
+void	beamforming_enter(PADAPTER adapter, PVOID psta)
+{
+	u8	idx = 0xff;
+
+	if(beamforming_init_entry(adapter, (struct sta_info *)psta, &idx))
+		rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8 *)&idx);
+
+	//DBG_871X("%s Idx %d\n", __FUNCTION__, idx);
+}
+
+void	beamforming_leave(PADAPTER adapter,u8* ra)
+{
+	if(ra == NULL)
+		beamforming_reset(adapter);
+	else
+		beamforming_deinit_entry(adapter, ra);
+
+	beamforming_notify(adapter);
+}
+
+BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info	*pBeamInfo)
+{
+	u8	i;
+	BOOLEAN 				bSelfBeamformer = _FALSE;
+	BOOLEAN 				bSelfBeamformee = _FALSE;
+	struct beamforming_entry	beamforming_entry;
+	BEAMFORMING_CAP 		beamform_cap = BEAMFORMING_CAP_NONE;
+
+	for(i = 0; i < BEAMFORMING_ENTRY_NUM; i++)
+	{
+		beamforming_entry = pBeamInfo->beamforming_entry[i];
+
+		if(beamforming_entry.bUsed)
+		{
+			if( (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU) ||
+				(beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_HT_EXPLICIT))
+				bSelfBeamformee = _TRUE;
+			if( (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) ||
+				(beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT))
+				bSelfBeamformer = _TRUE;
+		}
+
+		if(bSelfBeamformer && bSelfBeamformee)
+			i = BEAMFORMING_ENTRY_NUM;
+	}
+
+	if(bSelfBeamformer)
+		beamform_cap |= BEAMFORMER_CAP;
+	if(bSelfBeamformee)
+		beamform_cap |= BEAMFORMEE_CAP;
+
+	return beamform_cap;
+}
+
+void	beamforming_watchdog(PADAPTER Adapter)
+{
+	struct beamforming_info	*pBeamInfo = GET_BEAMFORM_INFO(( &(Adapter->mlmepriv)));
+
+	if(pBeamInfo->beamforming_state != BEAMFORMING_STATE_START)
+		return;
+
+	beamforming_dym_period(Adapter);
+	beamforming_dym_ndpa_rate(Adapter);
+}
+
+void	beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf)
+{
+	
+_func_enter_;
+
+	switch(type)
+	{
+		case BEAMFORMING_CTRL_ENTER:
+			beamforming_enter(padapter, (PVOID)pbuf);
+			break;
+
+		case BEAMFORMING_CTRL_LEAVE:
+			beamforming_leave(padapter, pbuf);
+			break;
+
+		case BEAMFORMING_CTRL_SOUNDING_FAIL:
+			beamforming_sounding_fail(padapter);
+			break;
+
+		case BEAMFORMING_CTRL_SOUNDING_CLK:
+			rtw_hal_set_hwreg(padapter, HW_VAR_SOUNDING_CLK, NULL);
+			break;
+	
+		default:
+			break;
+	}
+
+_func_exit_;
+}
+
+u8	beamforming_wk_cmd(_adapter*padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	
+_func_enter_;
+
+	if(enqueue)
+	{
+		u8	*wk_buf;
+	
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+		if(ph2c==NULL){
+			res= _FAIL;
+			goto exit;
+		}
+		
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+		if(pdrvextra_cmd_parm==NULL){
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res= _FAIL;
+			goto exit;
+		}
+
+		if (pbuf != NULL) {
+			wk_buf = rtw_zmalloc(size);
+			if(wk_buf==NULL){
+				rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj));
+				rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+				res= _FAIL;
+				goto exit;
+			}
+
+			_rtw_memcpy(wk_buf, pbuf, size);
+		} else {
+			wk_buf = NULL;
+			size = 0;
+		}
+
+		pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID;
+		pdrvextra_cmd_parm->type = type;
+		pdrvextra_cmd_parm->size = size;
+		pdrvextra_cmd_parm->pbuf = wk_buf;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+	else
+	{
+		beamforming_wk_hdl(padapter, type, pbuf);
+	}
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+}
+
+#endif //CONFIG_BEAMFORMING
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_br_ext.c b/drivers/net/wireless/rtl8189es/core/rtw_br_ext.c
new file mode 100644
index 000000000000..f90f790a31d8
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_br_ext.c
@@ -0,0 +1,1695 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_BR_EXT_C_
+
+#ifdef __KERNEL__
+#include <linux/if_arp.h>
+#include <net/ip.h>
+#include <net/ipx.h>
+#include <linux/atalk.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+#endif
+
+#if 1	// rtw_wifi_driver
+#include <drv_types.h>
+#else	// rtw_wifi_driver
+#include "./8192cd_cfg.h"
+
+#ifndef __KERNEL__
+#include "./sys-support.h"
+#endif
+
+#include "./8192cd.h"
+#include "./8192cd_headers.h"
+#include "./8192cd_br_ext.h"
+#include "./8192cd_debug.h"
+#endif	// rtw_wifi_driver
+
+#ifdef CL_IPV6_PASS
+#ifdef __KERNEL__
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ndisc.h>
+#include <net/checksum.h>
+#endif
+#endif
+
+#ifdef CONFIG_BR_EXT
+
+//#define BR_EXT_DEBUG
+
+#define NAT25_IPV4		01
+#define NAT25_IPV6		02
+#define NAT25_IPX		03
+#define NAT25_APPLE		04
+#define NAT25_PPPOE		05
+
+#define RTL_RELAY_TAG_LEN (ETH_ALEN)
+#define TAG_HDR_LEN		4
+
+#define MAGIC_CODE		0x8186
+#define MAGIC_CODE_LEN	2
+#define WAIT_TIME_PPPOE	5	// waiting time for pppoe server in sec
+
+/*-----------------------------------------------------------------
+  How database records network address:
+           0    1    2    3    4    5    6    7    8    9   10
+        |----|----|----|----|----|----|----|----|----|----|----|
+  IPv4  |type|                             |      IP addr      |
+  IPX   |type|      Net addr     |          Node addr          |
+  IPX   |type|      Net addr     |Sckt addr|
+  Apple |type| Network |node|
+  PPPoE |type|   SID   |           AC MAC            |
+-----------------------------------------------------------------*/
+
+
+//Find a tag in pppoe frame and return the pointer
+static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
+{
+	unsigned char *cur_ptr, *start_ptr;
+	unsigned short tagLen, tagType;
+
+	start_ptr = cur_ptr = (unsigned char *)ph->tag;
+	while((cur_ptr - start_ptr) < ntohs(ph->length)) {
+		// prevent un-alignment access
+		tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
+		tagLen  = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
+		if(tagType == type)
+			return cur_ptr;
+		cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
+	}
+	return 0;
+}
+
+
+static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+	struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+	int data_len;
+
+	data_len = tag->tag_len + TAG_HDR_LEN;
+	if (skb_tailroom(skb) < data_len) {
+		_DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+		return -1;
+	}
+
+	skb_put(skb, data_len);
+	// have a room for new tag
+	memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+	ph->length = htons(ntohs(ph->length) + data_len);
+	memcpy((unsigned char *)ph->tag, tag, data_len);
+	return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+	int tail_len;
+	unsigned long end, tail;
+
+	if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
+		return -1;
+
+	tail = (unsigned long)skb_tail_pointer(skb);
+	end = (unsigned long)src+len;
+	if (tail < end)
+		return -1;
+
+	tail_len = (int)(tail-end);
+	if (tail_len > 0)
+		memmove(src, src+len, tail_len);
+
+	skb_trim(skb, skb->len-len);
+	return 0;
+}
+
+static __inline__ unsigned long __nat25_timeout(_adapter *priv)
+{
+	unsigned long timeout;
+
+	timeout = jiffies - NAT25_AGEING_TIME*HZ;
+
+	return timeout;
+}
+
+
+static __inline__ int  __nat25_has_expired(_adapter *priv,
+				struct nat25_network_db_entry *fdb)
+{
+	if(time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+		return 1;
+
+	return 0;
+}
+
+
+static __inline__ void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+				unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV4;
+	memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
+}
+
+
+static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
+				unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr+5, ipxNodeAddr, 6);
+}
+
+
+static __inline__ void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
+				unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2);
+}
+
+
+static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
+				unsigned short *network, unsigned char *node)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_APPLE;
+	memcpy(networkAddr+1, (unsigned char *)network, 2);
+	networkAddr[3] = *node;
+}
+
+
+static __inline__ void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+				unsigned char *ac_mac, unsigned short *sid)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_PPPOE;
+	memcpy(networkAddr+1, (unsigned char *)sid, 2);
+	memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
+}
+
+
+#ifdef CL_IPV6_PASS
+static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+				unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV6;
+	memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
+}
+
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+	while (len > 0) {
+		if (*data == tag && *(data+1) == len8b && len >= len8b*8)
+			return data+2;	
+		
+		len -= (*(data+1))*8;		
+		data += (*(data+1))*8;		
+	}
+	return NULL;
+}
+
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+	struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+	unsigned char *mac;
+	
+	if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { 
+		if (len >= 8) {
+			mac = scan_tlv(&data[8], len-8, 1, 1);
+			if (mac) {
+				DBG_871X("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],					
+					replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]);
+				memcpy(mac, replace_mac, 6);	
+				return 1;				
+			}
+		}
+	}
+	else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+		if (len >= 16) {
+			mac = scan_tlv(&data[16], len-16, 1, 1);
+			if (mac) {
+				DBG_871X("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],					
+					replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]);
+				memcpy(mac, replace_mac, 6);			
+				return 1;				
+			}
+		}		
+	}
+	else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len-24, 1, 1);
+			if (mac) {		
+				DBG_871X("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],					
+					replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]);
+				memcpy(mac, replace_mac, 6);	
+				return 1;								
+			}
+		}		
+	}
+	else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len-24, 2, 1);
+			if (mac) {
+				DBG_871X("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],					
+					replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]);
+				memcpy(mac, replace_mac, 6);		
+				return 1;				
+			}
+		}		
+	}
+	else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+		if (len >= 40) {
+			mac = scan_tlv(&data[40], len-40, 2, 1);
+			if (mac) {				
+				DBG_871X("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],					
+					replace_mac[0],replace_mac[1],replace_mac[2],replace_mac[3],replace_mac[4],replace_mac[5]);
+				memcpy(mac, replace_mac, 6);	
+				return 1;				
+			}
+		}		
+	}	
+	return 0;
+}
+
+
+static void convert_ipv6_mac_to_mc(struct sk_buff *skb)
+{	
+	struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+	unsigned char *dst_mac = skb->data;
+
+	//dst_mac[0] = 0xff;
+	//dst_mac[1] = 0xff;
+	/*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/
+	dst_mac[0] = 0x33;
+	dst_mac[1] = 0x33;
+	memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4);
+	#if defined(__LINUX_2_6__) 
+	/*modified by qinjunjie,warning:should not remove next line*/
+	skb->pkt_type = PACKET_MULTICAST;
+	#endif
+}
+#endif /* CL_IPV6_PASS */
+
+
+static __inline__ int __nat25_network_hash(unsigned char *networkAddr)
+{
+	if(networkAddr[0] == NAT25_IPV4)
+	{
+		unsigned long x;
+
+		x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+	else if(networkAddr[0] == NAT25_IPX)
+	{
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+			networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+	else if(networkAddr[0] == NAT25_APPLE)
+	{
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+	else if(networkAddr[0] == NAT25_PPPOE)
+	{
+		unsigned long x;
+
+		x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+#ifdef CL_IPV6_PASS
+	else if(networkAddr[0] == NAT25_IPV6)
+	{
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+			networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+			networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+			networkAddr[16];
+	
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+#endif	
+	else
+	{
+		unsigned long x = 0;
+		int i;
+
+		for (i=0; i<MAX_NETWORK_ADDR_LEN; i++)
+			x ^= networkAddr[i];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+}
+
+
+static __inline__ void __network_hash_link(_adapter *priv,
+				struct nat25_network_db_entry *ent, int hash)
+{
+	// Caller must _enter_critical_bh already!
+	//_irqL irqL;
+	//_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	ent->next_hash = priv->nethash[hash];
+	if(ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = &ent->next_hash;
+	priv->nethash[hash] = ent;
+	ent->pprev_hash = &priv->nethash[hash];
+
+	//_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+	// Caller must _enter_critical_bh already!
+	//_irqL irqL;
+	//_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	*(ent->pprev_hash) = ent->next_hash;
+	if(ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = ent->pprev_hash;
+	ent->next_hash = NULL;
+	ent->pprev_hash = NULL;
+
+	//_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+static int __nat25_db_network_lookup_and_replace(_adapter *priv,
+				struct sk_buff *skb, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	db = priv->nethash[__nat25_network_hash(networkAddr)];
+	while (db != NULL)
+	{
+		if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN))
+		{
+			if(!__nat25_has_expired(priv, db))
+			{
+				// replace the destination mac address
+				memcpy(skb->data, db->macAddr, ETH_ALEN);
+				atomic_inc(&db->use_count);
+
+#ifdef CL_IPV6_PASS
+				DBG_871X("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"	
+							"%02x%02x%02x%02x%02x%02x\n",				
+					db->macAddr[0],
+					db->macAddr[1],
+					db->macAddr[2],
+					db->macAddr[3],
+					db->macAddr[4],
+					db->macAddr[5],
+					db->networkAddr[0],
+					db->networkAddr[1],
+					db->networkAddr[2],
+					db->networkAddr[3],
+					db->networkAddr[4],
+					db->networkAddr[5],
+					db->networkAddr[6],
+					db->networkAddr[7],
+					db->networkAddr[8],
+					db->networkAddr[9],
+					db->networkAddr[10],
+					db->networkAddr[11],
+					db->networkAddr[12],
+					db->networkAddr[13],
+					db->networkAddr[14],
+					db->networkAddr[15],
+					db->networkAddr[16]);
+#else				
+				DBG_871X("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+					db->macAddr[0],
+					db->macAddr[1],
+					db->macAddr[2],
+					db->macAddr[3],
+					db->macAddr[4],
+					db->macAddr[5],
+					db->networkAddr[0],
+					db->networkAddr[1],
+					db->networkAddr[2],
+					db->networkAddr[3],
+					db->networkAddr[4],
+					db->networkAddr[5],
+					db->networkAddr[6],
+					db->networkAddr[7],
+					db->networkAddr[8],
+					db->networkAddr[9],
+					db->networkAddr[10]);
+#endif
+			}
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return 1;
+		}
+
+		db = db->next_hash;
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+	return 0;
+}
+
+
+static void __nat25_db_network_insert(_adapter *priv,
+				unsigned char *macAddr, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	int hash;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL)
+	{
+		if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN))
+		{
+			memcpy(db->macAddr, macAddr, ETH_ALEN);
+			db->ageing_timer = jiffies;
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return;
+		}
+
+		db = db->next_hash;
+	}
+
+	db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
+	if(db == NULL) {
+		_exit_critical_bh(&priv->br_ext_lock, &irqL);
+		return;
+	}
+
+	memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
+	memcpy(db->macAddr, macAddr, ETH_ALEN);
+	atomic_set(&db->use_count, 1);
+	db->ageing_timer = jiffies;
+
+	__network_hash_link(priv, db, hash);
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+static void __nat25_db_print(_adapter *priv)
+{
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+#ifdef BR_EXT_DEBUG
+	static int counter = 0;
+	int i, j;
+	struct nat25_network_db_entry *db;
+
+	counter++;
+	if((counter % 16) != 0)
+		return;
+
+	for(i=0, j=0; i<NAT25_HASH_SIZE; i++)
+	{
+		db = priv->nethash[i];
+
+		while (db != NULL)
+		{
+#ifdef CL_IPV6_PASS
+			panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+					"%02x%02x%02x%02x%02x%02x\n",
+				j,
+				i,
+				atomic_read(&db->use_count),
+				db->macAddr[0],
+				db->macAddr[1],
+				db->macAddr[2],
+				db->macAddr[3],
+				db->macAddr[4],
+				db->macAddr[5],
+				db->networkAddr[0],
+				db->networkAddr[1],
+				db->networkAddr[2],
+				db->networkAddr[3],
+				db->networkAddr[4],
+				db->networkAddr[5],
+				db->networkAddr[6],
+				db->networkAddr[7],
+				db->networkAddr[8],
+				db->networkAddr[9],
+				db->networkAddr[10],
+				db->networkAddr[11],
+				db->networkAddr[12],
+				db->networkAddr[13],
+				db->networkAddr[14],
+				db->networkAddr[15],
+				db->networkAddr[16]);
+#else
+			panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+				j,
+				i,
+				atomic_read(&db->use_count),
+				db->macAddr[0],
+				db->macAddr[1],
+				db->macAddr[2],
+				db->macAddr[3],
+				db->macAddr[4],
+				db->macAddr[5],
+				db->networkAddr[0],
+				db->networkAddr[1],
+				db->networkAddr[2],
+				db->networkAddr[3],
+				db->networkAddr[4],
+				db->networkAddr[5],
+				db->networkAddr[6],
+				db->networkAddr[7],
+				db->networkAddr[8],
+				db->networkAddr[9],
+				db->networkAddr[10]);
+#endif
+			j++;
+
+			db = db->next_hash;
+		}
+	}
+#endif
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+
+
+/*
+ *	NAT2.5 interface
+ */
+
+void nat25_db_cleanup(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+	
+	for(i=0; i<NAT25_HASH_SIZE; i++)
+	{
+		struct nat25_network_db_entry *f;
+		f = priv->nethash[i];
+		while (f != NULL) {
+			struct nat25_network_db_entry *g;
+
+			g = f->next_hash;
+			if(priv->scdb_entry == f)
+			{
+				memset(priv->scdb_mac, 0, ETH_ALEN);
+				memset(priv->scdb_ip, 0, 4);
+				priv->scdb_entry = NULL;
+			}
+			__network_hash_unlink(f);
+			rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+
+			f = g;
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+void nat25_db_expire(_adapter *priv)
+{
+	int i;
+	_irqL irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+	
+	//if(!priv->ethBrExtInfo.nat25_disable)
+	{
+		for (i=0; i<NAT25_HASH_SIZE; i++)
+		{
+			struct nat25_network_db_entry *f;
+			f = priv->nethash[i];
+
+			while (f != NULL)
+			{
+				struct nat25_network_db_entry *g;
+				g = f->next_hash;
+
+				if(__nat25_has_expired(priv, f))
+				{
+					if(atomic_dec_and_test(&f->use_count))
+					{
+#ifdef BR_EXT_DEBUG
+#ifdef CL_IPV6_PASS
+						panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+								"%02x%02x%02x%02x%02x%02x\n",
+							i,
+							f->macAddr[0],
+							f->macAddr[1],
+							f->macAddr[2],
+							f->macAddr[3],
+							f->macAddr[4],
+							f->macAddr[5],
+							f->networkAddr[0],
+							f->networkAddr[1],
+							f->networkAddr[2],
+							f->networkAddr[3],
+							f->networkAddr[4],
+							f->networkAddr[5],
+							f->networkAddr[6],
+							f->networkAddr[7],
+							f->networkAddr[8],
+							f->networkAddr[9],
+							f->networkAddr[10],
+							f->networkAddr[11],
+							f->networkAddr[12],
+							f->networkAddr[13],
+							f->networkAddr[14],
+							f->networkAddr[15],
+							f->networkAddr[16]);
+#else
+
+						panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+							i,
+							f->macAddr[0],
+							f->macAddr[1],
+							f->macAddr[2],
+							f->macAddr[3],
+							f->macAddr[4],
+							f->macAddr[5],
+							f->networkAddr[0],
+							f->networkAddr[1],
+							f->networkAddr[2],
+							f->networkAddr[3],
+							f->networkAddr[4],
+							f->networkAddr[5],
+							f->networkAddr[6],
+							f->networkAddr[7],
+							f->networkAddr[8],
+							f->networkAddr[9],
+							f->networkAddr[10]);
+#endif
+#endif
+						if(priv->scdb_entry == f)
+						{
+							memset(priv->scdb_mac, 0, ETH_ALEN);
+							memset(priv->scdb_ip, 0, 4);
+							priv->scdb_entry = NULL;
+						}
+						__network_hash_unlink(f);
+						rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry));
+					}
+				}
+
+				f = g;
+			}
+		}
+	}
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+
+#ifdef SUPPORT_TX_MCAST2UNI
+static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int *dst_ip)
+{
+	struct stat_info	*pstat;
+	struct list_head	*phead, *plist;
+	int i;
+
+	phead = &priv->asoc_list;
+	plist = phead->next;
+
+	while (plist != phead) {
+		pstat = list_entry(plist, struct stat_info, asoc_list);
+		plist = plist->next;
+
+		if (pstat->ipmc_num == 0)
+			continue;
+
+		for (i=0; i<MAX_IP_MC_ENTRY; i++) {
+			if (pstat->ipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip)+1, 3)) {
+				memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+#endif
+
+int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method)
+{
+	unsigned short protocol;
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+
+	if(skb == NULL)
+		return -1;
+
+	if((method <= NAT25_MIN) || (method >= NAT25_MAX))
+		return -1;
+
+	protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
+
+	/*---------------------------------------------------*/
+	/*                 Handle IP frame                   */
+	/*---------------------------------------------------*/
+	if(protocol == __constant_htons(ETH_P_IP))
+	{
+		struct iphdr* iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+		if(((unsigned char*)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len))
+		{
+			DEBUG_WARN("NAT25: malformed IP packet !\n");
+			return -1;
+		}
+
+		switch(method)
+		{
+			case NAT25_CHECK:
+				return -1;
+
+			case NAT25_INSERT:
+				{
+					//some muticast with source IP is all zero, maybe other case is illegal
+					//in class A, B, C, host address is all zero or all one is illegal
+					if (iph->saddr == 0)
+						return 0;
+					DBG_871X("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+					__nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr);
+					//record source IP address and , source mac address into db
+					__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+					__nat25_db_print(priv);
+				}
+				return 0;
+
+			case NAT25_LOOKUP:
+				{
+					DBG_871X("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr);
+#ifdef SUPPORT_TX_MCAST2UNI
+					if (priv->pshare->rf_ft_var.mc2u_disable ||
+							((((OPMODE & (WIFI_STATION_STATE|WIFI_ASOC_STATE))
+							== (WIFI_STATION_STATE|WIFI_ASOC_STATE)) &&
+							!checkIPMcAndReplace(priv, skb, &iph->daddr)) ||
+							(OPMODE & WIFI_ADHOC_STATE)))
+#endif
+					{
+						__nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr);
+
+						if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+							if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
+								// L2 is unicast but L3 is broadcast, make L2 bacome broadcast
+								DBG_871X("NAT25: Set DA as boardcast\n");
+								memset(skb->data, 0xff, ETH_ALEN);
+							}
+							else {
+								// forward unknow IP packet to upper TCP/IP
+								DBG_871X("NAT25: Replace DA with BR's MAC\n");
+								if ( (*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0 ) {
+									void netdev_br_init(struct net_device *netdev);
+									printk("Re-init netdev_br_init() due to br_mac==0!\n");
+									netdev_br_init(priv->pnetdev);
+								}
+								memcpy(skb->data, priv->br_mac, ETH_ALEN);
+							}
+						}
+					}
+				}
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle ARP frame                  */
+	/*---------------------------------------------------*/
+	else if(protocol == __constant_htons(ETH_P_ARP))
+	{
+		struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+		unsigned int *sender, *target;
+
+		if(arp->ar_pro != __constant_htons(ETH_P_IP))
+		{
+			DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro));
+			return -1;
+		}
+
+		switch(method)
+		{
+			case NAT25_CHECK:
+				return 0;	// skb_copy for all ARP frame
+
+			case NAT25_INSERT:
+				{
+					DBG_871X("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+						arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+					// change to ARP sender mac address to wlan STA address
+                                        memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+
+					arp_ptr += arp->ar_hln;
+					sender = (unsigned int *)arp_ptr;
+
+					__nat25_generate_ipv4_network_addr(networkAddr, sender);
+
+					__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+					__nat25_db_print(priv);
+				}
+				return 0;
+
+			case NAT25_LOOKUP:
+				{
+					DBG_871X("NAT25: Lookup ARP\n");
+
+					arp_ptr += arp->ar_hln;
+					sender = (unsigned int *)arp_ptr;
+					arp_ptr += (arp->ar_hln + arp->ar_pln);
+					target = (unsigned int *)arp_ptr;
+
+					__nat25_generate_ipv4_network_addr(networkAddr, target);
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+					// change to ARP target mac address to Lookup result
+					arp_ptr = (unsigned char *)(arp + 1);
+					arp_ptr += (arp->ar_hln + arp->ar_pln);
+					memcpy(arp_ptr, skb->data, ETH_ALEN);
+				}
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPX and Apple Talk frame           */
+	/*---------------------------------------------------*/
+	else if((protocol == __constant_htons(ETH_P_IPX)) || 
+		(protocol == __constant_htons(ETH_P_ATALK)) ||
+		(protocol == __constant_htons(ETH_P_AARP)))
+	{
+		unsigned char ipx_header[2] = {0xFF, 0xFF};
+		struct ipxhdr	*ipx = NULL;
+		struct elapaarp	*ea = NULL;
+		struct ddpehdr	*ddp = NULL;
+		unsigned char *framePtr = skb->data + ETH_HLEN;
+
+		if(protocol == __constant_htons(ETH_P_IPX))
+		{
+			DBG_871X("NAT25: Protocol=IPX (Ethernet II)\n");
+			ipx = (struct ipxhdr *)framePtr;
+		}
+		else //if(protocol <= __constant_htons(ETH_FRAME_LEN))
+		{
+			if(!memcmp(ipx_header, framePtr, 2))
+			{
+				DBG_871X("NAT25: Protocol=IPX (Ethernet 802.3)\n");
+				ipx = (struct ipxhdr *)framePtr;
+			}
+			else
+			{
+				unsigned char ipx_8022_type =  0xE0;
+				unsigned char snap_8022_type = 0xAA;
+
+				if(*framePtr == snap_8022_type)
+				{
+					unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37};		// IPX SNAP ID
+					unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3};	// Apple Talk AARP SNAP ID
+					unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B};	// Apple Talk DDP SNAP ID
+
+					framePtr += 3;	// eliminate the 802.2 header
+
+					if(!memcmp(ipx_snap_id, framePtr, 5))
+					{
+						framePtr += 5;	// eliminate the SNAP header
+
+						DBG_871X("NAT25: Protocol=IPX (Ethernet SNAP)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					}
+					else if(!memcmp(aarp_snap_id, framePtr, 5))
+					{
+						framePtr += 5;	// eliminate the SNAP header
+
+						ea = (struct elapaarp *)framePtr;
+					}
+					else if(!memcmp(ddp_snap_id, framePtr, 5))
+					{
+						framePtr += 5;	// eliminate the SNAP header
+
+						ddp = (struct ddpehdr *)framePtr;
+					}
+					else
+					{
+						DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
+							framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
+						return -1;
+					}
+				}
+				else if(*framePtr == ipx_8022_type)
+				{
+					framePtr += 3;	// eliminate the 802.2 header
+
+					if(!memcmp(ipx_header, framePtr, 2))
+					{
+						DBG_871X("NAT25: Protocol=IPX (Ethernet 802.2)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					}
+					else
+						return -1;
+				}
+			}
+		}
+
+		/*   IPX   */
+		if(ipx != NULL)
+		{
+			switch(method)
+			{
+				case NAT25_CHECK:
+					if(!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
+					{
+						DBG_871X("NAT25: Check IPX skb_copy\n");
+						return 0;
+					}
+					return -1;
+
+				case NAT25_INSERT:
+					{
+						DBG_871X("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
+							ipx->ipx_dest.net,
+							ipx->ipx_dest.node[0],
+							ipx->ipx_dest.node[1],
+							ipx->ipx_dest.node[2],
+							ipx->ipx_dest.node[3],
+							ipx->ipx_dest.node[4],
+							ipx->ipx_dest.node[5],
+							ipx->ipx_dest.sock,
+							ipx->ipx_source.net,
+							ipx->ipx_source.node[0],
+							ipx->ipx_source.node[1],
+							ipx->ipx_source.node[2],
+							ipx->ipx_source.node[3],
+							ipx->ipx_source.node[4],
+							ipx->ipx_source.node[5],
+							ipx->ipx_source.sock);
+
+						if(!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
+						{
+							DBG_871X("NAT25: Use IPX Net, and Socket as network addr\n");
+
+							__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
+
+							// change IPX source node addr to wlan STA address
+                                                        memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
+						}
+						else
+						{
+							__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
+						}
+
+						__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+						__nat25_db_print(priv);
+					}
+					return 0;
+
+				case NAT25_LOOKUP:
+					{
+                                                if(!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN))
+						{
+							DBG_871X("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
+
+							__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
+
+							__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+							// replace IPX destination node addr with Lookup destination MAC addr
+							memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
+						}
+						else
+						{
+							__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
+
+							__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+						}
+					}
+					return 0;
+
+				default:
+					return -1;
+			}
+		}
+
+		/*   AARP   */
+		else if(ea != NULL)
+		{
+			/* Sanity check fields. */
+			if(ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN)
+			{
+				DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
+				return -1;
+			}
+
+			switch(method)
+			{
+				case NAT25_CHECK:
+					return 0;
+
+				case NAT25_INSERT:
+					{
+						// change to AARP source mac address to wlan STA address
+                                                memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
+
+						DBG_871X("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n",
+							ea->pa_src_net,
+							ea->pa_src_node,
+							ea->pa_dst_net,
+							ea->pa_dst_node);
+
+						__nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
+
+						__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+						__nat25_db_print(priv);
+					}
+					return 0;
+
+				case NAT25_LOOKUP:
+					{
+						DBG_871X("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n",
+							ea->pa_src_net,
+							ea->pa_src_node,
+							ea->pa_dst_net,
+							ea->pa_dst_node);
+
+						__nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
+
+						__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+						// change to AARP destination mac address to Lookup result
+						memcpy(ea->hw_dst, skb->data, ETH_ALEN);
+					}
+					return 0;
+
+				default:
+					return -1;
+			}
+		}
+
+		/*   DDP   */
+		else if(ddp != NULL)
+		{
+			switch(method)
+			{
+				case NAT25_CHECK:
+					return -1;
+
+				case NAT25_INSERT:
+					{
+						DBG_871X("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n",
+							ddp->deh_snet,
+							ddp->deh_snode,
+							ddp->deh_dnet,
+							ddp->deh_dnode);
+
+						__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
+
+						__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+						__nat25_db_print(priv);
+					}
+					return 0;
+
+				case NAT25_LOOKUP:
+					{
+						DBG_871X("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n",
+							ddp->deh_snet,
+							ddp->deh_snode,
+							ddp->deh_dnet,
+							ddp->deh_dnode);
+
+						__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
+
+						__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+					}
+					return 0;
+
+				default:
+					return -1;
+			}
+		}
+
+		return -1;
+	}
+
+	/*---------------------------------------------------*/
+	/*                Handle PPPoE frame                 */
+	/*---------------------------------------------------*/
+	else if((protocol == __constant_htons(ETH_P_PPP_DISC)) ||
+		(protocol == __constant_htons(ETH_P_PPP_SES)))
+	{
+		struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+		unsigned short *pMagic;
+
+		switch(method)
+		{
+			case NAT25_CHECK:
+				if (ph->sid == 0)
+					return 0;
+				return 1;
+
+			case NAT25_INSERT:
+				if(ph->sid == 0)	// Discovery phase according to tag
+				{
+					if(ph->code == PADI_CODE || ph->code == PADR_CODE)
+					{
+						if (priv->ethBrExtInfo.addPPPoETag) {
+							struct pppoe_tag *tag, *pOldTag;
+							unsigned char tag_buf[40];
+							int old_tag_len=0;
+
+							tag = (struct pppoe_tag *)tag_buf;
+							pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+							if (pOldTag) { // if SID existed, copy old value and delete it
+								old_tag_len = ntohs(pOldTag->tag_len);
+								if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+									DEBUG_ERR("SID tag length too long!\n");
+									return -1;
+								}
+
+								memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
+									pOldTag->tag_data, old_tag_len);
+
+								if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
+									DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+									return -1;
+								}
+								ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
+							}
+
+							tag->tag_type = PTT_RELAY_SID;
+							tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
+
+							// insert the magic_code+client mac in relay tag
+							pMagic = (unsigned short *)tag->tag_data;
+							*pMagic = htons(MAGIC_CODE);
+							memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
+
+							//Add relay tag
+							if(__nat25_add_pppoe_tag(skb, tag) < 0)
+								return -1;
+
+							DBG_871X("NAT25: Insert PPPoE, forward %s packet\n",
+											(ph->code == PADI_CODE ? "PADI" : "PADR"));
+						}
+						else { // not add relay tag
+							if (priv->pppoe_connection_in_progress &&
+									memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))	 {
+								DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+								return -2;
+							}
+
+							if (priv->pppoe_connection_in_progress == 0)
+								memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
+
+							priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+						}
+					}
+					else
+						return -1;
+				}
+				else	// session phase
+				{
+						DBG_871X("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+						__nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
+
+						__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+						__nat25_db_print(priv);
+
+						if (!priv->ethBrExtInfo.addPPPoETag &&
+								priv->pppoe_connection_in_progress &&
+									!memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+							priv->pppoe_connection_in_progress = 0;
+				}
+				return 0;
+
+			case NAT25_LOOKUP:
+				if(ph->code == PADO_CODE || ph->code == PADS_CODE)
+				{
+					if (priv->ethBrExtInfo.addPPPoETag) {
+						struct pppoe_tag *tag;
+						unsigned char *ptr;
+						unsigned short tagType, tagLen;
+						int offset=0;
+
+						if((ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID))) == 0) {
+							DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
+							return -1;
+						}
+
+						tag = (struct pppoe_tag *)ptr;
+						tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
+						tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
+
+						if((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) {
+							DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
+							return -1;
+						}
+
+						pMagic = (unsigned short *)tag->tag_data;
+						if (ntohs(*pMagic) != MAGIC_CODE) {
+							DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
+								(ph->code == PADO_CODE ? "PADO" : "PADS"));
+							return -1;
+						}
+
+						memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN);
+
+						if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN)
+							offset = TAG_HDR_LEN;
+
+						if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) {
+							DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
+							return -1;
+						}
+						ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset));
+						if (offset > 0)
+							tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN);
+
+						DBG_871X("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
+							(ph->code == PADO_CODE ? "PADO" : "PADS"),	skb->dev->name);
+					}
+					else { // not add relay tag
+						if (!priv->pppoe_connection_in_progress) {
+							DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+							return -1;
+						}
+						memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
+						priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+					}
+				}
+				else {
+					if(ph->sid != 0)
+					{
+						DBG_871X("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
+						__nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid));
+
+						__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+						__nat25_db_print(priv);
+					}
+					else
+						return -1;
+
+				}
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*                 Handle EAP frame                  */
+	/*---------------------------------------------------*/
+	else if(protocol == __constant_htons(0x888e))
+	{
+		switch(method)
+		{
+			case NAT25_CHECK:
+				return -1;
+
+			case NAT25_INSERT:
+				return 0;
+
+			case NAT25_LOOKUP:
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle C-Media proprietary frame          */
+	/*---------------------------------------------------*/
+	else if((protocol == __constant_htons(0xe2ae)) ||
+		(protocol == __constant_htons(0xe2af)))
+	{
+		switch(method)
+		{
+			case NAT25_CHECK:
+				return -1;
+
+			case NAT25_INSERT:
+				return 0;
+
+			case NAT25_LOOKUP:
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+
+	/*---------------------------------------------------*/
+	/*         Handle IPV6 frame      							  */
+	/*---------------------------------------------------*/
+#ifdef CL_IPV6_PASS
+	else if(protocol == __constant_htons(ETH_P_IPV6))
+	{
+		struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+		if (sizeof(*iph) >= (skb->len - ETH_HLEN))
+		{
+			DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+			return -1;
+		}
+
+		switch(method)
+		{
+			case NAT25_CHECK:
+				if (skb->data[0] & 1)
+					return 0;				
+				return -1;
+
+			case NAT25_INSERT:
+				{
+					DBG_871X("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+									" DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", 
+						iph->saddr.s6_addr16[0],iph->saddr.s6_addr16[1],iph->saddr.s6_addr16[2],iph->saddr.s6_addr16[3],
+						iph->saddr.s6_addr16[4],iph->saddr.s6_addr16[5],iph->saddr.s6_addr16[6],iph->saddr.s6_addr16[7],
+						iph->daddr.s6_addr16[0],iph->daddr.s6_addr16[1],iph->daddr.s6_addr16[2],iph->daddr.s6_addr16[3],
+						iph->daddr.s6_addr16[4],iph->daddr.s6_addr16[5],iph->daddr.s6_addr16[6],iph->daddr.s6_addr16[7]);
+
+					if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+						__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+						__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+						__nat25_db_print(priv);
+
+						if (iph->nexthdr == IPPROTO_ICMPV6 && 
+								skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
+							if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), 
+                                                                skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {                                                   
+								struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+								hdr->icmp6_cksum = 0;
+								hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+												iph->payload_len,
+												IPPROTO_ICMPV6,
+												csum_partial((__u8 *)hdr, iph->payload_len, 0));
+							}
+						}						
+					}
+				}
+				return 0;
+
+			case NAT25_LOOKUP:
+				DBG_871X("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+								" DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", 
+						iph->saddr.s6_addr16[0],iph->saddr.s6_addr16[1],iph->saddr.s6_addr16[2],iph->saddr.s6_addr16[3],
+						iph->saddr.s6_addr16[4],iph->saddr.s6_addr16[5],iph->saddr.s6_addr16[6],iph->saddr.s6_addr16[7],
+						iph->daddr.s6_addr16[0],iph->daddr.s6_addr16[1],iph->daddr.s6_addr16[2],iph->daddr.s6_addr16[3],
+						iph->daddr.s6_addr16[4],iph->daddr.s6_addr16[5],iph->daddr.s6_addr16[6],iph->daddr.s6_addr16[7]);
+			
+
+				__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr);
+				if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+#ifdef SUPPORT_RX_UNI2MCAST							
+					if (iph->daddr.s6_addr[0] == 0xff)
+						convert_ipv6_mac_to_mc(skb);	
+#endif											
+				}
+				return 0;
+
+			default:
+				return -1;
+		}
+	}
+#endif	// CL_IPV6_PASS
+
+	return -1;
+}
+
+
+int nat25_handle_frame(_adapter *priv, struct sk_buff *skb)
+{
+#ifdef BR_EXT_DEBUG
+	if((!priv->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1)))
+	{
+		panic_printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n",
+			skb->data[0],
+			skb->data[1],
+			skb->data[2],
+			skb->data[3],
+			skb->data[4],
+			skb->data[5],
+			skb->data[6],
+			skb->data[7],
+			skb->data[8],
+			skb->data[9],
+			skb->data[10],
+			skb->data[11]);
+	}
+#endif
+
+	if(!(skb->data[0] & 1))
+	{
+		int is_vlan_tag=0, i, retval=0;
+		unsigned short vlan_hdr=0;
+
+		if (*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_8021Q)) {
+			is_vlan_tag = 1;
+			vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2));
+			for (i=0; i<6; i++)
+				*((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2));
+			skb_pull(skb, 4);
+		}
+
+		if (!priv->ethBrExtInfo.nat25_disable)
+		{
+			_irqL irqL;
+			_enter_critical_bh(&priv->br_ext_lock, &irqL);
+			/*
+			 *	This function look up the destination network address from
+			 *	the NAT2.5 database. Return value = -1 means that the
+			 *	corresponding network protocol is NOT support.
+			 */
+			if (!priv->ethBrExtInfo.nat25sc_disable &&
+				(*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP)) &&
+				!memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) {
+				memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+				
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			}
+			else {
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+				
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		}
+		else {
+			if (((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP)) &&
+					!memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) ||
+				((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_ARP)) &&
+					!memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) {
+				// for traffic to upper TCP/IP
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		}
+
+		if (is_vlan_tag) {
+			skb_push(skb, 4);
+			for (i=0; i<6; i++)
+				*((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+			*((unsigned short *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q);
+			*((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr;
+		}
+
+		if(retval == -1) {
+			//DEBUG_ERR("NAT25: Lookup fail!\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+#if 0
+void mac_clone(_adapter *priv, unsigned char *addr)
+{
+	struct sockaddr sa;
+
+	memcpy(sa.sa_data, addr, ETH_ALEN);
+	DBG_871X("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n",
+		addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+	rtl8192cd_set_hwaddr(priv->dev, &sa);
+}
+
+
+int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb)
+{
+	if(priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed)
+	{
+		if(!(skb->data[ETH_ALEN] & 1))	//// check any other particular MAC add
+		{
+                        if(memcmp(skb->data+ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) &&
+				((priv->dev->br_port) &&
+				 memcmp(skb->data+ETH_ALEN, priv->br_mac, ETH_ALEN)))
+			{
+				mac_clone(priv, skb->data+ETH_ALEN);
+				priv->macclone_completed = 1;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif // 0
+
+#define SERVER_PORT			67
+#define CLIENT_PORT			68
+#define DHCP_MAGIC			0x63825363
+#define BROADCAST_FLAG		0x8000
+
+struct dhcpMessage {
+	u_int8_t op;
+	u_int8_t htype;
+	u_int8_t hlen;
+	u_int8_t hops;
+	u_int32_t xid;
+	u_int16_t secs;
+	u_int16_t flags;
+	u_int32_t ciaddr;
+	u_int32_t yiaddr;
+	u_int32_t siaddr;
+	u_int32_t giaddr;
+	u_int8_t chaddr[16];
+	u_int8_t sname[64];
+	u_int8_t file[128];
+	u_int32_t cookie;
+	u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb)
+{
+	if(skb == NULL)
+		return;
+
+	if(!priv->ethBrExtInfo.dhcp_bcst_disable)
+	{
+		unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
+
+		if(protocol == __constant_htons(ETH_P_IP)) // IP
+		{
+			struct iphdr* iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+			if(iph->protocol == IPPROTO_UDP) // UDP
+			{
+				struct udphdr *udph = (struct udphdr *)((SIZE_PTR)iph + (iph->ihl << 2));
+
+				if((udph->source == __constant_htons(CLIENT_PORT))
+					&& (udph->dest == __constant_htons(SERVER_PORT))) // DHCP request
+				{
+					struct dhcpMessage *dhcph =
+						(struct dhcpMessage *)((SIZE_PTR)udph + sizeof(struct udphdr));
+
+					if(dhcph->cookie == __constant_htonl(DHCP_MAGIC)) // match magic word
+					{
+						if(!(dhcph->flags & htons(BROADCAST_FLAG))) // if not broadcast
+						{
+							register int sum = 0;
+
+							DBG_871X("DHCP: change flag of DHCP request to broadcast.\n");
+							// or BROADCAST flag
+							dhcph->flags |= htons(BROADCAST_FLAG);
+							// recalculate checksum
+							sum = ~(udph->check) & 0xffff;
+							sum += dhcph->flags;
+							while(sum >> 16)
+								sum = (sum & 0xffff) + (sum >> 16);
+							udph->check = ~sum;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+void *scdb_findEntry(_adapter *priv, unsigned char *macAddr,
+				unsigned char *ipAddr)
+{
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+	struct nat25_network_db_entry *db;
+	int hash;
+	//_irqL irqL;
+	//_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	__nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL)
+	{
+		if(!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			//_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return (void *)db;
+		}
+
+		db = db->next_hash;
+	}
+
+	//_exit_critical_bh(&priv->br_ext_lock, &irqL);
+	return NULL;
+}
+
+#endif	// CONFIG_BR_EXT
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_bt_mp.c b/drivers/net/wireless/rtl8189es/core/rtw_bt_mp.c
new file mode 100644
index 000000000000..d4d8968a8ea1
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_bt_mp.c
@@ -0,0 +1,1753 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *										  
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#include <drv_types.h>
+#include <rtw_bt_mp.h>
+
+#if defined(CONFIG_RTL8723B)
+#include <rtl8723b_hal.h>
+#endif
+
+#if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8821A)
+void MPh2c_timeout_handle(void *FunctionContext)
+{
+	PADAPTER pAdapter;
+	PMPT_CONTEXT pMptCtx;
+
+
+	DBG_8192C("[MPT], MPh2c_timeout_handle \n");
+
+	pAdapter = (PADAPTER)FunctionContext;
+	pMptCtx = &pAdapter->mppriv.MptCtx;
+
+	pMptCtx->bMPh2c_timeout = _TRUE;
+
+	if ((_FALSE == pMptCtx->MptH2cRspEvent)
+		|| ((_TRUE == pMptCtx->MptH2cRspEvent)
+			&& (_FALSE == pMptCtx->MptBtC2hEvent)))
+	{
+		_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+	}
+}
+
+u32 WaitC2Hevent(PADAPTER pAdapter, u8 *C2H_event, u32 delay_time)
+{
+	PMPT_CONTEXT		pMptCtx=&(pAdapter->mppriv.MptCtx);
+	pMptCtx->bMPh2c_timeout=_FALSE;
+	
+	if( pAdapter->registrypriv.mp_mode == 0 )
+	{
+		DBG_8192C("[MPT], Error!! WaitC2Hevent mp_mode == 0!!\n");
+		return _FALSE;
+	}
+
+	_set_timer( &pMptCtx->MPh2c_timeout_timer, delay_time );
+	
+	_rtw_down_sema(&pMptCtx->MPh2c_Sema);
+
+	if (pMptCtx->bMPh2c_timeout == _TRUE)
+	{
+		*C2H_event = _FALSE;
+		
+		return _FALSE;
+	}
+
+	// for safty, cancel timer here again
+	_cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer);
+	
+	return _TRUE;
+}
+
+BT_CTRL_STATUS
+mptbt_CheckC2hFrame(
+	PADAPTER		Adapter,
+	PBT_H2C			pH2c,
+	PBT_EXT_C2H		pExtC2h
+	)
+{
+	BT_CTRL_STATUS	c2hStatus = BT_STATUS_C2H_SUCCESS;
+		
+	//DBG_8192C("[MPT], MPT rsp C2H hex: %x %x %x  %x %x %x \n"), pExtC2h , pExtC2h+1 ,pExtC2h+2 ,pExtC2h+3 ,pExtC2h+4 ,pExtC2h+5);
+
+	DBG_8192C("[MPT], statusCode = 0x%x\n", pExtC2h->statusCode);
+	DBG_8192C("[MPT], retLen = %d\n", pExtC2h->retLen);
+	DBG_8192C("[MPT], opCodeVer : req/rsp=%d/%d\n", pH2c->opCodeVer, pExtC2h->opCodeVer);
+	DBG_8192C("[MPT], reqNum : req/rsp=%d/%d\n", pH2c->reqNum, pExtC2h->reqNum);
+	if(pExtC2h->reqNum != pH2c->reqNum)
+	{
+		c2hStatus = BT_STATUS_C2H_REQNUM_MISMATCH;
+		DBG_8192C("[MPT], Error!! C2H reqNum Mismatch!!\n");
+	}
+	else if(pExtC2h->opCodeVer != pH2c->opCodeVer)
+	{
+		c2hStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH;
+		DBG_8192C("[MPT], Error!! OPCode version L mismatch!!\n");
+	}
+
+	return c2hStatus;
+}
+
+BT_CTRL_STATUS
+mptbt_SendH2c(
+	PADAPTER	Adapter,
+	PBT_H2C	pH2c,
+	u2Byte		h2cCmdLen
+	)
+{
+	//KIRQL				OldIrql = KeGetCurrentIrql();
+	BT_CTRL_STATUS	h2cStatus=BT_STATUS_H2C_SUCCESS;
+	PMPT_CONTEXT		pMptCtx=&(Adapter->mppriv.MptCtx);
+	u1Byte				i;
+
+	DBG_8192C("[MPT], mptbt_SendH2c()=========>\n");
+
+	//PlatformResetEvent(&pMptCtx->MptH2cRspEvent);
+	//PlatformResetEvent(&pMptCtx->MptBtC2hEvent);
+	
+//	if(OldIrql == PASSIVE_LEVEL)
+//	{
+		//RTPRINT_DATA(FMPBT, FMPBT_H2C_CONTENT, ("[MPT], MPT H2C hex: \n"), pH2c, h2cCmdLen);
+
+		for(i=0; i<BT_H2C_MAX_RETRY; i++)
+		{
+			DBG_8192C("[MPT], Send H2C command to wifi!!!\n");
+
+			pMptCtx->MptH2cRspEvent = _FALSE;
+			pMptCtx->MptBtC2hEvent = _FALSE;
+
+#if defined(CONFIG_RTL8723B)
+			rtl8723b_set_FwBtMpOper_cmd(Adapter, pH2c->opCode, pH2c->opCodeVer, pH2c->reqNum, pH2c->buf);
+#endif
+			pMptCtx->h2cReqNum++;
+			pMptCtx->h2cReqNum %= 16;
+
+			if(WaitC2Hevent(Adapter, &pMptCtx->MptH2cRspEvent, 100))
+			{
+				DBG_8192C("[MPT], Received WiFi MptH2cRspEvent!!!\n");
+				if(WaitC2Hevent(Adapter, &pMptCtx->MptBtC2hEvent, 400))
+				{
+					DBG_8192C("[MPT], Received MptBtC2hEvent!!!\n");
+					break;
+				}
+				else
+				{
+					DBG_8192C("[MPT], Error!!BT MptBtC2hEvent timeout!!\n");
+					h2cStatus = BT_STATUS_H2C_BT_NO_RSP;
+				}
+			}
+			else
+			{
+				DBG_8192C("[MPT], Error!!WiFi  MptH2cRspEvent timeout!!\n");
+				h2cStatus = BT_STATUS_H2C_TIMTOUT;
+			}
+		}
+//	}
+//	else
+//	{
+//		RT_ASSERT(FALSE, ("[MPT],  mptbt_SendH2c() can only run under PASSIVE_LEVEL!!\n"));
+//		h2cStatus = BT_STATUS_WRONG_LEVEL;
+//	}
+
+	DBG_8192C("[MPT], mptbt_SendH2c()<=========\n");
+	return h2cStatus;
+}
+
+
+
+BT_CTRL_STATUS
+mptbt_CheckBtRspStatus(
+	PADAPTER			Adapter,
+	PBT_EXT_C2H			pExtC2h
+	)
+{
+	BT_CTRL_STATUS	retStatus=BT_OP_STATUS_SUCCESS;
+
+	switch(pExtC2h->statusCode)
+	{
+		case BT_OP_STATUS_SUCCESS:
+			retStatus = BT_STATUS_BT_OP_SUCCESS;
+			DBG_8192C("[MPT], BT status : BT_STATUS_SUCCESS\n");
+			break;
+		case BT_OP_STATUS_VERSION_MISMATCH:
+			retStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH;
+			DBG_8192C("[MPT], BT status : BT_STATUS_OPCODE_L_VERSION_MISMATCH\n");
+			break;
+		case BT_OP_STATUS_UNKNOWN_OPCODE:
+			retStatus = BT_STATUS_UNKNOWN_OPCODE_L;
+			DBG_8192C("[MPT], BT status : BT_STATUS_UNKNOWN_OPCODE_L\n");
+			break;
+		case BT_OP_STATUS_ERROR_PARAMETER:
+			retStatus = BT_STATUS_PARAMETER_FORMAT_ERROR_L;
+			DBG_8192C("[MPT], BT status : BT_STATUS_PARAMETER_FORMAT_ERROR_L\n");
+			break;
+		default:
+			retStatus = BT_STATUS_UNKNOWN_STATUS_L;
+			DBG_8192C("[MPT], BT status : BT_STATUS_UNKNOWN_STATUS_L\n");
+			break;
+	}
+	
+	return retStatus;
+}	
+
+
+
+BT_CTRL_STATUS
+mptbt_BtFwOpCodeProcess(
+	PADAPTER		Adapter,
+	u1Byte			btFwOpCode,
+	u1Byte			opCodeVer,
+	pu1Byte			pH2cPar,
+	u1Byte			h2cParaLen
+	)
+{
+	u1Byte				H2C_Parameter[6] ={0};
+	PBT_H2C				pH2c=(PBT_H2C)&H2C_Parameter[0];
+	PMPT_CONTEXT		pMptCtx=&(Adapter->mppriv.MptCtx);
+	PBT_EXT_C2H			pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u2Byte				paraLen=0,i;
+	BT_CTRL_STATUS	h2cStatus=BT_STATUS_H2C_SUCCESS, c2hStatus=BT_STATUS_C2H_SUCCESS;
+	BT_CTRL_STATUS	retStatus=BT_STATUS_H2C_BT_NO_RSP;
+
+	if( Adapter->registrypriv.mp_mode == 0 )
+	{
+		DBG_8192C("[MPT], Error!! mptbt_BtFwOpCodeProces mp_mode == 0!!\n");
+		return _FALSE;
+	}
+
+	pH2c->opCode = btFwOpCode;
+	pH2c->opCodeVer = opCodeVer;
+	pH2c->reqNum = pMptCtx->h2cReqNum;
+	//PlatformMoveMemory(&pH2c->buf[0], pH2cPar, h2cParaLen);
+	//_rtw_memcpy(&pH2c->buf[0], pH2cPar, h2cParaLen);
+	_rtw_memcpy(pH2c->buf, pH2cPar, h2cParaLen);
+
+	DBG_8192C("[MPT], pH2c->opCode=%d\n", pH2c->opCode);
+	DBG_8192C("[MPT], pH2c->opCodeVer=%d\n", pH2c->opCodeVer);
+	DBG_8192C("[MPT], pH2c->reqNum=%d\n", pH2c->reqNum);
+	DBG_8192C("[MPT], h2c parameter length=%d\n", h2cParaLen);
+	for (i=0; i<h2cParaLen; i++)
+	{
+		DBG_8192C("[MPT], parameter[%d]=0x%02x\n", i, pH2c->buf[i]);
+	}
+
+	h2cStatus = mptbt_SendH2c(Adapter, pH2c, h2cParaLen+2);
+	if(BT_STATUS_H2C_SUCCESS == h2cStatus)
+	{
+		// if reach here, it means H2C get the correct c2h response, 
+		c2hStatus = mptbt_CheckC2hFrame(Adapter, pH2c, pExtC2h);
+		if(BT_STATUS_C2H_SUCCESS == c2hStatus)
+		{
+			retStatus = mptbt_CheckBtRspStatus(Adapter, pExtC2h);
+		}
+		else
+		{
+			DBG_8192C("[MPT], Error!! C2H failed for pH2c->opCode=%d\n", pH2c->opCode);
+			// check c2h status error, return error status code to upper layer.
+			retStatus = c2hStatus;
+		}
+	}
+	else
+	{
+		DBG_8192C("[MPT], Error!! H2C failed for pH2c->opCode=%d\n", pH2c->opCode);
+		// check h2c status error, return error status code to upper layer.
+		retStatus = h2cStatus;
+	}
+
+	return retStatus;
+}
+
+
+
+
+u2Byte
+mptbt_BtReady(
+	PADAPTER		Adapter,
+	PBT_REQ_CMD 	pBtReq,
+	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	PMPT_CONTEXT		pMptCtx=&(Adapter->mppriv.MptCtx);
+	PBT_EXT_C2H			pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u1Byte				i;
+	u1Byte				btFwVer=0, bdAddr[6]={0};
+	u2Byte				btRealFwVer=0;
+	pu2Byte 			pu2Tmp=NULL;
+
+	//
+	// check upper layer parameters
+	//
+
+	// 1. check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+
+	pBtRsp->pParamStart[0] = MP_BT_NOT_READY;
+	paraLen = 10;
+	//
+	// execute lower layer opcodes
+	//
+
+	// Get BT FW version
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_GET_BT_VERSION;
+	// execute h2c and check respond c2h from bt fw is correct or not
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+	else
+	{
+		pu2Tmp = (pu2Byte)&pExtC2h->buf[0];
+		btRealFwVer = *pu2Tmp;
+		btFwVer = pExtC2h->buf[1];
+		DBG_8192C("[MPT], btRealFwVer=0x%x, btFwVer=0x%x\n", btRealFwVer, btFwVer);
+	}
+
+	// Get BD Address
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_GET_BD_ADDR_L;
+	// execute h2c and check respond c2h from bt fw is correct or not
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+	else
+	{
+		bdAddr[5] = pExtC2h->buf[0];
+		bdAddr[4] = pExtC2h->buf[1];
+		bdAddr[3] = pExtC2h->buf[2];
+	}
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_GET_BD_ADDR_H;
+	// execute h2c and check respond c2h from bt fw is correct or not
+	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+	else
+	{
+		bdAddr[2] = pExtC2h->buf[0];
+		bdAddr[1] = pExtC2h->buf[1];
+		bdAddr[0] = pExtC2h->buf[2];
+	}
+	DBG_8192C("[MPT], Local BDAddr:");
+	for(i=0; i<6; i++)
+	{
+		DBG_8192C(" 0x%x ", bdAddr[i]);
+	}
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	pBtRsp->pParamStart[0] = MP_BT_READY;
+	pu2Tmp = (pu2Byte)&pBtRsp->pParamStart[1];
+	*pu2Tmp = btRealFwVer;
+	pBtRsp->pParamStart[3] = btFwVer;
+	for(i=0; i<6; i++)
+	{
+		pBtRsp->pParamStart[4+i] = bdAddr[5-i];
+	}
+
+	return paraLen;
+}
+
+void mptbt_close_WiFiRF(PADAPTER Adapter)
+{
+	PHY_SetBBReg(Adapter, 0x824, 0xF, 0x0);
+	PHY_SetBBReg(Adapter, 0x824, 0x700000, 0x0);
+	PHY_SetRFReg(Adapter, RF90_PATH_A, 0x0, 0xF0000, 0x0);
+}
+
+void mptbt_open_WiFiRF(PADAPTER	Adapter)
+{
+	PHY_SetBBReg(Adapter, 0x824, 0x700000, 0x3);
+	PHY_SetBBReg(Adapter, 0x824, 0xF, 0x2);
+	PHY_SetRFReg(Adapter, RF90_PATH_A, 0x0, 0xF0000, 0x3);
+}
+
+u4Byte mptbt_switch_RF(PADAPTER	Adapter, u1Byte	Enter)
+{
+	u2Byte	tmp_2byte = 0;
+
+	//Enter test mode
+	if (Enter) {
+		////1>. close WiFi RF
+		mptbt_close_WiFiRF(Adapter);
+		
+		////2>. change ant switch to BT
+		tmp_2byte = rtw_read16(Adapter, 0x860);
+		tmp_2byte = tmp_2byte | BIT(9);
+		tmp_2byte = tmp_2byte & (~BIT(8));
+		rtw_write16(Adapter, 0x860, tmp_2byte);
+		rtw_write16(Adapter, 0x870, 0x300);
+	} else {
+		////1>. Open WiFi RF
+		mptbt_open_WiFiRF(Adapter);
+		
+		////2>. change ant switch back
+		tmp_2byte = rtw_read16(Adapter, 0x860);
+		tmp_2byte = tmp_2byte | BIT(8);
+		tmp_2byte = tmp_2byte & (~BIT(9));
+		rtw_write16(Adapter, 0x860, tmp_2byte);
+		rtw_write16(Adapter, 0x870, 0x300);
+	}
+
+	return 0;
+}
+
+u2Byte
+mptbt_BtSetMode(
+	PADAPTER		Adapter,
+	PBT_REQ_CMD 	pBtReq,
+	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	u1Byte				btModeToSet=0;
+
+	//
+	// check upper layer parameters
+	//
+	// 1. check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	// 2. check upper layer parameter length
+	if(1 == pBtReq->paraLength)
+	{
+		btModeToSet = pBtReq->pParamStart[0];
+		DBG_8192C("[MPT], BtTestMode=%d \n", btModeToSet);
+	}
+	else
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	
+	//
+	// execute lower layer opcodes
+	//
+	
+	// 1. fill h2c parameters	
+	// check bt mode
+	btOpcode = BT_LO_OP_SET_BT_MODE;
+	if(btModeToSet >= MP_BT_MODE_MAX)
+	{
+		pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		mptbt_switch_RF(Adapter, 1);
+
+		h2cParaBuf[0] = btModeToSet;
+		h2cParaLen = 1;
+		// 2. execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// 3. construct respond status code and data.
+	if(BT_STATUS_BT_OP_SUCCESS == retStatus)
+	{
+		pBtRsp->status = BT_STATUS_SUCCESS;
+	}
+	else
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+	}
+	
+	return paraLen;
+}
+
+
+VOID
+MPTBT_FwC2hBtMpCtrl(
+	PADAPTER	Adapter,
+	pu1Byte 	tmpBuf,
+	u1Byte		length
+	)
+{
+	u32 i;
+	PMPT_CONTEXT	pMptCtx=&(Adapter->mppriv.MptCtx);
+	PBT_EXT_C2H pExtC2h=(PBT_EXT_C2H)tmpBuf;
+	
+	if(Adapter->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0 )
+	{	
+		//DBG_8192C("Ignore C2H BT MP Info since not in MP mode \n");
+		return;
+	}
+	if( length > 32 || length < 3 )
+	{
+		DBG_8192C("\n [MPT], pExtC2h->buf hex: length=%d > 32 || < 3\n",length);
+		return;
+	}
+
+	//cancel_timeout for h2c handle
+	_cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer);
+
+	for (i=0; i<length; i++)
+	{
+		DBG_8192C("[MPT], %s, buf[%d]=0x%02x ", __FUNCTION__, i, tmpBuf[i]);
+	}
+	DBG_8192C("[MPT], pExtC2h->extendId=0x%x\n", pExtC2h->extendId);
+	
+	switch(pExtC2h->extendId)
+	{
+		case EXT_C2H_WIFI_FW_ACTIVE_RSP:
+			DBG_8192C("[MPT], EXT_C2H_WIFI_FW_ACTIVE_RSP\n");
+#if 0
+			DBG_8192C("[MPT], pExtC2h->buf hex: \n");
+			for (i=0; i<(length-3); i++)
+			{
+				DBG_8192C(" 0x%x ", pExtC2h->buf[i]);
+			}
+#endif
+			if ((_FALSE == pMptCtx->bMPh2c_timeout)
+				&& (_FALSE == pMptCtx->MptH2cRspEvent))
+			{
+				pMptCtx->MptH2cRspEvent = _TRUE;
+				_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+			}
+			break;
+
+		case EXT_C2H_TRIG_BY_BT_FW:
+			DBG_8192C("[MPT], EXT_C2H_TRIG_BY_BT_FW\n");
+			_rtw_memcpy(&pMptCtx->c2hBuf[0], tmpBuf, length);
+			DBG_8192C("[MPT], pExtC2h->statusCode=0x%x\n", pExtC2h->statusCode);
+			DBG_8192C("[MPT], pExtC2h->retLen=0x%x\n", pExtC2h->retLen);
+			DBG_8192C("[MPT], pExtC2h->opCodeVer=0x%x\n", pExtC2h->opCodeVer);
+			DBG_8192C("[MPT], pExtC2h->reqNum=0x%x\n", pExtC2h->reqNum);
+			for (i=0; i<(length-3); i++)
+			{
+				DBG_8192C("[MPT], pExtC2h->buf[%d]=0x%02x\n", i, pExtC2h->buf[i]);
+			}
+
+			if ((_FALSE == pMptCtx->bMPh2c_timeout)
+				&& (_TRUE == pMptCtx->MptH2cRspEvent)
+				&& (_FALSE == pMptCtx->MptBtC2hEvent))
+			{
+				pMptCtx->MptBtC2hEvent = _TRUE;
+				_rtw_up_sema(&pMptCtx->MPh2c_Sema);
+			}
+			break;
+
+		default:
+			DBG_8192C("[MPT], EXT_C2H Target not found,pExtC2h->extendId =%d ,pExtC2h->reqNum=%d\n",pExtC2h->extendId,pExtC2h->reqNum);
+			break;
+	}
+	
+
+	
+}
+
+
+u2Byte
+mptbt_BtGetGeneral(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD 	pBtReq,
+	IN	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	PMPT_CONTEXT		pMptCtx=&(Adapter->mppriv.MptCtx);
+	PBT_EXT_C2H 		pExtC2h=(PBT_EXT_C2H)&pMptCtx->c2hBuf[0];
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode, bdAddr[6]={0};
+	u1Byte				btOpcodeVer=0;
+	u1Byte				getType=0, i;
+	u2Byte				getParaLen=0, validParaLen=0;
+	u1Byte				regType=0, reportType=0;
+	u4Byte				regAddr=0, regValue=0;
+	pu4Byte 			pu4Tmp;
+	pu2Byte 			pu2Tmp;
+	pu1Byte 			pu1Tmp;
+
+	//
+	// check upper layer parameters
+	//
+	
+	// check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	// check upper layer parameter length
+	if(pBtReq->paraLength < 1)
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	getParaLen = pBtReq->paraLength - 1;
+	getType = pBtReq->pParamStart[0];
+	
+	DBG_8192C("[MPT], getType=%d, getParaLen=%d\n", getType, getParaLen);
+
+	// check parameter first
+	switch(getType)
+	{
+		case BT_GGET_REG:
+			DBG_8192C("[MPT], [BT_GGET_REG]\n");
+			validParaLen = 5;
+			if(getParaLen == validParaLen)
+			{
+				btOpcode = BT_LO_OP_READ_REG;
+				regType = pBtReq->pParamStart[1];
+				pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2];
+				regAddr = *pu4Tmp;
+				DBG_8192C("[MPT], BT_GGET_REG regType=0x%02x, regAddr=0x%08x!!\n",
+					regType, regAddr);
+				if(regType >= BT_REG_MAX)
+				{
+					pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				else
+				{
+					if( ((BT_REG_RF==regType)&&(regAddr>0x7f)) ||
+						((BT_REG_MODEM==regType)&&(regAddr>0x1ff)) ||
+						((BT_REG_BLUEWIZE==regType)&&(regAddr>0xfff)) ||
+						((BT_REG_VENDOR==regType)&&(regAddr>0xfff)) ||
+						((BT_REG_LE==regType)&&(regAddr>0xfff)) )
+					{				
+						pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+						return paraLen;
+					}
+				}
+			}
+			break;
+		case BT_GGET_STATUS:
+			DBG_8192C("[MPT], [BT_GGET_STATUS]\n");
+			validParaLen = 0;
+			break;
+		case BT_GGET_REPORT:
+			DBG_8192C("[MPT], [BT_GGET_REPORT]\n");
+			validParaLen = 1;
+			if(getParaLen == validParaLen)
+			{
+				reportType = pBtReq->pParamStart[1];
+				DBG_8192C("[MPT], BT_GGET_REPORT reportType=0x%x!!\n", reportType);
+				if(reportType >= BT_REPORT_MAX)
+				{
+					pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+			}
+			break;
+		default:
+			{
+				DBG_8192C("[MPT], Error!! getType=%d, out of range\n", getType);
+				pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+			break;
+	}
+	if(getParaLen != validParaLen)
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d for BT_GET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n",
+			getParaLen, getType, validParaLen);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	
+	//
+	// execute lower layer opcodes
+	//
+	if(BT_GGET_REG == getType)
+	{
+		// fill h2c parameters
+		// here we should write reg value first then write the address, adviced by Austin
+		btOpcode = BT_LO_OP_READ_REG;
+		h2cParaBuf[0] = regType;
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		// execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// construct respond status code and data.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+
+		pu2Tmp = (pu2Byte)&pExtC2h->buf[0];
+		regValue = *pu2Tmp;
+		DBG_8192C("[MPT], read reg regType=0x%02x, regAddr=0x%08x, regValue=0x%04x\n", 
+			regType, regAddr, regValue);
+		
+		pu4Tmp = (pu4Byte)&pBtRsp->pParamStart[0];
+		*pu4Tmp = regValue;
+		paraLen = 4;
+	}
+	else if(BT_GGET_STATUS == getType)
+	{
+		btOpcode = BT_LO_OP_GET_BT_STATUS;
+		h2cParaLen = 0;
+		// execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// construct respond status code and data.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+
+		pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+		pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+		DBG_8192C("[MPT], read bt status, testMode=0x%x, testStatus=0x%x\n", 
+			pBtRsp->pParamStart[0], pBtRsp->pParamStart[1]);		
+		paraLen = 2;
+	}
+	else if(BT_GGET_REPORT == getType)
+	{
+		switch(reportType)
+		{
+			case BT_REPORT_RX_PACKET_CNT:
+				{
+					DBG_8192C("[MPT], [Rx Packet Counts]\n");
+					btOpcode = BT_LO_OP_GET_RX_PKT_CNT_L;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+					btOpcode = BT_LO_OP_GET_RX_PKT_CNT_H;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+					paraLen = 4;
+				}
+				break;
+			case BT_REPORT_RX_ERROR_BITS:
+				{
+					DBG_8192C("[MPT], [Rx Error Bits]\n");
+					btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_L;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+					btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_H;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+					paraLen = 4;
+				}
+				break;
+			case BT_REPORT_RSSI:
+				{
+					DBG_8192C("[MPT], [RSSI]\n");
+					btOpcode = BT_LO_OP_GET_RSSI;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+					paraLen = 2;
+				}
+				break;
+			case BT_REPORT_CFO_HDR_QUALITY:
+				{
+					DBG_8192C("[MPT], [CFO & Header Quality]\n");
+					btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_L;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[0] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[1] = pExtC2h->buf[1];
+
+					btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_H;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					pBtRsp->pParamStart[2] = pExtC2h->buf[0];
+					pBtRsp->pParamStart[3] = pExtC2h->buf[1];
+					paraLen = 4;
+				}
+				break;
+			case BT_REPORT_CONNECT_TARGET_BD_ADDR:
+				{
+					DBG_8192C("[MPT], [Connected Target BD ADDR]\n");
+					btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_L;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					bdAddr[5] = pExtC2h->buf[0];
+					bdAddr[4] = pExtC2h->buf[1];
+					bdAddr[3] = pExtC2h->buf[2];
+
+					btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_H;
+					h2cParaLen = 0;
+					// execute h2c and check respond c2h from bt fw is correct or not
+					retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+					// construct respond status code and data.
+					if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+					{
+						pBtRsp->status = ((btOpcode<<8)|retStatus);
+						DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+						return paraLen;
+					}
+					bdAddr[2] = pExtC2h->buf[0];
+					bdAddr[1] = pExtC2h->buf[1];
+					bdAddr[0] = pExtC2h->buf[2];
+						
+					DBG_8192C("[MPT], Connected Target BDAddr:%s", bdAddr);
+					for(i=0; i<6; i++)
+					{
+						pBtRsp->pParamStart[i] = bdAddr[5-i];
+					}
+					paraLen = 6;
+				}
+				break;
+			default:
+				pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+				break;
+		}
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtSetGeneral(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD 	pBtReq,
+	IN	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	u1Byte				setType=0;
+	u2Byte				setParaLen=0, validParaLen=0;
+	u1Byte				regType=0, bdAddr[6]={0}, calVal=0;
+	u4Byte				regAddr=0, regValue=0;
+	pu4Byte 			pu4Tmp;
+	pu2Byte 			pu2Tmp;
+	pu1Byte 			pu1Tmp;
+
+	//
+	// check upper layer parameters
+	//
+	
+	// check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	// check upper layer parameter length
+	if(pBtReq->paraLength < 1)
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	setParaLen = pBtReq->paraLength - 1;
+	setType = pBtReq->pParamStart[0];
+	
+	DBG_8192C("[MPT], setType=%d, setParaLen=%d\n", setType, setParaLen);
+
+	// check parameter first
+	switch(setType)
+	{
+		case BT_GSET_REG:
+			DBG_8192C ("[MPT], [BT_GSET_REG]\n");
+			validParaLen = 9;
+			if(setParaLen == validParaLen)
+			{
+				btOpcode = BT_LO_OP_WRITE_REG_VALUE;
+				regType = pBtReq->pParamStart[1];
+				pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2];
+				regAddr = *pu4Tmp;
+				pu4Tmp = (pu4Byte)&pBtReq->pParamStart[6];
+				regValue = *pu4Tmp;
+				DBG_8192C("[MPT], BT_GSET_REG regType=0x%x, regAddr=0x%x, regValue=0x%x!!\n", 
+					regType, regAddr, regValue);
+				if(regType >= BT_REG_MAX)
+				{
+					pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				else
+				{
+					if( ((BT_REG_RF==regType)&&(regAddr>0x7f)) ||
+						((BT_REG_MODEM==regType)&&(regAddr>0x1ff)) ||
+						((BT_REG_BLUEWIZE==regType)&&(regAddr>0xfff)) ||
+						((BT_REG_VENDOR==regType)&&(regAddr>0xfff)) ||
+						((BT_REG_LE==regType)&&(regAddr>0xfff)) )
+					{				
+						pBtRsp->status = (btOpcode<<8)| BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+						return paraLen;
+					}
+				}
+			}
+			break;
+		case BT_GSET_RESET:
+			DBG_8192C("[MPT], [BT_GSET_RESET]\n");
+			validParaLen = 0;
+			break;
+		case BT_GSET_TARGET_BD_ADDR:
+			DBG_8192C("[MPT], [BT_GSET_TARGET_BD_ADDR]\n");
+			validParaLen = 6;
+			if(setParaLen == validParaLen)
+			{
+				btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H;
+				if( (pBtReq->pParamStart[1]==0) &&
+					(pBtReq->pParamStart[2]==0) &&
+					(pBtReq->pParamStart[3]==0) &&
+					(pBtReq->pParamStart[4]==0) &&
+					(pBtReq->pParamStart[5]==0) &&
+					(pBtReq->pParamStart[6]==0) )
+				{
+					DBG_8192C("[MPT], Error!! targetBDAddr=all zero\n");
+					pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				if( (pBtReq->pParamStart[1]==0xff) &&
+					(pBtReq->pParamStart[2]==0xff) &&
+					(pBtReq->pParamStart[3]==0xff) &&
+					(pBtReq->pParamStart[4]==0xff) &&
+					(pBtReq->pParamStart[5]==0xff) &&
+					(pBtReq->pParamStart[6]==0xff) )
+				{
+					DBG_8192C("[MPT], Error!! targetBDAddr=all 0xf\n");
+					pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				bdAddr[0] = pBtReq->pParamStart[6];
+				bdAddr[1] = pBtReq->pParamStart[5];
+				bdAddr[2] = pBtReq->pParamStart[4];
+				bdAddr[3] = pBtReq->pParamStart[3];
+				bdAddr[4] = pBtReq->pParamStart[2];
+				bdAddr[5] = pBtReq->pParamStart[1];
+				DBG_8192C ("[MPT], target BDAddr:%x,%x,%x,%x,%x,%x\n", 
+							bdAddr[0],bdAddr[1],bdAddr[2],bdAddr[3],bdAddr[4],bdAddr[5]);
+			}
+			break;
+		case BT_GSET_TX_PWR_FINETUNE:
+			DBG_8192C("[MPT], [BT_GSET_TX_PWR_FINETUNE]\n");
+			validParaLen = 1;
+			if(setParaLen == validParaLen)
+			{
+				btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION;
+				calVal = pBtReq->pParamStart[1];
+				if( (calVal<1) || (calVal>9) )
+				{
+					pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				DBG_8192C ("[MPT], calVal=%d\n", calVal);
+			}
+			break;
+		case BT_SET_TRACKING_INTERVAL:
+			DBG_871X("[MPT], [BT_SET_TRACKING_INTERVAL] setParaLen =%d \n",setParaLen);
+			
+			validParaLen = 1;	
+			if(setParaLen == validParaLen)	
+				calVal = pBtReq->pParamStart[1];
+			break;
+		case BT_SET_THERMAL_METER:
+			DBG_871X("[MPT], [BT_SET_THERMAL_METER] setParaLen =%d \n",setParaLen);
+			validParaLen = 1;	
+			if(setParaLen == validParaLen)	
+				calVal = pBtReq->pParamStart[1];
+			break;
+		case BT_ENABLE_CFO_TRACKING:
+			DBG_871X("[MPT], [BT_ENABLE_CFO_TRACKING] setParaLen =%d \n",setParaLen);
+			validParaLen = 1;	
+			if(setParaLen == validParaLen)	
+				calVal = pBtReq->pParamStart[1];
+			break;
+		case BT_GSET_UPDATE_BT_PATCH:
+			
+			break;
+		default:
+			{
+				DBG_8192C ("[MPT], Error!! setType=%d, out of range\n", setType);
+				pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+				return paraLen;
+			}
+			break;
+	}
+	if(setParaLen != validParaLen)
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d for BT_SET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n",
+			setParaLen, setType, validParaLen);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	
+	//
+	// execute lower layer opcodes
+	//
+	if(BT_GSET_REG == setType)
+	{
+		// fill h2c parameters
+		// here we should write reg value first then write the address, adviced by Austin
+		btOpcode = BT_LO_OP_WRITE_REG_VALUE;
+		h2cParaBuf[0] = pBtReq->pParamStart[6];
+		h2cParaBuf[1] = pBtReq->pParamStart[7];
+		h2cParaBuf[2] = pBtReq->pParamStart[8];
+		h2cParaLen = 3;
+		// execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// construct respond status code and data.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+		
+		// write reg address
+		btOpcode = BT_LO_OP_WRITE_REG_ADDR;
+		h2cParaBuf[0] = regType;
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		// execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// construct respond status code and data.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}		
+	}
+	else if(BT_GSET_RESET == setType)
+	{
+		btOpcode = BT_LO_OP_RESET;
+		h2cParaLen = 0;
+		// execute h2c and check respond c2h from bt fw is correct or not
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// construct respond status code and data.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+	}
+	else if(BT_GSET_TARGET_BD_ADDR == setType)
+	{
+		// fill h2c parameters
+		btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_L;
+		h2cParaBuf[0] = pBtReq->pParamStart[1];
+		h2cParaBuf[1] = pBtReq->pParamStart[2];
+		h2cParaBuf[2] = pBtReq->pParamStart[3];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);		
+		// ckeck bt return status.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+
+		btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H;
+		h2cParaBuf[0] = pBtReq->pParamStart[4];
+		h2cParaBuf[1] = pBtReq->pParamStart[5];
+		h2cParaBuf[2] = pBtReq->pParamStart[6];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);		
+		// ckeck bt return status.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+	}
+	else if(BT_GSET_TX_PWR_FINETUNE == setType)
+	{
+		// fill h2c parameters
+		btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION;
+		h2cParaBuf[0] = calVal;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		// ckeck bt return status.
+		if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+		{
+			pBtRsp->status = ((btOpcode<<8)|retStatus);
+			DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+	}
+	else if(BT_SET_TRACKING_INTERVAL == setType)
+	{
+		//	BT_LO_OP_SET_TRACKING_INTERVAL								= 0x22,
+		//	BT_LO_OP_SET_THERMAL_METER									= 0x23,
+		//	BT_LO_OP_ENABLE_CFO_TRACKING									= 0x24,
+				btOpcode = BT_LO_OP_SET_TRACKING_INTERVAL;
+				h2cParaBuf[0] = calVal;
+				h2cParaLen = 1;
+				retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);		
+				// ckeck bt return status.
+				if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+				{
+					pBtRsp->status = ((btOpcode<<8)|retStatus);
+					DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+					return paraLen;
+				}
+	}
+	else if(BT_SET_THERMAL_METER == setType)
+	{
+				btOpcode = BT_LO_OP_SET_THERMAL_METER;
+				h2cParaBuf[0] = calVal;
+				h2cParaLen = 1;
+				retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);		
+				// ckeck bt return status.
+				if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+				{
+					pBtRsp->status = ((btOpcode<<8)|retStatus);
+					DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+					return paraLen;
+				}
+	}
+	else if(BT_ENABLE_CFO_TRACKING == setType)
+	{
+				btOpcode = BT_LO_OP_ENABLE_CFO_TRACKING;
+				h2cParaBuf[0] = calVal;
+				h2cParaLen = 1;
+				retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);		
+				// ckeck bt return status.
+				if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+				{
+					pBtRsp->status = ((btOpcode<<8)|retStatus);
+					DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+			return paraLen;
+		}
+	}
+	
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtSetTxRxPars(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD 	pBtReq,
+	IN	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	PBT_TXRX_PARAMETERS pTxRxPars=(PBT_TXRX_PARAMETERS)&pBtReq->pParamStart[0];
+	u2Byte				lenTxRx=sizeof(BT_TXRX_PARAMETERS);
+	u1Byte				i;
+	u1Byte				bdAddr[6]={0};
+
+	//
+	// check upper layer parameters
+	//
+	
+	// 1. check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	// 2. check upper layer parameter length
+	if(pBtReq->paraLength == sizeof(BT_TXRX_PARAMETERS))
+	{	
+		DBG_8192C ("[MPT], pTxRxPars->txrxChannel=0x%x \n", pTxRxPars->txrxChannel);
+		DBG_8192C ("[MPT], pTxRxPars->txrxTxPktCnt=0x%8x \n", pTxRxPars->txrxTxPktCnt);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxTxPktInterval=0x%x \n", pTxRxPars->txrxTxPktInterval);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxPayloadType=0x%x \n", pTxRxPars->txrxPayloadType);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxPktType=0x%x \n", pTxRxPars->txrxPktType);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxPayloadLen=0x%x \n", pTxRxPars->txrxPayloadLen);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxPktHeader=0x%x \n", pTxRxPars->txrxPktHeader);
+		DBG_8192C  ("[MPT], pTxRxPars->txrxWhitenCoeff=0x%x \n", pTxRxPars->txrxWhitenCoeff); 	
+		bdAddr[0] = pTxRxPars->txrxBdaddr[5];
+		bdAddr[1] = pTxRxPars->txrxBdaddr[4];
+		bdAddr[2] = pTxRxPars->txrxBdaddr[3];
+		bdAddr[3] = pTxRxPars->txrxBdaddr[2];
+		bdAddr[4] = pTxRxPars->txrxBdaddr[1];
+		bdAddr[5] = pTxRxPars->txrxBdaddr[0];
+		DBG_8192C  ("[MPT], pTxRxPars->txrxBdaddr: %s", &bdAddr[0]);
+		DBG_8192C ("[MPT], pTxRxPars->txrxTxGainIndex=0x%x \n", pTxRxPars->txrxTxGainIndex);
+	}
+	else
+	{
+		DBG_8192C  ("[MPT], Error!! pBtReq->paraLength=%d, correct Len=%d\n", pBtReq->paraLength, lenTxRx);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+
+	//
+	// execute lower layer opcodes
+	//
+	
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_PKT_HEADER;
+	if(pTxRxPars->txrxPktHeader > 0x3ffff)
+	{
+		DBG_8192C  ("[MPT], Error!! pTxRxPars->txrxPktHeader=0x%x is out of range, (should be between 0x0~0x3ffff)\n", pTxRxPars->txrxPktHeader);
+		pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		h2cParaBuf[0] = (u1Byte)(pTxRxPars->txrxPktHeader&0xff);
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPktHeader&0xff00)>>8);
+		h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPktHeader&0xff0000)>>16);
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C  ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}	
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_PKT_TYPE_LEN;
+	{
+		u2Byte	payloadLenLimit=0;
+		switch(pTxRxPars->txrxPktType)
+		{
+			case MP_BT_PKT_DH1:
+				payloadLenLimit = 27*8;
+				break;
+			case MP_BT_PKT_DH3:
+				payloadLenLimit = 183*8;
+				break;
+			case MP_BT_PKT_DH5:
+				payloadLenLimit = 339*8;
+				break;
+			case MP_BT_PKT_2DH1:
+				payloadLenLimit = 54*8;
+				break;
+			case MP_BT_PKT_2DH3:
+				payloadLenLimit = 367*8;
+				break;
+			case MP_BT_PKT_2DH5:
+				payloadLenLimit = 679*8;
+				break;
+			case MP_BT_PKT_3DH1:
+				payloadLenLimit = 83*8;
+				break;
+			case MP_BT_PKT_3DH3:
+				payloadLenLimit = 552*8;
+				break;
+			case MP_BT_PKT_3DH5:
+				payloadLenLimit = 1021*8;
+				break;
+			case MP_BT_PKT_LE:
+				payloadLenLimit = 39*8;
+				break;
+			default:
+				{
+					DBG_8192C  ("[MPT], Error!! Unknown pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType);
+					pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+					return paraLen;
+				}
+				break;
+		}
+
+		if(pTxRxPars->txrxPayloadLen > payloadLenLimit)
+		{
+			DBG_8192C ("[MPT], Error!! pTxRxPars->txrxPayloadLen=0x%x, (should smaller than %d)\n", 
+				pTxRxPars->txrxPayloadLen, payloadLenLimit);
+			pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+			return paraLen;
+		}
+
+		h2cParaBuf[0] = pTxRxPars->txrxPktType;
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPayloadLen&0xff));
+		h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPayloadLen&0xff00)>>8);
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_PKT_CNT_L_PL_TYPE;
+	if(pTxRxPars->txrxPayloadType > MP_BT_PAYLOAD_MAX)
+	{
+		DBG_8192C  ("[MPT], Error!! pTxRxPars->txrxPayloadType=0x%x, (should be between 0~4)\n", pTxRxPars->txrxPayloadType);
+		pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff));
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff00)>>8);
+		h2cParaBuf[2] = pTxRxPars->txrxPayloadType;
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}	
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_PKT_CNT_H_PKT_INTV;
+	if(pTxRxPars->txrxTxPktInterval > 15)
+	{
+	DBG_8192C  ("[MPT], Error!! pTxRxPars->txrxTxPktInterval=0x%x, (should be between 0~15)\n", pTxRxPars->txrxTxPktInterval);
+	pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff0000)>>16);
+		h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt&0xff000000)>>24);
+		h2cParaBuf[2] = pTxRxPars->txrxTxPktInterval;
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}	
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_WHITENCOEFF;
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxWhitenCoeff;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C  ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_CHNL_TX_GAIN;
+	if( (pTxRxPars->txrxChannel > 78) ||
+		(pTxRxPars->txrxTxGainIndex > 7) )
+	{
+		DBG_8192C ("[MPT], Error!! pTxRxPars->txrxChannel=0x%x, (should be between 0~78)\n", pTxRxPars->txrxChannel);
+		DBG_8192C ("[MPT], Error!! pTxRxPars->txrxTxGainIndex=0x%x, (should be between 0~7)\n", pTxRxPars->txrxTxGainIndex);
+		pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxChannel;
+		h2cParaBuf[1] = pTxRxPars->txrxTxGainIndex;
+		h2cParaLen = 2;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+	// fill h2c parameters
+	btOpcode = BT_LO_OP_SET_BD_ADDR_L;
+	if( (pTxRxPars->txrxBdaddr[0]==0) &&
+		(pTxRxPars->txrxBdaddr[1]==0) &&
+		(pTxRxPars->txrxBdaddr[2]==0) &&
+		(pTxRxPars->txrxBdaddr[3]==0) &&
+		(pTxRxPars->txrxBdaddr[4]==0) &&
+		(pTxRxPars->txrxBdaddr[5]==0) )
+	{
+		DBG_8192C ("[MPT], Error!! pTxRxPars->txrxBdaddr=all zero\n");
+		pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	if( (pTxRxPars->txrxBdaddr[0]==0xff) &&
+		(pTxRxPars->txrxBdaddr[1]==0xff) &&
+		(pTxRxPars->txrxBdaddr[2]==0xff) &&
+		(pTxRxPars->txrxBdaddr[3]==0xff) &&
+		(pTxRxPars->txrxBdaddr[4]==0xff) &&
+		(pTxRxPars->txrxBdaddr[5]==0xff) )
+	{
+		DBG_8192C ("[MPT], Error!! pTxRxPars->txrxBdaddr=all 0xf\n");
+		pBtRsp->status = (btOpcode<<8)|BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxBdaddr[0];
+		h2cParaBuf[1] = pTxRxPars->txrxBdaddr[1];
+		h2cParaBuf[2] = pTxRxPars->txrxBdaddr[2];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}	
+
+	btOpcode = BT_LO_OP_SET_BD_ADDR_H;
+	{
+		h2cParaBuf[0] = pTxRxPars->txrxBdaddr[3];
+		h2cParaBuf[1] = pTxRxPars->txrxBdaddr[4];
+		h2cParaBuf[2] = pTxRxPars->txrxBdaddr[5];
+		h2cParaLen = 3;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	// ckeck bt return status.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C  ("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+
+u2Byte
+mptbt_BtTestCtrl(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD 	pBtReq,
+	IN	PBT_RSP_CMD 	pBtRsp
+	)
+{
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	u1Byte				testCtrl=0;
+
+	//
+	// check upper layer parameters
+	//
+	
+	// 1. check upper layer opcode version
+	if(pBtReq->opCodeVer != 1)
+	{
+		DBG_8192C("[MPT], Error!! Upper OP code version not match!!!\n");
+		pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH;
+		return paraLen;
+	}
+	// 2. check upper layer parameter length
+	if(1 == pBtReq->paraLength)
+	{
+		testCtrl = pBtReq->pParamStart[0];
+		DBG_8192C("[MPT], testCtrl=%d \n", testCtrl);
+	}
+	else
+	{
+		DBG_8192C("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength);
+		pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U;
+		return paraLen;
+	}
+	
+	//
+	// execute lower layer opcodes
+	//
+	
+	// 1. fill h2c parameters	
+	// check bt mode
+	btOpcode = BT_LO_OP_TEST_CTRL;
+	if(testCtrl >= MP_BT_TEST_MAX)
+	{
+		DBG_8192C("[MPT], Error!! testCtrl=0x%x, (should be between smaller or equal to 0x%x)\n", 
+			testCtrl, MP_BT_TEST_MAX-1);
+		pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U;
+		return paraLen;
+	}
+	else
+	{
+		h2cParaBuf[0] = testCtrl;
+		h2cParaLen = 1;
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+	}
+	
+	// 3. construct respond status code and data.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+
+u2Byte
+mptbt_TestBT(
+	IN	PADAPTER		Adapter,
+	IN	PBT_REQ_CMD 	pBtReq,
+	IN	PBT_RSP_CMD 	pBtRsp
+	)
+{
+
+	u1Byte				h2cParaBuf[6] ={0};
+	u1Byte				h2cParaLen=0;
+	u2Byte				paraLen=0;
+	u1Byte				retStatus=BT_STATUS_BT_OP_SUCCESS;
+	u1Byte				btOpcode;
+	u1Byte				btOpcodeVer=0;
+	u1Byte				testCtrl=0;
+
+	// 1. fill h2c parameters	
+		btOpcode =  0x11;
+		h2cParaBuf[0] = 0x11;
+		h2cParaBuf[1] = 0x0;
+		h2cParaBuf[2] = 0x0;
+		h2cParaBuf[3] = 0x0;
+		h2cParaBuf[4] = 0x0;
+		h2cParaLen = 1;
+	//	retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen);
+		retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, h2cParaBuf, h2cParaLen);
+	
+	
+	// 3. construct respond status code and data.
+	if(BT_STATUS_BT_OP_SUCCESS != retStatus)
+	{
+		pBtRsp->status = ((btOpcode<<8)|retStatus);
+		DBG_8192C("[MPT], Error!! status code=0x%x \n", pBtRsp->status);
+		return paraLen;
+	}
+
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	return paraLen;
+}
+
+VOID
+mptbt_BtControlProcess(
+	PADAPTER	Adapter,
+	PVOID		pInBuf
+	)
+{
+	u1Byte			H2C_Parameter[6] ={0};
+	PBT_H2C 		pH2c=(PBT_H2C)&H2C_Parameter[0];
+	PMPT_CONTEXT	pMptCtx=&(Adapter->mppriv.MptCtx);
+	PBT_REQ_CMD 	pBtReq=(PBT_REQ_CMD)pInBuf;
+	PBT_RSP_CMD 	pBtRsp;
+	u1Byte			i;
+
+
+	DBG_8192C("[MPT], mptbt_BtControlProcess()=========>\n");
+
+	DBG_8192C("[MPT], input opCodeVer=%d\n", pBtReq->opCodeVer);
+	DBG_8192C("[MPT], input OpCode=%d\n", pBtReq->OpCode);
+	DBG_8192C("[MPT], paraLength=%d \n", pBtReq->paraLength);
+	if(pBtReq->paraLength)
+	{
+		//DBG_8192C("[MPT], parameters(hex):0x%x %d \n",&pBtReq->pParamStart[0], pBtReq->paraLength);
+	}
+
+	_rtw_memset((void*)pMptCtx->mptOutBuf, 0, 100);
+	pMptCtx->mptOutLen = 4; //length of (BT_RSP_CMD.status+BT_RSP_CMD.paraLength)
+
+	pBtRsp = (PBT_RSP_CMD)pMptCtx->mptOutBuf;
+	pBtRsp->status = BT_STATUS_SUCCESS;
+	pBtRsp->paraLength = 0x0;
+
+	// The following we should maintain the User OP codes sent by upper layer
+	switch(pBtReq->OpCode)
+	{
+		case BT_UP_OP_BT_READY:
+			DBG_8192C("[MPT], OPcode : [BT_READY]\n");
+			pBtRsp->paraLength = mptbt_BtReady(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_BT_SET_MODE:
+			DBG_8192C("[MPT], OPcode : [BT_SET_MODE]\n");
+			pBtRsp->paraLength = mptbt_BtSetMode(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_BT_SET_TX_RX_PARAMETER:
+			DBG_8192C("[MPT], OPcode : [BT_SET_TXRX_PARAMETER]\n");
+			pBtRsp->paraLength = mptbt_BtSetTxRxPars(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_BT_SET_GENERAL:
+			DBG_8192C("[MPT], OPcode : [BT_SET_GENERAL]\n");
+			pBtRsp->paraLength = mptbt_BtSetGeneral(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_BT_GET_GENERAL:
+			DBG_8192C("[MPT], OPcode : [BT_GET_GENERAL]\n");
+			pBtRsp->paraLength = mptbt_BtGetGeneral(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_BT_TEST_CTRL:
+			DBG_8192C("[MPT], OPcode : [BT_TEST_CTRL]\n");
+			pBtRsp->paraLength = mptbt_BtTestCtrl(Adapter, pBtReq, pBtRsp);
+			break;
+		case BT_UP_OP_TEST_BT:
+			DBG_8192C("[MPT], OPcode : [TEST_BT]\n");
+			pBtRsp->paraLength = mptbt_TestBT(Adapter, pBtReq, pBtRsp);
+			break;
+		default:
+			DBG_8192C("[MPT], Error!! OPcode : UNDEFINED!!!!\n");
+			pBtRsp->status = BT_STATUS_UNKNOWN_OPCODE_U;
+			pBtRsp->paraLength = 0x0;
+			break;
+	}
+
+	pMptCtx->mptOutLen += pBtRsp->paraLength;
+
+	DBG_8192C("[MPT], pMptCtx->mptOutLen=%d, pBtRsp->paraLength=%d\n", pMptCtx->mptOutLen, pBtRsp->paraLength);
+	DBG_8192C("[MPT], mptbt_BtControlProcess()<=========\n");
+}
+
+#endif
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_btcoex.c b/drivers/net/wireless/rtl8189es/core/rtw_btcoex.c
new file mode 100644
index 000000000000..fa5af56010cc
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_btcoex.c
@@ -0,0 +1,1689 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2013 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifdef CONFIG_BT_COEXIST
+
+#include <drv_types.h>
+#include <hal_btcoex.h>
+#include <hal_data.h>
+
+
+void rtw_btcoex_Initialize(PADAPTER padapter)
+{
+	hal_btcoex_Initialize(padapter);
+}
+
+void rtw_btcoex_PowerOnSetting(PADAPTER padapter)
+{
+	hal_btcoex_PowerOnSetting(padapter);
+}
+
+void rtw_btcoex_PreLoadFirmware(PADAPTER padapter)
+{
+	hal_btcoex_PreLoadFirmware(padapter);
+}
+
+void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly)
+{
+	hal_btcoex_InitHwConfig(padapter, bWifiOnly);
+}
+
+void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_IpsNotify(padapter, type);
+}
+
+void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_LpsNotify(padapter, type);
+}
+
+void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type)
+{
+	PHAL_DATA_TYPE	pHalData;
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	PBT_MGNT	pBtMgnt=&pcoex_info->BtMgnt;
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if ((_FALSE == type) && (padapter->pbuddy_adapter))
+	{
+		PADAPTER pbuddy = padapter->pbuddy_adapter;
+		if (check_fwstate(&pbuddy->mlmepriv, WIFI_SITE_MONITOR) == _TRUE)
+			return;
+	}
+#endif
+
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+	if(pBtMgnt->ExtConfig.bEnableWifiScanNotify)
+		rtw_btcoex_SendScanNotify(padapter, type);
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX	
+
+	hal_btcoex_ScanNotify(padapter, type);
+}
+
+void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+#ifdef DBG_CONFIG_ERROR_RESET
+	if (_TRUE == rtw_hal_sreset_inprogress(padapter))
+	{
+		DBG_8192C(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n",
+			FUNC_ADPT_ARG(padapter));
+		return;
+	}
+#endif // DBG_CONFIG_ERROR_RESET
+		
+#ifdef CONFIG_CONCURRENT_MODE
+	if ((_FALSE == action) && (padapter->pbuddy_adapter))
+	{
+		PADAPTER pbuddy = padapter->pbuddy_adapter;
+		if (check_fwstate(&pbuddy->mlmepriv, WIFI_UNDER_LINKING) == _TRUE)
+			return;
+	}
+#endif
+
+	hal_btcoex_ConnectNotify(padapter, action);
+}
+
+void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+#ifdef DBG_CONFIG_ERROR_RESET
+	if (_TRUE == rtw_hal_sreset_inprogress(padapter))
+	{
+		DBG_8192C(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n",
+			FUNC_ADPT_ARG(padapter));
+		return;
+	}
+#endif // DBG_CONFIG_ERROR_RESET
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if ((RT_MEDIA_DISCONNECT == mediaStatus) && (padapter->pbuddy_adapter))
+	{
+		PADAPTER pbuddy = padapter->pbuddy_adapter;
+		if (check_fwstate(&pbuddy->mlmepriv, WIFI_ASOC_STATE) == _TRUE)
+			return;
+	}
+#endif // CONFIG_CONCURRENT_MODE
+
+	if ((RT_MEDIA_CONNECT == mediaStatus)
+		&& (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE))
+	{
+		rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL);
+	}
+
+	hal_btcoex_MediaStatusNotify(padapter, mediaStatus);
+}
+
+void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_SpecialPacketNotify(padapter, pktType);
+}
+
+void rtw_btcoex_IQKNotify(PADAPTER padapter, u8 state)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_IQKNotify(padapter, state);
+}
+
+void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_BtInfoNotify(padapter, length, tmpBuf);
+}
+
+void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	hal_btcoex_SuspendNotify(padapter, state);
+}
+
+void rtw_btcoex_HaltNotify(PADAPTER padapter)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+	if (_FALSE == padapter->bup)
+	{
+		DBG_871X(FUNC_ADPT_FMT ": bup=%d Skip!\n",
+			FUNC_ADPT_ARG(padapter), padapter->bup);
+
+		return;
+	}
+
+	if (rtw_is_surprise_removed(padapter)) {
+		DBG_871X(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n",
+			FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter)?"True":"False");
+
+		return;
+	}
+
+	hal_btcoex_HaltNotify(padapter);
+}
+
+void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter)
+{
+	hal_btcoex_SwitchBtTRxMask(padapter);	
+}
+
+void rtw_btcoex_Switch(PADAPTER padapter, u8 enable)
+{
+	hal_btcoex_SetBTCoexist(padapter, enable);
+}
+
+u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter)
+{
+	return hal_btcoex_IsBtDisabled(padapter);
+}
+
+void rtw_btcoex_Handler(PADAPTER padapter)
+{
+	PHAL_DATA_TYPE	pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+
+	if (_FALSE == pHalData->EEPROMBluetoothCoexist)
+		return;
+
+#if defined(CONFIG_CONCURRENT_MODE)
+	if (padapter->adapter_type != PRIMARY_ADAPTER)
+		return;
+#endif
+
+
+
+	hal_btcoex_Hanlder(padapter);
+}
+
+s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter)
+{
+	s32 coexctrl;
+
+	coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter);
+
+	return coexctrl;
+}
+
+s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter)
+{
+	s32 coexctrl;
+
+	coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter);
+
+	return coexctrl;
+}
+
+u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter)
+{
+	u32 size;
+
+	size = hal_btcoex_GetAMPDUSize(padapter);
+
+	return size;
+}
+
+void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual)
+{
+	if (_TRUE == manual)
+	{
+		hal_btcoex_SetManualControl(padapter, _TRUE);
+	}
+	else
+	{
+		hal_btcoex_SetManualControl(padapter, _FALSE);
+	}
+}
+
+u8 rtw_btcoex_1Ant(PADAPTER padapter)
+{
+	return hal_btcoex_1Ant(padapter);
+}
+
+u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter)
+{
+	return hal_btcoex_IsBtControlLps(padapter);
+}
+
+u8 rtw_btcoex_IsLpsOn(PADAPTER padapter)
+{
+	return hal_btcoex_IsLpsOn(padapter);
+}
+
+u8 rtw_btcoex_RpwmVal(PADAPTER padapter)
+{
+	return hal_btcoex_RpwmVal(padapter);
+}
+
+u8 rtw_btcoex_LpsVal(PADAPTER padapter)
+{
+	return hal_btcoex_LpsVal(padapter);
+}
+
+void rtw_btcoex_SetBTCoexist(PADAPTER padapter, u8 bBtExist)
+{
+	hal_btcoex_SetBTCoexist(padapter, bBtExist);
+}
+
+void rtw_btcoex_SetChipType(PADAPTER padapter, u8 chipType)
+{
+	hal_btcoex_SetChipType(padapter, chipType);
+}
+
+void rtw_btcoex_SetPGAntNum(PADAPTER padapter, u8 antNum)
+{
+	hal_btcoex_SetPgAntNum(padapter, antNum);
+}
+
+u8 rtw_btcoex_GetPGAntNum(PADAPTER padapter)
+{
+	return hal_btcoex_GetPgAntNum(padapter);
+}
+
+void rtw_btcoex_SetSingleAntPath(PADAPTER padapter, u8 singleAntPath)
+{
+	hal_btcoex_SetSingleAntPath(padapter, singleAntPath);
+}
+
+u32 rtw_btcoex_GetRaMask(PADAPTER padapter)
+{
+	return hal_btcoex_GetRaMask(padapter);
+}
+
+void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen)
+{
+	hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen);
+}
+
+void rtw_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize)
+{
+	hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
+}
+
+void rtw_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule)
+{
+	hal_btcoex_SetDBG(padapter, pDbgModule);
+}
+
+u32 rtw_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize)
+{
+	return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize);
+}
+
+u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter)
+{
+	return hal_btcoex_IncreaseScanDeviceNum(padapter);
+}
+
+u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter)
+{
+	return hal_btcoex_IsBtLinkExist(padapter);
+}
+
+void rtw_btcoex_SetBtPatchVersion(PADAPTER padapter,u16 btHciVer, u16 btPatchVer)
+{
+	hal_btcoex_SetBtPatchVersion(padapter,btHciVer,btPatchVer);
+}
+
+void rtw_btcoex_SetHciVersion(PADAPTER  padapter, u16 hciVersion)
+{
+	hal_btcoex_SetHciVersion(padapter, hciVersion);
+}
+
+void rtw_btcoex_StackUpdateProfileInfo(void) 
+{
+	hal_btcoex_StackUpdateProfileInfo();
+}
+
+void rtw_btcoex_BTOffOnNotify(PADAPTER padapter, u8 bBTON)
+{
+	hal_btcoex_BTOffOnNotify(padapter, bBTON);
+}
+
+// ==================================================
+// Below Functions are called by BT-Coex
+// ==================================================
+void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter)
+{
+	rtw_rx_ampdu_apply(padapter);
+}
+
+void rtw_btcoex_LPS_Enter(PADAPTER padapter)
+{
+	struct pwrctrl_priv *pwrpriv;
+	u8 lpsVal;
+
+
+	pwrpriv = adapter_to_pwrctl(padapter);
+
+	pwrpriv->bpower_saving = _TRUE;
+	lpsVal = rtw_btcoex_LpsVal(padapter);
+	rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX");
+}
+
+void rtw_btcoex_LPS_Leave(PADAPTER padapter)
+{
+	struct pwrctrl_priv *pwrpriv;
+
+
+	pwrpriv = adapter_to_pwrctl(padapter);
+
+	if (pwrpriv->pwr_mode != PS_MODE_ACTIVE)
+	{
+		rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX");
+		LPS_RF_ON_check(padapter, 100);
+		pwrpriv->bpower_saving = _FALSE;
+	}
+}
+
+
+// ==================================================
+// Below Functions are BT-Coex socket related function
+// ==================================================
+
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+_adapter *pbtcoexadapter = NULL;
+u8 rtw_btcoex_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	u8 *btinfo;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	btinfo = rtw_zmalloc(len);
+	if (btinfo == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		rtw_mfree((u8*)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = len;
+	pdrvextra_cmd_parm->pbuf = btinfo;
+
+	_rtw_memcpy(btinfo, buf, len);
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+	return res;
+}
+
+u8 rtw_btcoex_send_event_to_BT(_adapter *padapter, u8 status,  u8 event_code, u8 opcode_low, u8 opcode_high,u8 *dbg_msg)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0,tx_event_length = 0;
+	rtw_HCI_event *pEvent;
+	
+	pEvent = (rtw_HCI_event*)(&localBuf[0]);
+
+	pEvent->EventCode = event_code;
+	pEvent->Data[0] = 0x1;	//packet #
+	pEvent->Data[1] = opcode_low;
+	pEvent->Data[2] = opcode_high;
+	len = len + 3;
+
+		// Return parameters starts from here
+	pRetPar = &pEvent->Data[len];		
+	pRetPar[0] = status;		//status
+
+	len++;
+	pEvent->Length = len;
+
+	//total tx event length + EventCode length + sizeof(length)
+	tx_event_length = pEvent->Length + 2;
+#if 0
+	rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, dbg_msg);
+#endif		
+	status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		
+	return status;
+}
+
+/* 
+Ref: 
+Realtek Wi-Fi Driver
+Host Controller Interface for
+Bluetooth 3.0 + HS V1.4 2013/02/07
+
+Window team code & BT team code
+ */
+
+
+u8 rtw_btcoex_parse_BT_info_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	#define BT_INFO_LENGTH 8
+	
+	u8 curPollEnable = pcmd[0];
+	u8 curPollTime = pcmd[1];
+	u8 btInfoReason = pcmd[2];
+	u8 btInfoLen = pcmd[3];
+	u8 btinfo[BT_INFO_LENGTH];
+
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0,tx_event_length = 0;
+	RTW_HCI_STATUS status = HCI_STATUS_SUCCESS;
+	rtw_HCI_event *pEvent;
+
+	DBG_871X("%s\n",__func__);
+	DBG_871X("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime);
+	DBG_871X("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen);
+	/*DBG_871X("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
+		,pcmd[4],pcmd[5],pcmd[6],pcmd[7],pcmd[8],pcmd[9],pcmd[10],pcmd[11]);*/
+
+	_rtw_memset(btinfo, 0, BT_INFO_LENGTH);
+	
+#if 1
+	if(BT_INFO_LENGTH != btInfoLen)
+	{
+		status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+		DBG_871X("Error BT Info Length: %d\n",btInfoLen);
+		//return _FAIL;
+	}
+	else
+#endif
+	{
+		if(0x1 == btInfoReason || 0x2 == btInfoReason)
+		{
+			_rtw_memcpy(btinfo, &pcmd[4], btInfoLen);
+			btinfo[0] = btInfoReason;
+			rtw_btcoex_btinfo_cmd(padapter,btinfo,btInfoLen);
+		}
+		else
+		{
+			DBG_871X("Other BT info reason\n");
+		}
+	}
+
+	//send complete event to BT
+	{
+
+		pEvent = (rtw_HCI_event*)(&localBuf[0]);
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_INFO_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_INFO_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+			// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+			//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+#if 0
+		rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length,"BT_info_event");
+#endif		
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		
+		return status;
+			//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_BT_patch_ver_info_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	RTW_HCI_STATUS status=HCI_STATUS_SUCCESS;
+	u16		btPatchVer=0x0, btHciVer=0x0;
+	//u16		*pU2tmp;
+	
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+
+	btHciVer = pcmd[0] | pcmd[1]<<8;
+	btPatchVer = pcmd[2] | pcmd[3]<<8;
+
+
+	DBG_871X("%s, cmd:%02x %02x %02x %02x\n",__func__, pcmd[0] ,pcmd[1] ,pcmd[2] ,pcmd[3]);
+	DBG_871X("%s, HCI Ver:%d, Patch Ver:%d\n",__func__, btHciVer,btPatchVer);
+	
+	rtw_btcoex_SetBtPatchVersion(padapter,btHciVer,btPatchVer);
+
+
+	//send complete event to BT
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+#if 0
+		rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length,"BT_patch_event");
+#endif
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_HCI_Ver_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	RTW_HCI_STATUS status=HCI_STATUS_SUCCESS;
+	u16 hciver = pcmd[0] | pcmd[1] <<8;
+	
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	PBT_MGNT	pBtMgnt=&pcoex_info->BtMgnt;
+	pBtMgnt->ExtConfig.HCIExtensionVer = hciver;
+	DBG_871X("%s, HCI Version: %d\n",__func__,pBtMgnt->ExtConfig.HCIExtensionVer);
+	if(pBtMgnt->ExtConfig.HCIExtensionVer  < 4)
+	{
+		status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+		DBG_871X("%s, Version = %d, HCI Version < 4\n",__func__,pBtMgnt->ExtConfig.HCIExtensionVer );
+	}
+	else
+	{
+		rtw_btcoex_SetHciVersion(padapter,hciver);
+	}
+	//send complete event to BT
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+	
+}
+
+u8 rtw_btcoex_parse_WIFI_scan_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	RTW_HCI_STATUS status=HCI_STATUS_SUCCESS;
+
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	PBT_MGNT	pBtMgnt=&pcoex_info->BtMgnt;
+	pBtMgnt->ExtConfig.bEnableWifiScanNotify= pcmd[0];
+	DBG_871X("%s, bEnableWifiScanNotify: %d\n",__func__,pBtMgnt->ExtConfig.bEnableWifiScanNotify);
+	
+	//send complete event to BT
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_HCI_link_status_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+	struct bt_coex_info	*pcoex_info=&padapter->coex_info;
+	PBT_MGNT	pBtMgnt=&pcoex_info->BtMgnt;
+	//PBT_DBG		pBtDbg=&padapter->MgntInfo.BtInfo.BtDbg;
+	u8		i, numOfHandle=0, numOfAcl=0;
+	u16		conHandle;
+	u8		btProfile, btCoreSpec, linkRole;
+	u8		*pTriple;
+
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	
+	//pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++;
+	//RT_DISP_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", 
+	//		&pHciCmd->Data[0], pHciCmd->Length);
+
+	DBG_871X("BTLinkStatusNotify\n");
+
+	// Current only RTL8723 support this command.
+	//pBtMgnt->bSupportProfile = TRUE;
+	pBtMgnt->bSupportProfile = _FALSE;
+
+	pBtMgnt->ExtConfig.NumberOfACL = 0;
+	pBtMgnt->ExtConfig.NumberOfSCO = 0;
+	
+	numOfHandle = pcmd[0];
+	//RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("numOfHandle = 0x%x\n", numOfHandle));
+	//RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer));
+	DBG_871X("numOfHandle = 0x%x\n", numOfHandle);
+	DBG_871X("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer);
+	
+	pTriple = &pcmd[1];
+	for(i=0; i<numOfHandle; i++)
+	{	
+		if(pBtMgnt->ExtConfig.HCIExtensionVer < 1)
+		{
+			conHandle = *((u8 *)&pTriple[0]);
+			btProfile = pTriple[2];
+			btCoreSpec = pTriple[3];
+			if(BT_PROFILE_SCO == btProfile)
+			{
+				pBtMgnt->ExtConfig.NumberOfSCO++;
+			}
+			else
+			{
+				pBtMgnt->ExtConfig.NumberOfACL++;			
+				pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle;
+				pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile;
+				pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec;
+			}
+			//RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, 
+			//	("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n",
+			//		conHandle, btProfile, btCoreSpec));
+			DBG_871X("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", conHandle, btProfile, btCoreSpec);
+			pTriple += 4;
+		}
+		else if(pBtMgnt->ExtConfig.HCIExtensionVer >= 1)
+		{
+			conHandle = *((pu2Byte)&pTriple[0]);
+			btProfile = pTriple[2];
+			btCoreSpec = pTriple[3];
+			linkRole = pTriple[4];
+			if(BT_PROFILE_SCO == btProfile)
+			{
+				pBtMgnt->ExtConfig.NumberOfSCO++;
+			}
+			else
+			{
+				pBtMgnt->ExtConfig.NumberOfACL++;			
+				pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle;
+				pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile;
+				pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec;
+				pBtMgnt->ExtConfig.aclLink[i].linkRole = linkRole;
+			}
+			//RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, 
+			DBG_871X("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d, LinkRole=%d\n",
+				conHandle, btProfile, btCoreSpec, linkRole);
+			pTriple += 5;
+		}	
+	}
+	rtw_btcoex_StackUpdateProfileInfo();
+
+		//send complete event to BT
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+	
+	
+}
+
+u8 rtw_btcoex_parse_HCI_BT_coex_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_COEX_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_COEX_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_HCI_BT_operation_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	DBG_871X("%s, OP code: %d\n",__func__,pcmd[0]);
+
+	switch(pcmd[0])
+	{
+		case HCI_BT_OP_NONE:
+			DBG_871X("[bt operation] : Operation None!!\n");
+			break;
+		case HCI_BT_OP_INQUIRY_START:
+			DBG_871X("[bt operation] : Inquiry start!!\n");
+			break;
+		case HCI_BT_OP_INQUIRY_FINISH:
+			DBG_871X("[bt operation] : Inquiry finished!!\n");
+			break;
+		case HCI_BT_OP_PAGING_START:
+			DBG_871X("[bt operation] : Paging is started!!\n");
+			break;
+		case HCI_BT_OP_PAGING_SUCCESS:
+			DBG_871X("[bt operation] : Paging complete successfully!!\n");
+			break;
+		case HCI_BT_OP_PAGING_UNSUCCESS:
+			DBG_871X("[bt operation] : Paging complete unsuccessfully!!\n");
+			break;
+		case HCI_BT_OP_PAIRING_START:
+			DBG_871X("[bt operation] : Pairing start!!\n");
+			break;
+		case HCI_BT_OP_PAIRING_FINISH:
+			DBG_871X("[bt operation] : Pairing finished!!\n");
+			break;
+		case HCI_BT_OP_BT_DEV_ENABLE:
+			DBG_871X("[bt operation] : BT Device is enabled!!\n");
+			break;
+		case HCI_BT_OP_BT_DEV_DISABLE:
+			DBG_871X("[bt operation] : BT Device is disabled!!\n");
+			break;
+		default:
+			DBG_871X("[bt operation] : Unknown, error!!\n");
+			break;
+	}
+
+			//send complete event to BT
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_BT_register_val_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+u8 rtw_btcoex_parse_HCI_query_RF_status_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen)
+{
+	u8 localBuf[6] = "";
+	u8 *pRetPar;
+	u8	len=0, tx_event_length =0;
+	rtw_HCI_event *pEvent;
+	RTW_HCI_STATUS	status=HCI_STATUS_SUCCESS;
+
+	{
+		pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+
+		pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+		pEvent->Data[0] = 0x1;	//packet #
+		pEvent->Data[1] = HCIOPCODELOW(HCI_QUERY_RF_STATUS, OGF_EXTENSION);
+		pEvent->Data[2] = HCIOPCODEHIGHT(HCI_QUERY_RF_STATUS, OGF_EXTENSION);
+		len = len + 3;
+
+		// Return parameters starts from here
+		pRetPar = &pEvent->Data[len];		
+		pRetPar[0] = status;		//status
+
+		len++;
+		pEvent->Length = len;
+
+		//total tx event length + EventCode length + sizeof(length)
+		tx_event_length = pEvent->Length + 2;
+
+		status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+		return status;
+		//bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2);
+	}
+}
+
+/*****************************************
+* HCI cmd format :
+*| 15 - 0						|	
+*| OPcode (OCF|OGF<<10)		|
+*| 15 - 8		|7 - 0			|
+*|Cmd para 	|Cmd para Length	|
+*|Cmd para......				|
+******************************************/
+
+//bit 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+//	 |	OCF			             |	   OGF       |
+void rtw_btcoex_parse_hci_extend_cmd(_adapter *padapter, u8 *pcmd, u16 len,const u16 hci_OCF)
+{
+
+	DBG_871X("%s: OCF: %x\n",__func__,hci_OCF);
+	switch(hci_OCF)
+	{
+		case HCI_EXTENSION_VERSION_NOTIFY:
+			DBG_871X("HCI_EXTENSION_VERSION_NOTIFY\n");
+			rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_LINK_STATUS_NOTIFY:
+			DBG_871X("HCI_LINK_STATUS_NOTIFY\n");
+			rtw_btcoex_parse_HCI_link_status_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_OPERATION_NOTIFY:
+			// only for 8723a 2ant
+			DBG_871X("HCI_BT_OPERATION_NOTIFY\n");
+			rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter,pcmd, len);
+			//
+			break;
+		case HCI_ENABLE_WIFI_SCAN_NOTIFY:
+			DBG_871X("HCI_ENABLE_WIFI_SCAN_NOTIFY\n");
+			rtw_btcoex_parse_WIFI_scan_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_QUERY_RF_STATUS:
+			// only for 8723b 2ant
+			DBG_871X("HCI_QUERY_RF_STATUS\n");
+			rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_ABNORMAL_NOTIFY:
+			DBG_871X("HCI_BT_ABNORMAL_NOTIFY\n");
+			rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_INFO_NOTIFY:
+			DBG_871X("HCI_BT_INFO_NOTIFY\n");
+			rtw_btcoex_parse_BT_info_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_COEX_NOTIFY:
+			DBG_871X("HCI_BT_COEX_NOTIFY\n");
+			rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_PATCH_VERSION_NOTIFY:
+			DBG_871X("HCI_BT_PATCH_VERSION_NOTIFY\n");
+			rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_AFH_MAP_NOTIFY:
+			DBG_871X("HCI_BT_AFH_MAP_NOTIFY\n");
+			rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter,pcmd, len);
+			break;
+		case HCI_BT_REGISTER_VALUE_NOTIFY:
+			DBG_871X("HCI_BT_REGISTER_VALUE_NOTIFY\n");
+			rtw_btcoex_parse_BT_register_val_notify_cmd(padapter,pcmd, len);
+			break;
+		default:
+			DBG_871X("ERROR!!! Unknown OCF: %x\n",hci_OCF);
+			break;
+			
+	}
+}
+
+void rtw_btcoex_parse_hci_cmd(_adapter *padapter, u8 *pcmd, u16 len)
+{
+	u16 opcode = pcmd[0] | pcmd[1]<<8;
+	u16 hci_OGF = HCI_OGF(opcode);
+	u16 hci_OCF = HCI_OCF(opcode);
+	u8 cmdlen = len -3;
+	u8 pare_len = pcmd[2];
+
+	DBG_871X("%s\n",__func__);
+	DBG_871X("OGF: %x,OCF: %x\n",hci_OGF,hci_OCF);
+	switch(hci_OGF)
+	{
+		case OGF_EXTENSION:
+			DBG_871X("HCI_EXTENSION_CMD_OGF\n");
+			rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF);
+			break;
+		default:
+			DBG_871X("Other OGF: %x\n",hci_OGF);
+			break;
+	}
+}
+
+u16 rtw_btcoex_parse_recv_data(u8 *msg, u8 msg_size)
+{
+	u8 cmp_msg1[32] = attend_ack;
+	u8 cmp_msg2[32] = leave_ack;
+	u8 cmp_msg3[32] = bt_leave;
+	u8 cmp_msg4[32] = invite_req;
+	u8 cmp_msg5[32] = attend_req;
+	u8 cmp_msg6[32] = invite_rsp;
+	u8 res = OTHER;
+	
+	if (_rtw_memcmp(cmp_msg1, msg, msg_size) == _TRUE) {
+		/*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+		res = RX_ATTEND_ACK;
+	} else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) {
+		/*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+		res = RX_LEAVE_ACK;
+	} else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) {
+		/*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+		res = RX_BT_LEAVE;
+	} else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) {
+		/*DBG_871X("%s, msg:%s\n",__func__,msg);*/
+		res = RX_INVITE_REQ;
+	} else if (_rtw_memcmp(cmp_msg5, msg, msg_size) == _TRUE) {
+		res = RX_ATTEND_REQ;
+	} else if (_rtw_memcmp(cmp_msg6, msg, msg_size) == _TRUE) {
+		res = RX_INVITE_RSP;
+	} else {
+		DBG_871X("%s, %s\n", __func__, msg);
+		res = OTHER;
+	}
+	
+	DBG_871X("%s, res:%d\n", __func__, res);
+	
+	return res;
+}
+
+void rtw_btcoex_recvmsgbysocket(void *data)
+{
+	u8 recv_data[255];
+	u8 tx_msg[255] = leave_ack;
+	u32 len = 0;
+	u16 recv_length = 0;
+	u16 parse_res = 0;
+#if 0
+	u8 para_len = 0, polling_enable = 0, poling_interval = 0, reason = 0, btinfo_len = 0;
+	u8 btinfo[BT_INFO_LEN] = {0};
+#endif
+
+	struct bt_coex_info *pcoex_info = NULL;
+	struct sock *sk = NULL;
+	struct sk_buff *skb = NULL;
+	
+	DBG_871X("%s\n",__func__);
+
+	if (pbtcoexadapter == NULL) {
+		DBG_871X("%s: btcoexadapter NULL!\n", __func__);
+		return;
+	}
+
+	pcoex_info = &pbtcoexadapter->coex_info;
+	sk = pcoex_info->sk_store;
+
+	if (sk == NULL) {
+		DBG_871X("%s: critical error when receive socket data!\n", __func__);
+		return;
+	}
+	
+	len = skb_queue_len(&sk->sk_receive_queue);
+	while (len > 0) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+
+		/*important: cut the udp header from skb->data! header length is 8 byte*/
+		recv_length = skb->len-8;
+		_rtw_memset(recv_data, 0, sizeof(recv_data));
+		_rtw_memcpy(recv_data, skb->data+8, recv_length);
+		
+		parse_res = rtw_btcoex_parse_recv_data(recv_data, recv_length);
+/*
+		if (RX_ATTEND_ACK == parse_res) {
+			//attend ack 
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+		} else if (RX_ATTEND_REQ == parse_res) {
+			//attend req from BT 
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE);
+		} else if (RX_INVITE_REQ == parse_res) {
+			//invite req from BT
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE);
+		} else if (RX_INVITE_RSP == parse_res) {
+			//invite rsp
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+		} else if (RX_LEAVE_ACK == parse_res) {
+			//mean BT know wifi  will leave
+			pcoex_info->BT_attend = _FALSE;
+			DBG_871X("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);			
+		} else if (RX_BT_LEAVE == parse_res) {
+			//BT leave
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); // no ack
+			pcoex_info->BT_attend = _FALSE;
+			DBG_871X("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);			
+		} else {
+			//todo: check if recv data are really hci cmds
+			if (_TRUE == pcoex_info->BT_attend)
+				rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length);
+		}
+*/
+		switch (parse_res) {
+		case RX_ATTEND_ACK:
+			/* attend ack */
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		case RX_ATTEND_REQ:
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE);
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		case RX_INVITE_REQ:
+			/* invite req from BT */
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE);
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		case RX_INVITE_RSP:
+			 /*invite rsp*/
+			pcoex_info->BT_attend = _TRUE;
+			DBG_871X("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		case RX_LEAVE_ACK:
+			/* mean BT know wifi  will leave */
+			pcoex_info->BT_attend = _FALSE;
+			DBG_871X("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		case RX_BT_LEAVE:
+			/* BT leave */
+			rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */
+			pcoex_info->BT_attend = _FALSE;
+			DBG_871X("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);	
+			rtw_btcoex_BTOffOnNotify(pbtcoexadapter, pcoex_info->BT_attend);
+			break;
+
+		default:
+			if (_TRUE == pcoex_info->BT_attend)
+				rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length);
+			else
+				DBG_871X("ERROR!! BT is UP\n");
+			break;
+
+		}
+		
+		len--;
+		kfree_skb(skb);
+	}
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0))
+void rtw_btcoex_recvmsg_init(struct sock *sk_in, s32 bytes)
+#else
+void rtw_btcoex_recvmsg_init(struct sock *sk_in)
+#endif
+{
+	struct bt_coex_info *pcoex_info = NULL;
+	
+	if (pbtcoexadapter == NULL) {
+		DBG_871X("%s: btcoexadapter NULL\n", __func__);
+		return;
+	}
+	pcoex_info = &pbtcoexadapter->coex_info;
+	pcoex_info->sk_store = sk_in;
+	if (pcoex_info->btcoex_wq != NULL)
+		queue_delayed_work(pcoex_info->btcoex_wq, &pcoex_info->recvmsg_work, 0);
+	else
+		DBG_871X("%s: BTCOEX workqueue NULL\n", __func__);
+}
+
+u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool force)
+{
+	u8 error; 
+	struct msghdr	udpmsg; 
+	mm_segment_t	oldfs; 
+	struct iovec	iov; 
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+
+	DBG_871X("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE");
+	if (_FALSE == force) {
+		if (_FALSE == pcoex_info->BT_attend) {
+			DBG_871X("TX Blocked: WiFi-BT disconnected\n");			
+			return _FAIL;
+		}
+	}
+		
+	iov.iov_base	 = (void *)msg; 
+	iov.iov_len	 = msg_size; 
+	udpmsg.msg_name	 = &pcoex_info->bt_sockaddr; 
+	udpmsg.msg_namelen	= sizeof(struct sockaddr_in); 
+	udpmsg.msg_iov	 = &iov; 
+	udpmsg.msg_iovlen	= 1; 
+	udpmsg.msg_control	= NULL; 
+	udpmsg.msg_controllen = 0; 
+	udpmsg.msg_flags	= MSG_DONTWAIT | MSG_NOSIGNAL; 
+	oldfs = get_fs(); 
+	set_fs(KERNEL_DS); 
+	error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); 
+	set_fs(oldfs); 
+	if (error < 0) {
+		DBG_871X("Error when sendimg msg, error:%d\n", error); 
+		return _FAIL;
+	} else
+		return _SUCCESS;
+}
+
+u8 rtw_btcoex_create_kernel_socket(_adapter *padapter)
+{
+	s8 kernel_socket_err; 
+	u8 tx_msg[255] = attend_req;
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	s32 sock_reuse = 1;
+	u8 status = _FAIL;
+	
+	DBG_871X("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT);
+
+	if (NULL == pcoex_info) {
+		DBG_871X("coex_info: NULL\n"); 
+		status =  _FAIL;
+	}
+	
+	kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); 
+    
+	if (kernel_socket_err < 0) { 
+		DBG_871X("Error during creation of socket error:%d\n", kernel_socket_err); 
+		status = _FAIL;	
+	} else {
+		_rtw_memset(&(pcoex_info->wifi_sockaddr), 0, sizeof(pcoex_info->wifi_sockaddr)); 
+		pcoex_info->wifi_sockaddr.sin_family = AF_INET; 
+		pcoex_info->wifi_sockaddr.sin_port = htons(CONNECT_PORT); 
+		pcoex_info->wifi_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+		_rtw_memset(&(pcoex_info->bt_sockaddr), 0, sizeof(pcoex_info->bt_sockaddr)); 
+		pcoex_info->bt_sockaddr.sin_family = AF_INET; 
+		pcoex_info->bt_sockaddr.sin_port = htons(CONNECT_PORT_BT); 
+		pcoex_info->bt_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+		pcoex_info->sk_store = NULL;
+		kernel_socket_err = pcoex_info->udpsock->ops->bind(pcoex_info->udpsock, (struct sockaddr *)&pcoex_info->wifi_sockaddr, 
+			sizeof(pcoex_info->wifi_sockaddr)); 
+		if (kernel_socket_err == 0) {	
+			DBG_871X("binding socket success\n"); 
+			pcoex_info->udpsock->sk->sk_data_ready = rtw_btcoex_recvmsg_init;
+			pcoex_info->sock_open |=  KERNEL_SOCKET_OK;
+			pcoex_info->BT_attend = _FALSE;
+			DBG_871X("WIFI sending attend_req\n"); 
+			rtw_btcoex_sendmsgbysocket(padapter, attend_req, sizeof(attend_req), _TRUE);
+			status = _SUCCESS;
+		} else { 
+			pcoex_info->BT_attend = _FALSE;
+			sock_release(pcoex_info->udpsock); /* bind fail release socket */
+			DBG_871X("Error binding socket: %d\n", kernel_socket_err); 
+			status = _FAIL;
+		} 
+			
+	}
+
+	return status;
+}
+
+void rtw_btcoex_close_kernel_socket(_adapter *padapter)
+{
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	if (pcoex_info->sock_open & KERNEL_SOCKET_OK) {
+		DBG_871X("release kernel socket\n");
+		sock_release(pcoex_info->udpsock);
+		pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK);	
+		if (_TRUE == pcoex_info->BT_attend)
+			pcoex_info->BT_attend = _FALSE;
+		
+		DBG_871X("sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend);
+	}
+}
+
+void rtw_btcoex_init_socket(_adapter *padapter)
+{
+		
+	u8 is_invite = _FALSE;
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	DBG_871X("%s\n", __func__);
+	if (_FALSE == pcoex_info->is_exist) {
+		_rtw_memset(pcoex_info,0,sizeof(struct bt_coex_info));
+		pcoex_info->btcoex_wq = create_workqueue("BTCOEX");
+		INIT_DELAYED_WORK(&pcoex_info->recvmsg_work,
+			  (void *)rtw_btcoex_recvmsgbysocket);
+		pbtcoexadapter = padapter;
+		/* We expect BT is off if BT don't send ack to wifi */
+		DBG_871X("We expect BT is off if BT send ack to wifi\n");
+		rtw_btcoex_BTOffOnNotify(pbtcoexadapter, _FALSE);
+		if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) {
+			pcoex_info->is_exist = _TRUE;
+		} else {
+			pcoex_info->is_exist = _FALSE;
+			pbtcoexadapter = NULL;
+		}
+		
+		DBG_871X("%s: pbtcoexadapter:%p, coex_info->is_exist: %s\n"
+			, __func__, pbtcoexadapter, pcoex_info->is_exist == _TRUE?"TRUE":"FALSE");
+	}
+}
+
+void rtw_btcoex_close_socket(_adapter *padapter)
+{
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+
+	DBG_871X("%s--coex_info->is_exist: %s, pcoex_info->BT_attend:%s\n"
+		, __func__, pcoex_info->is_exist == _TRUE?"TRUE":"FALSE", pcoex_info->BT_attend == _TRUE?"TRUE":"FALSE");
+	
+	if (_TRUE == pcoex_info->is_exist) {
+		if (_TRUE == pcoex_info->BT_attend) {
+			/*inform BT wifi leave*/
+			rtw_btcoex_sendmsgbysocket(padapter, wifi_leave, sizeof(wifi_leave), _FALSE);
+			msleep(50);
+		}
+		rtw_btcoex_close_kernel_socket(padapter);
+		pbtcoexadapter = NULL;
+		pcoex_info->is_exist = _FALSE;
+	}
+	if (pcoex_info->btcoex_wq != NULL) {
+		flush_workqueue(pcoex_info->btcoex_wq);
+		destroy_workqueue(pcoex_info->btcoex_wq);
+	}
+}
+
+void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name)
+{
+	u8 	i = 0;
+	DBG_871X("======> Msg name: %s\n", msg_name);
+	for(i=0;i<len;i++)
+	{
+		printk("%02x ", tx_msg[i]);
+	}
+	printk("\n");
+	DBG_871X("Msg name: %s <======\n", msg_name);
+}
+
+/* Porting from Windows team */
+void rtw_btcoex_SendEventExtBtCoexControl(PADAPTER padapter, u8 bNeedDbgRsp, u8 dataLen, void *pData)
+{
+	u8			len=0, tx_event_length = 0;
+	u8 			localBuf[32] = "";
+	u8			*pRetPar;
+	u8			opCode=0;
+	u8			*pInBuf=(pu1Byte)pData;
+	u8			*pOpCodeContent;
+	rtw_HCI_event *pEvent;
+
+	opCode = pInBuf[0];	
+
+	DBG_871X("%s, OPCode:%02x\n",__func__,opCode);
+
+	pEvent = (rtw_HCI_event*)(&localBuf[0]);
+
+	//len += bthci_ExtensionEventHeaderRtk(&localBuf[0], 
+	//	HCI_EVENT_EXT_BT_COEX_CONTROL);
+	pEvent->EventCode = HCI_EVENT_EXTENSION_RTK;
+	pEvent->Data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL;	//extension event code
+	len ++;
+	
+	// Return parameters starts from here
+	pRetPar = &pEvent->Data[len];
+	_rtw_memcpy(&pRetPar[0], pData, dataLen);
+
+	len += dataLen;
+
+	pEvent->Length = len;
+
+	//total tx event length + EventCode length + sizeof(length)
+	tx_event_length = pEvent->Length + 2;
+#if 0
+	rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT COEX CONTROL", _FALSE);
+#endif
+	rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+
+}
+
+/* Porting from Windows team */
+void rtw_btcoex_SendEventExtBtInfoControl(PADAPTER padapter, u8 dataLen, void *pData)
+{
+	rtw_HCI_event *pEvent;
+	u8			*pRetPar;
+	u8			len=0, tx_event_length = 0;
+	u8 			localBuf[32] = "";
+
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	PBT_MGNT		pBtMgnt = &pcoex_info->BtMgnt;
+	
+	DBG_871X("%s\n",__func__);
+	if(pBtMgnt->ExtConfig.HCIExtensionVer < 4) //not support
+	{
+		DBG_871X("ERROR: HCIExtensionVer = %d, HCIExtensionVer<4 !!!!\n",pBtMgnt->ExtConfig.HCIExtensionVer);
+		return;
+	}
+
+	pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+	//len += bthci_ExtensionEventHeaderRtk(&localBuf[0], 
+	//		HCI_EVENT_EXT_BT_INFO_CONTROL);
+	pEvent->EventCode = HCI_EVENT_EXTENSION_RTK;
+	pEvent->Data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL;		//extension event code
+	len ++;
+
+	// Return parameters starts from here
+	pRetPar = &pEvent->Data[len];
+	_rtw_memcpy(&pRetPar[0], pData, dataLen);
+
+	len += dataLen;
+
+	pEvent->Length = len;
+
+	//total tx event length + EventCode length + sizeof(length)
+	tx_event_length = pEvent->Length + 2;
+#if 0
+	rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT INFO CONTROL");
+#endif
+	rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+	
+}
+
+void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType)
+{
+	u8	len=0, tx_event_length=0;
+	u8 	localBuf[7] = "";
+	u8	*pRetPar;
+	u8	*pu1Temp;
+	rtw_HCI_event *pEvent;
+	struct bt_coex_info *pcoex_info = &padapter->coex_info;
+	PBT_MGNT		pBtMgnt = &pcoex_info->BtMgnt;
+
+//	if(!pBtMgnt->BtOperationOn)
+//		return;
+		
+	pEvent = (rtw_HCI_event *)(&localBuf[0]);
+
+//	len += bthci_ExtensionEventHeaderRtk(&localBuf[0], 
+//			HCI_EVENT_EXT_WIFI_SCAN_NOTIFY);
+
+	pEvent->EventCode = HCI_EVENT_EXTENSION_RTK;
+	pEvent->Data[0] = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY;		//extension event code
+	len ++;
+
+	// Return parameters starts from here
+	//pRetPar = &PPacketIrpEvent->Data[len];
+	//pu1Temp = (u8 *)&pRetPar[0];
+	//*pu1Temp = scanType;
+	pEvent->Data[len] = scanType;
+	len += 1;
+
+	pEvent->Length = len;
+
+	//total tx event length + EventCode length + sizeof(length)
+	tx_event_length = pEvent->Length + 2;
+#if 0
+	rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "WIFI SCAN OPERATION");
+#endif	
+	rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE);
+}
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX
+#endif // CONFIG_BT_COEXIST
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_cmd.c b/drivers/net/wireless/rtl8189es/core/rtw_cmd.c
new file mode 100644
index 000000000000..a240eb85bf29
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_cmd.c
@@ -0,0 +1,4133 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_CMD_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+sint	_rtw_init_cmd_priv (struct	cmd_priv *pcmdpriv)
+{
+	sint res=_SUCCESS;
+	
+_func_enter_;	
+
+	_rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0);
+	//_rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0);
+	_rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0);
+	
+	
+	_rtw_init_queue(&(pcmdpriv->cmd_queue));
+	
+	//allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf
+	
+	pcmdpriv->cmd_seq = 1;
+	
+	pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+	
+	if (pcmdpriv->cmd_allocated_buf == NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ - ( (SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1));
+		
+	pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4);
+	
+	if (pcmdpriv->rsp_allocated_buf == NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ( (SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3);
+
+	pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0;
+
+	_rtw_mutex_init(&pcmdpriv->sctx_mutex);
+exit:
+	
+_func_exit_;	  
+
+	return res;
+	
+}	
+
+#ifdef CONFIG_C2H_WK
+static void c2h_wk_callback(_workitem *work);
+#endif
+sint _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+	sint res=_SUCCESS;
+
+_func_enter_;	
+
+#ifdef CONFIG_H2CLBK
+	_rtw_init_sema(&(pevtpriv->lbkevt_done), 0);
+	pevtpriv->lbkevt_limit = 0;
+	pevtpriv->lbkevt_num = 0;
+	pevtpriv->cmdevt_parm = NULL;		
+#endif		
+	
+	//allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf
+	ATOMIC_SET(&pevtpriv->event_seq, 0);
+	pevtpriv->evt_done_cnt = 0;
+
+#ifdef CONFIG_EVENT_THREAD_MODE
+
+	_rtw_init_sema(&(pevtpriv->evt_notify), 0);
+	_rtw_init_sema(&(pevtpriv->terminate_evtthread_sema), 0);
+
+	pevtpriv->evt_allocated_buf = rtw_zmalloc(MAX_EVTSZ + 4);	
+	if (pevtpriv->evt_allocated_buf == NULL){
+		res= _FAIL;
+		goto exit;
+		}
+	pevtpriv->evt_buf = pevtpriv->evt_allocated_buf  +  4 - ((unsigned int)(pevtpriv->evt_allocated_buf) & 3);
+	
+		
+#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
+	pevtpriv->allocated_c2h_mem = rtw_zmalloc(C2H_MEM_SZ +4); 
+	
+	if (pevtpriv->allocated_c2h_mem == NULL){
+		res= _FAIL;
+		goto exit;
+	}
+
+	pevtpriv->c2h_mem = pevtpriv->allocated_c2h_mem +  4\
+	- ( (u32)(pevtpriv->allocated_c2h_mem) & 3);
+#ifdef PLATFORM_OS_XP
+	pevtpriv->pc2h_mdl= IoAllocateMdl((u8 *)pevtpriv->c2h_mem, C2H_MEM_SZ , FALSE, FALSE, NULL);
+	
+	if(pevtpriv->pc2h_mdl == NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	MmBuildMdlForNonPagedPool(pevtpriv->pc2h_mdl);
+#endif
+#endif //end of CONFIG_SDIO_HCI
+
+	_rtw_init_queue(&(pevtpriv->evt_queue));
+
+exit:	
+
+#endif //end of CONFIG_EVENT_THREAD_MODE
+
+#ifdef CONFIG_C2H_WK
+	_init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+	pevtpriv->c2h_wk_alive = _FALSE;
+	pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
+#endif
+
+_func_exit_;		 
+
+	return res;
+}
+
+void _rtw_free_evt_priv (struct	evt_priv *pevtpriv)
+{
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("+_rtw_free_evt_priv \n"));
+
+#ifdef CONFIG_EVENT_THREAD_MODE
+	_rtw_free_sema(&(pevtpriv->evt_notify));
+	_rtw_free_sema(&(pevtpriv->terminate_evtthread_sema));
+
+
+	if (pevtpriv->evt_allocated_buf)
+		rtw_mfree(pevtpriv->evt_allocated_buf, MAX_EVTSZ + 4);
+#endif
+
+#ifdef CONFIG_C2H_WK
+	_cancel_workitem_sync(&pevtpriv->c2h_wk);
+	while(pevtpriv->c2h_wk_alive)
+		rtw_msleep_os(10);
+
+	while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
+		void *c2h;
+		if ((c2h = rtw_cbuf_pop(pevtpriv->c2h_queue)) != NULL
+			&& c2h != (void *)pevtpriv) {
+			rtw_mfree(c2h, 16);
+		}
+	}
+	rtw_cbuf_free(pevtpriv->c2h_queue);
+#endif
+
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("-_rtw_free_evt_priv \n"));
+
+_func_exit_;	  	
+
+}
+
+void _rtw_free_cmd_priv (struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+
+	if(pcmdpriv){
+		_rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock));
+		_rtw_free_sema(&(pcmdpriv->cmd_queue_sema));
+		//_rtw_free_sema(&(pcmdpriv->cmd_done_sema));
+		_rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema));
+
+		if (pcmdpriv->cmd_allocated_buf)
+			rtw_mfree(pcmdpriv->cmd_allocated_buf, MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+		
+		if (pcmdpriv->rsp_allocated_buf)
+			rtw_mfree(pcmdpriv->rsp_allocated_buf, MAX_RSPSZ + 4);
+
+		_rtw_mutex_free(&pcmdpriv->sctx_mutex);
+	}
+_func_exit_;		
+}
+
+/*
+Calling Context:
+
+rtw_enqueue_cmd can only be called between kernel thread, 
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+
+*/
+#ifdef DBG_CMD_QUEUE
+extern u8 dump_cmd_id;
+#endif
+
+sint	_rtw_enqueue_cmd(_queue *queue, struct cmd_obj *obj)
+{
+	_irqL irqL;
+
+_func_enter_;
+
+	if (obj == NULL)
+		goto exit;
+
+	if(obj->cmdsz > MAX_CMDSZ ){
+		DBG_871X("%s failed due to obj->cmdsz(%d) > MAX_CMDSZ(%d) \n",__FUNCTION__, obj->cmdsz,MAX_CMDSZ);
+		goto exit;
+	}
+	//_enter_critical_bh(&queue->lock, &irqL);
+	_enter_critical(&queue->lock, &irqL);	
+
+	rtw_list_insert_tail(&obj->list, &queue->queue);
+
+	#ifdef DBG_CMD_QUEUE
+	if(dump_cmd_id){
+		printk("%s===> cmdcode:0x%02x\n",__FUNCTION__,obj->cmdcode);
+		if(obj->cmdcode == GEN_CMD_CODE(_Set_MLME_EVT)){
+			if(obj->parmbuf){
+				struct C2HEvent_Header *pc2h_evt_hdr = (struct C2HEvent_Header *)(obj->parmbuf);
+				printk("pc2h_evt_hdr->ID:0x%02x(%d)\n",pc2h_evt_hdr->ID,pc2h_evt_hdr->ID);
+			}
+		}
+		if(obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)){
+			if(obj->parmbuf){
+				struct drvextra_cmd_parm *pdrvextra_cmd_parm =(struct drvextra_cmd_parm*)(obj->parmbuf);
+				printk("pdrvextra_cmd_parm->ec_id:0x%02x\n",pdrvextra_cmd_parm->ec_id);
+			}
+		}
+	}	
+	
+	if (queue->queue.prev->next != &queue->queue)
+	{
+		DBG_871X("[%d] head %p, tail %p, tail->prev->next %p[tail], tail->next %p[head]\n", __LINE__,
+            &queue->queue, queue->queue.prev, queue->queue.prev->prev->next, queue->queue.prev->next);
+		
+		DBG_871X("==========%s============\n",__FUNCTION__);
+		DBG_871X("head:%p,obj_addr:%p\n",&queue->queue,obj);
+		DBG_871X("padapter: %p\n",obj->padapter);
+		DBG_871X("cmdcode: 0x%02x\n",obj->cmdcode);
+		DBG_871X("res: %d\n",obj->res);
+		DBG_871X("parmbuf: %p\n",obj->parmbuf);
+		DBG_871X("cmdsz: %d\n",obj->cmdsz);
+		DBG_871X("rsp: %p\n",obj->rsp);
+		DBG_871X("rspsz: %d\n",obj->rspsz);
+		DBG_871X("sctx: %p\n",obj->sctx);
+		DBG_871X("list->next: %p\n",obj->list.next);
+		DBG_871X("list->prev: %p\n",obj->list.prev);
+	}
+	#endif //DBG_CMD_QUEUE
+	
+	//_exit_critical_bh(&queue->lock, &irqL);	
+	_exit_critical(&queue->lock, &irqL);
+
+exit:	
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+struct	cmd_obj	*_rtw_dequeue_cmd(_queue *queue)
+{
+	_irqL irqL;
+	struct cmd_obj *obj;
+
+_func_enter_;
+
+	//_enter_critical_bh(&(queue->lock), &irqL);
+	_enter_critical(&queue->lock, &irqL);
+	
+	#ifdef DBG_CMD_QUEUE
+	if (queue->queue.prev->next != &queue->queue)
+	{
+   		 DBG_871X("[%d] head %p, tail %p, tail->prev->next %p[tail], tail->next %p[head]\n", __LINE__,
+            &queue->queue, queue->queue.prev, queue->queue.prev->prev->next, queue->queue.prev->next);
+	}
+	#endif //DBG_CMD_QUEUE
+
+
+	if (rtw_is_list_empty(&(queue->queue))){
+		obj = NULL;
+	}
+	else
+	{
+		obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list);
+
+		#ifdef DBG_CMD_QUEUE
+		if (queue->queue.prev->next != &queue->queue){
+				DBG_871X("==========%s============\n",__FUNCTION__);
+                          DBG_871X("head:%p,obj_addr:%p\n",&queue->queue,obj);
+				DBG_871X("padapter: %p\n",obj->padapter);
+				DBG_871X("cmdcode: 0x%02x\n",obj->cmdcode);
+				DBG_871X("res: %d\n",obj->res);
+				DBG_871X("parmbuf: %p\n",obj->parmbuf);
+				DBG_871X("cmdsz: %d\n",obj->cmdsz);
+				DBG_871X("rsp: %p\n",obj->rsp);
+				DBG_871X("rspsz: %d\n",obj->rspsz);
+				DBG_871X("sctx: %p\n",obj->sctx);                        	
+				DBG_871X("list->next: %p\n",obj->list.next);
+				DBG_871X("list->prev: %p\n",obj->list.prev);
+		}
+		
+		if(dump_cmd_id){
+			DBG_871X("%s===> cmdcode:0x%02x\n",__FUNCTION__,obj->cmdcode);
+		 	if(obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)){
+				if(obj->parmbuf){
+                                struct drvextra_cmd_parm *pdrvextra_cmd_parm =(struct drvextra_cmd_parm*)(obj->parmbuf);
+                                printk("pdrvextra_cmd_parm->ec_id:0x%02x\n",pdrvextra_cmd_parm->ec_id);
+                        }
+                	}
+
+		}	
+		#endif //DBG_CMD_QUEUE
+		
+		rtw_list_delete(&obj->list);
+	}
+
+	//_exit_critical_bh(&(queue->lock), &irqL);
+	_exit_critical(&queue->lock, &irqL);
+
+_func_exit_;	
+
+	return obj;
+}
+
+u32	rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+	u32	res;
+_func_enter_;	
+	res = _rtw_init_cmd_priv (pcmdpriv);
+_func_exit_;	
+	return res;	
+}
+
+u32	rtw_init_evt_priv (struct	evt_priv *pevtpriv)
+{
+	int	res;
+_func_enter_;		
+	res = _rtw_init_evt_priv(pevtpriv);
+_func_exit_;		
+	return res;
+}
+
+void rtw_free_evt_priv (struct	evt_priv *pevtpriv)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("rtw_free_evt_priv\n"));
+	_rtw_free_evt_priv(pevtpriv);
+_func_exit_;		
+}	
+
+void rtw_free_cmd_priv (struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("rtw_free_cmd_priv\n"));
+	_rtw_free_cmd_priv(pcmdpriv);
+_func_exit_;	
+}	
+
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj);
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+	u8 bAllow = _FALSE; //set to _TRUE to allow enqueuing cmd when hw_init_completed is _FALSE
+	
+	#ifdef SUPPORT_HW_RFOFF_DETECTED
+	//To decide allow or not
+	if( (adapter_to_pwrctl(pcmdpriv->padapter)->bHWPwrPindetect)
+		&&(!pcmdpriv->padapter->registrypriv.usbss_enable)
+	)		
+	{
+		if(cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra) ) 
+		{
+			struct drvextra_cmd_parm	*pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; 
+			if(pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
+			{	
+				//DBG_871X("==>enqueue POWER_SAVING_CTRL_WK_CID\n");
+				bAllow = _TRUE; 
+			}
+		}
+	}
+	#endif
+
+#ifndef CONFIG_C2H_PACKET_EN
+	/* C2H should be always allowed */
+	if(cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+		struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+		if(pdrvextra_cmd_parm->ec_id == C2H_WK_CID) {
+			bAllow = _TRUE;
+		}
+	}
+#endif
+
+	if(cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+		bAllow = _TRUE;
+
+	if ((!rtw_is_hw_init_completed(pcmdpriv->padapter) && (bAllow == _FALSE))
+		|| ATOMIC_READ(&(pcmdpriv->cmdthd_running)) == _FALSE	//com_thread not running
+	) {
+		/*DBG_871X("%s:%s: drop cmdcode:%u, hw_init_completed:%u, cmdthd_running:%u\n", caller_func, __FUNCTION__,
+			cmd_obj->cmdcode,
+			rtw_get_hw_init_completed(cmd_obj->padapter),
+			pcmdpriv->cmdthd_running
+		);*/
+
+		return _FAIL;
+	}	
+	return _SUCCESS;
+}
+
+
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+	int res = _FAIL;
+	PADAPTER padapter = pcmdpriv->padapter;
+	
+_func_enter_;	
+	
+	if (cmd_obj == NULL) {
+		goto exit;
+	}
+
+	cmd_obj->padapter = padapter;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	//change pcmdpriv to primary's pcmdpriv
+	if (padapter->adapter_type != PRIMARY_ADAPTER && padapter->pbuddy_adapter)
+		pcmdpriv = &(padapter->pbuddy_adapter->cmdpriv);
+#endif	
+
+	if( _FAIL == (res=rtw_cmd_filter(pcmdpriv, cmd_obj)) ) {
+		rtw_free_cmd_obj(cmd_obj);
+		goto exit;
+	}
+
+	res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
+
+	if(res == _SUCCESS)
+		_rtw_up_sema(&pcmdpriv->cmd_queue_sema);
+	
+exit:	
+	
+_func_exit_;
+
+	return res;
+}
+
+struct	cmd_obj	*rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+	struct cmd_obj *cmd_obj;
+	
+_func_enter_;		
+
+	cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
+		
+_func_exit_;			
+	return cmd_obj;
+}
+
+void rtw_cmd_clr_isr(struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+	pcmdpriv->cmd_done_cnt++;
+	//_rtw_up_sema(&(pcmdpriv->cmd_done_sema));
+_func_exit_;		
+}
+
+void rtw_free_cmd_obj(struct cmd_obj *pcmd)
+{
+	struct drvextra_cmd_parm *extra_parm = NULL;
+_func_enter_;
+
+	if (pcmd->parmbuf != NULL) {
+		/* free parmbuf in cmd_obj */
+		rtw_mfree((unsigned char *)pcmd->parmbuf, pcmd->cmdsz);
+	}
+	if(pcmd->rsp!=NULL)
+	{
+		if(pcmd->rspsz!= 0)
+		{
+			//free rsp in cmd_obj
+			rtw_mfree((unsigned char*)pcmd->rsp, pcmd->rspsz);
+		}	
+	}	
+
+	//free cmd_obj
+	rtw_mfree((unsigned char*)pcmd, sizeof(struct cmd_obj));
+	
+_func_exit_;		
+}
+
+
+void rtw_stop_cmd_thread(_adapter *adapter)
+{
+	if(adapter->cmdThread &&
+		ATOMIC_READ(&(adapter->cmdpriv.cmdthd_running)) == _TRUE &&
+		adapter->cmdpriv.stop_req == 0)
+	{
+		adapter->cmdpriv.stop_req = 1;
+		_rtw_up_sema(&adapter->cmdpriv.cmd_queue_sema);
+		_rtw_down_sema(&adapter->cmdpriv.terminate_cmdthread_sema);
+	}
+}
+
+thread_return rtw_cmd_thread(thread_context context)
+{
+	u8 ret;
+	struct cmd_obj *pcmd;
+	u8 *pcmdbuf, *prspbuf;
+	u32 cmd_start_time;
+	u32 cmd_process_time;
+	u8 (*cmd_hdl)(_adapter *padapter, u8* pbuf);
+	void (*pcmd_callback)(_adapter *dev, struct cmd_obj *pcmd);
+	PADAPTER padapter = (PADAPTER)context;
+	struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+	struct drvextra_cmd_parm *extra_parm = NULL;
+	_irqL irqL;
+_func_enter_;
+
+	thread_enter("RTW_CMD_THREAD");
+
+	pcmdbuf = pcmdpriv->cmd_buf;
+	prspbuf = pcmdpriv->rsp_buf;
+
+	pcmdpriv->stop_req = 0;
+	ATOMIC_SET(&(pcmdpriv->cmdthd_running), _TRUE);
+	_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("start r871x rtw_cmd_thread !!!!\n"));
+
+	while(1)
+	{
+		if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) {
+			DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" _rtw_down_sema(&pcmdpriv->cmd_queue_sema) return _FAIL, break\n", FUNC_ADPT_ARG(padapter));
+			break;
+		}
+
+		if (RTW_CANNOT_RUN(padapter)) {
+			DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n",
+				__func__
+				, rtw_is_drv_stopped(padapter)?"True":"False"
+				, rtw_is_surprise_removed(padapter)?"True":"False"
+				, __LINE__);
+			break;
+		}
+
+		if (pcmdpriv->stop_req) {
+			DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req);
+			break;
+		}
+		
+		_enter_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+		if(rtw_is_list_empty(&(pcmdpriv->cmd_queue.queue)))
+		{
+			//DBG_871X("%s: cmd queue is empty!\n", __func__);
+			_exit_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+			continue;
+		}
+		_exit_critical(&pcmdpriv->cmd_queue.lock, &irqL);
+
+#ifdef CONFIG_LPS_LCLK
+		if (rtw_register_cmd_alive(padapter) != _SUCCESS)
+		{
+			RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
+					 ("%s: wait to leave LPS_LCLK\n", __FUNCTION__));
+			continue;
+		}
+#endif
+
+_next:
+		if (RTW_CANNOT_RUN(padapter)) {
+			DBG_871X_LEVEL(_drv_always_, "%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n",
+				__func__
+				, rtw_is_drv_stopped(padapter)?"True":"False"
+				, rtw_is_surprise_removed(padapter)?"True":"False"
+				, __LINE__);
+			break;
+		}
+
+		if(!(pcmd = rtw_dequeue_cmd(pcmdpriv))) {
+#ifdef CONFIG_LPS_LCLK
+			rtw_unregister_cmd_alive(padapter);
+#endif
+			continue;
+		}
+
+		cmd_start_time = rtw_get_current_time();
+
+		if( _FAIL == rtw_cmd_filter(pcmdpriv, pcmd) )
+		{
+			pcmd->res = H2C_DROPPED;
+			if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+				extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
+				if (extra_parm && extra_parm->pbuf && extra_parm->size > 0)
+					rtw_mfree(extra_parm->pbuf, extra_parm->size);
+			}
+			goto post_process;
+		}
+
+		pcmdpriv->cmd_issued_cnt++;
+
+		if(pcmd->cmdsz > MAX_CMDSZ ){
+			DBG_871X("%s cmdsz:%d > MAX_CMDSZ:%d\n",__FUNCTION__,pcmd->cmdsz,MAX_CMDSZ);
+		}
+
+		_rtw_memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+		if(pcmd->cmdcode < (sizeof(wlancmds) /sizeof(struct cmd_hdl)))
+		{
+			cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+			if (cmd_hdl)
+			{
+				ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+				pcmd->res = ret;
+			}
+
+			pcmdpriv->cmd_seq++;
+		}
+		else
+		{
+			pcmd->res = H2C_PARAMETERS_ERROR;
+		}
+
+		cmd_hdl = NULL;
+
+post_process:
+
+		_enter_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+		if (pcmd->sctx) {
+			if (0)
+				DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pcmd->sctx\n",
+					FUNC_ADPT_ARG(pcmd->padapter));
+			if (pcmd->res == H2C_SUCCESS)
+				rtw_sctx_done(&pcmd->sctx);
+			else
+				rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR);
+		}
+		_exit_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL);
+
+
+		if((cmd_process_time = rtw_get_passing_time_ms(cmd_start_time)) > 1000)
+		{
+			if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+				struct drvextra_cmd_parm *drvextra_parm = (struct drvextra_cmd_parm *)pcmdbuf;
+				DBG_871X(ADPT_FMT" cmd=%d,%d,%d process_time=%d > 1 sec\n",
+					ADPT_ARG(pcmd->padapter), pcmd->cmdcode, drvextra_parm->ec_id, drvextra_parm->type, cmd_process_time);
+				//rtw_warn_on(1);
+			} else if(pcmd->cmdcode == GEN_CMD_CODE(_Set_MLME_EVT)){
+				struct C2HEvent_Header *pc2h_evt_hdr = (struct C2HEvent_Header *)pcmdbuf;
+				DBG_871X(ADPT_FMT" cmd=%d,%d, process_time=%d > 1 sec\n",
+					ADPT_ARG(pcmd->padapter), pcmd->cmdcode, pc2h_evt_hdr->ID, cmd_process_time);
+				//rtw_warn_on(1);
+			} else {
+				DBG_871X(ADPT_FMT" cmd=%d, process_time=%d > 1 sec\n",
+					ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time);
+				//rtw_warn_on(1);
+			}
+		}
+
+		//call callback function for post-processed
+		if(pcmd->cmdcode < (sizeof(rtw_cmd_callback) /sizeof(struct _cmd_callback)))
+		{
+			pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+			if(pcmd_callback == NULL)
+			{
+				RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("mlme_cmd_hdl(): pcmd_callback=0x%p, cmdcode=0x%x\n", pcmd_callback, pcmd->cmdcode));
+				rtw_free_cmd_obj(pcmd);
+			}
+			else
+			{
+				//todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!=NULL)
+				pcmd_callback(pcmd->padapter, pcmd);//need conider that free cmd_obj in rtw_cmd_callback
+			}
+		}
+		else
+		{
+			RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("%s: cmdcode=0x%x callback not defined!\n", __FUNCTION__, pcmd->cmdcode));
+			rtw_free_cmd_obj(pcmd);
+		}
+
+		flush_signals_thread();
+
+		goto _next;
+
+	}
+
+	// free all cmd_obj resources
+	do{
+		pcmd = rtw_dequeue_cmd(pcmdpriv);
+		if(pcmd==NULL){
+#ifdef CONFIG_LPS_LCLK
+			rtw_unregister_cmd_alive(padapter);
+#endif
+			break;
+		}
+		//DBG_871X("%s: leaving... drop cmdcode:%u size:%d\n", __FUNCTION__, pcmd->cmdcode, pcmd->cmdsz);
+
+		if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+			extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf;
+			if(extra_parm->pbuf && extra_parm->size > 0) {
+				rtw_mfree(extra_parm->pbuf, extra_parm->size);
+			}
+		}
+
+		rtw_free_cmd_obj(pcmd);	
+	}while(1);
+
+	_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+	ATOMIC_SET(&(pcmdpriv->cmdthd_running), _FALSE);
+
+_func_exit_;
+
+	thread_exit();
+
+}
+
+
+#ifdef CONFIG_EVENT_THREAD_MODE
+u32 rtw_enqueue_evt(struct evt_priv *pevtpriv, struct evt_obj *obj)
+{
+	_irqL irqL;
+	int	res;
+	_queue *queue = &pevtpriv->evt_queue;
+	
+_func_enter_;	
+
+	res = _SUCCESS; 		
+
+	if (obj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}	
+
+	_enter_critical_bh(&queue->lock, &irqL);
+
+	rtw_list_insert_tail(&obj->list, &queue->queue);
+	
+	_exit_critical_bh(&queue->lock, &irqL);
+
+	//rtw_evt_notify_isr(pevtpriv);
+
+exit:
+	
+_func_exit_;		
+
+	return res;	
+}
+
+struct evt_obj *rtw_dequeue_evt(_queue *queue)
+{
+	_irqL irqL;
+	struct	evt_obj	*pevtobj;
+	
+_func_enter_;		
+
+	_enter_critical_bh(&queue->lock, &irqL);
+
+	if (rtw_is_list_empty(&(queue->queue)))
+		pevtobj = NULL;
+	else
+	{
+		pevtobj = LIST_CONTAINOR(get_next(&(queue->queue)), struct evt_obj, list);
+		rtw_list_delete(&pevtobj->list);
+	}
+
+	_exit_critical_bh(&queue->lock, &irqL);
+	
+_func_exit_;			
+
+	return pevtobj;	
+}
+
+void rtw_free_evt_obj(struct evt_obj *pevtobj)
+{
+_func_enter_;
+
+	if(pevtobj->parmbuf)
+		rtw_mfree((unsigned char*)pevtobj->parmbuf, pevtobj->evtsz);
+	
+	rtw_mfree((unsigned char*)pevtobj, sizeof(struct evt_obj));
+	
+_func_exit_;		
+}
+
+void rtw_evt_notify_isr(struct evt_priv *pevtpriv)
+{
+_func_enter_;
+	pevtpriv->evt_done_cnt++;
+	_rtw_up_sema(&(pevtpriv->evt_notify));
+_func_exit_;	
+}
+#endif
+
+
+/*
+u8 rtw_setstandby_cmd(unsigned char  *adapter) 
+*/
+u8 rtw_setstandby_cmd(_adapter *padapter, uint action)
+{
+	struct cmd_obj*			ph2c;
+	struct usb_suspend_parm*	psetusbsuspend;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+
+	u8 ret = _SUCCESS;
+	
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		ret = _FAIL;
+		goto exit;
+	}
+	
+	psetusbsuspend = (struct usb_suspend_parm*)rtw_zmalloc(sizeof(struct usb_suspend_parm)); 
+	if (psetusbsuspend == NULL) {
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		ret = _FAIL;
+		goto exit;
+	}
+
+	psetusbsuspend->action = action;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend));
+
+	ret = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	
+exit:	
+	
+_func_exit_;		
+
+	return ret;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+	### NOTE:#### (!!!!)
+	MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(_adapter  *padapter, NDIS_802_11_SSID *ssid, int ssid_num,
+	struct rtw_ieee80211_channel *ch, int ch_num)
+{
+	u8 res = _FAIL;
+	struct cmd_obj		*ph2c;
+	struct sitesurvey_parm	*psurveyPara;
+	struct cmd_priv 	*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+#ifdef CONFIG_P2P
+	struct wifidirect_info *pwdinfo= &(padapter->wdinfo);
+#endif //CONFIG_P2P
+
+_func_enter_;
+
+#ifdef CONFIG_LPS
+	if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE){
+		rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
+	}
+#endif
+
+#ifdef CONFIG_P2P_PS
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
+		p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
+	}
+#endif //CONFIG_P2P_PS
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL)
+		return _FAIL;
+
+	psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm)); 
+	if (psurveyPara == NULL) {
+		rtw_mfree((unsigned char*) ph2c, sizeof(struct cmd_obj));
+		return _FAIL;
+	}
+
+	rtw_free_network_queue(padapter, _FALSE);
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __FUNCTION__));
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+
+	/* psurveyPara->bsslimit = 48; */
+	psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+	/* prepare ssid list */
+	if (ssid) {
+		int i;
+		for (i=0; i<ssid_num && i< RTW_SSID_SCAN_AMOUNT; i++) {
+			if (ssid[i].SsidLength) {
+				_rtw_memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(NDIS_802_11_SSID));
+				psurveyPara->ssid_num++;
+				if (0)
+					DBG_871X(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter),
+						psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength);
+			}
+		}
+	}
+
+	/* prepare channel list */
+	if (ch) {
+		int i;
+		for (i=0; i<ch_num && i< RTW_CHANNEL_SCAN_AMOUNT; i++) {
+			if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
+				_rtw_memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+				psurveyPara->ch_num++;
+				if (0)
+					DBG_871X(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter),
+						psurveyPara->ch[i].hw_value);
+			}
+		}
+	}
+
+	set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+	if(res == _SUCCESS) {
+
+		pmlmepriv->scan_start_time = rtw_get_current_time();
+
+#ifdef CONFIG_SCAN_BACKOP
+		if((padapter->pbuddy_adapter->mlmeextpriv.mlmext_info.state&0x03) == WIFI_FW_AP_STATE)
+		{
+			if(IsSupported5G(padapter->registrypriv.wireless_mode) 
+				&& IsSupported24G(padapter->registrypriv.wireless_mode)) //dual band
+				mlme_set_scan_to_timer(pmlmepriv, CONC_SCANNING_TIMEOUT_DUAL_BAND);
+			else //single band
+				mlme_set_scan_to_timer(pmlmepriv, CONC_SCANNING_TIMEOUT_SINGLE_BAND);
+		}		
+		else
+#endif /* CONFIG_SCAN_BACKOP */
+			mlme_set_scan_to_timer(pmlmepriv, SCANNING_TIMEOUT);
+
+		rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+	} else {
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+	}
+
+_func_exit_;		
+
+	return res;
+}
+
+u8 rtw_setdatarate_cmd(_adapter *padapter, u8 *rateset)
+{
+	struct cmd_obj*			ph2c;
+	struct setdatarate_parm*	pbsetdataratepara;
+	struct cmd_priv*		pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pbsetdataratepara = (struct setdatarate_parm*)rtw_zmalloc(sizeof(struct setdatarate_parm)); 
+	if (pbsetdataratepara == NULL) {
+		rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+#ifdef MP_FIRMWARE_OFFLOAD
+	pbsetdataratepara->curr_rateidx = *(u32*)rateset;
+//	_rtw_memcpy(pbsetdataratepara, rateset, sizeof(u32));
+#else
+	pbsetdataratepara->mac_id = 5;
+	_rtw_memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+#endif
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setbasicrate_cmd(_adapter *padapter, u8 *rateset)
+{
+	struct cmd_obj*			ph2c;
+	struct setbasicrate_parm*	pssetbasicratepara;
+	struct cmd_priv*		pcmdpriv=&padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res= _FAIL;
+		goto exit;
+	}
+	pssetbasicratepara = (struct setbasicrate_parm*)rtw_zmalloc(sizeof(struct setbasicrate_parm)); 
+
+	if (pssetbasicratepara == NULL) {
+		rtw_mfree((u8*) ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_);
+
+	_rtw_memcpy(pssetbasicratepara->basicrates, rateset, NumRates);	   
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:	
+
+_func_exit_;		
+
+	return res;
+}
+
+
+/*
+unsigned char rtw_setphy_cmd(unsigned char  *adapter) 
+
+1.  be called only after rtw_update_registrypriv_dev_network( ~) or mp testing program
+2.  for AdHoc/Ap mode or mp mode?
+
+*/
+u8 rtw_setphy_cmd(_adapter *padapter, u8 modem, u8 ch)
+{
+	struct cmd_obj*			ph2c;
+	struct setphy_parm*		psetphypara;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+//	struct mlme_priv			*pmlmepriv = &padapter->mlmepriv;
+//	struct registry_priv*		pregistry_priv = &padapter->registrypriv;
+	u8	res=_SUCCESS;
+
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+		}
+	psetphypara = (struct setphy_parm*)rtw_zmalloc(sizeof(struct setphy_parm)); 
+
+	if(psetphypara==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_);
+
+	RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("CH=%d, modem=%d", ch, modem));
+
+	psetphypara->modem = modem;
+	psetphypara->rfchannel = ch;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:	
+_func_exit_;		
+	return res;
+}
+
+u8 rtw_setbbreg_cmd(_adapter*padapter, u8 offset, u8 val)
+{	
+	struct cmd_obj*			ph2c;
+	struct writeBB_parm*		pwritebbparm;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;	
+	u8	res=_SUCCESS;
+_func_enter_;
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+		}
+	pwritebbparm = (struct writeBB_parm*)rtw_zmalloc(sizeof(struct writeBB_parm)); 
+
+	if(pwritebbparm==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg));	
+
+	pwritebbparm->offset = offset;
+	pwritebbparm->value = val;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:	
+_func_exit_;	
+	return res;
+}
+
+u8 rtw_getbbreg_cmd(_adapter  *padapter, u8 offset, u8 *pval)
+{	
+	struct cmd_obj*			ph2c;
+	struct readBB_parm*		prdbbparm;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+	
+_func_enter_;
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res=_FAIL;
+		goto exit;
+		}
+	prdbbparm = (struct readBB_parm*)rtw_zmalloc(sizeof(struct readBB_parm)); 
+
+	if(prdbbparm ==NULL){
+		rtw_mfree((unsigned char *) ph2c, sizeof(struct	cmd_obj));
+		return _FAIL;
+	}
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode =GEN_CMD_CODE(_GetBBReg);
+	ph2c->parmbuf = (unsigned char *)prdbbparm;
+	ph2c->cmdsz =  sizeof(struct readBB_parm);
+	ph2c->rsp = pval;
+	ph2c->rspsz = sizeof(struct readBB_rsp);
+	
+	prdbbparm ->offset = offset;
+	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:
+_func_exit_;	
+	return res;
+}
+
+u8 rtw_setrfreg_cmd(_adapter  *padapter, u8 offset, u32 val)
+{	
+	struct cmd_obj*			ph2c;
+	struct writeRF_parm*		pwriterfparm;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;	
+	u8	res=_SUCCESS;
+_func_enter_;
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;	
+		goto exit;
+	}
+	pwriterfparm = (struct writeRF_parm*)rtw_zmalloc(sizeof(struct writeRF_parm)); 
+
+	if(pwriterfparm==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));	
+
+	pwriterfparm->offset = offset;
+	pwriterfparm->value = val;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:
+_func_exit_;	
+	return res;
+}
+
+u8 rtw_getrfreg_cmd(_adapter  *padapter, u8 offset, u8 *pval)
+{	
+	struct cmd_obj*			ph2c;
+	struct readRF_parm*		prdrfparm;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;	
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+
+	prdrfparm = (struct readRF_parm*)rtw_zmalloc(sizeof(struct readRF_parm)); 
+	if(prdrfparm ==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode =GEN_CMD_CODE(_GetRFReg);
+	ph2c->parmbuf = (unsigned char *)prdrfparm;
+	ph2c->cmdsz =  sizeof(struct readRF_parm);
+	ph2c->rsp = pval;
+	ph2c->rspsz = sizeof(struct readRF_rsp);
+	
+	prdrfparm ->offset = offset;
+	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{       
+ _func_enter_;  
+		
+	//rtw_free_cmd_obj(pcmd);
+	rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz);
+	rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj));
+	
+#ifdef CONFIG_MP_INCLUDED
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted= _TRUE;
+#endif	
+_func_exit_;		
+}
+
+void rtw_readtssi_cmdrsp_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{
+ _func_enter_;  
+
+	rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz);
+	rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj));
+	
+#ifdef CONFIG_MP_INCLUDED
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted= _TRUE;
+#endif
+
+_func_exit_;
+}
+
+static u8 rtw_createbss_cmd(_adapter  *adapter, int flags, bool adhoc
+	, s16 req_ch, u8 req_bw, u8 req_offset)
+{
+	struct cmd_obj *cmdobj;
+	struct createbss_parm *parm;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct submit_ctx sctx;
+	u8 res = _SUCCESS;
+
+	/* prepare cmd parameter */
+	parm = (struct createbss_parm *)rtw_zmalloc(sizeof(*parm));
+	if (parm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	if (adhoc) {
+		/* for now, adhoc doesn't support ch,bw,offset request */
+		parm->adhoc = 1;
+	} else {
+		parm->adhoc = 0;
+		parm->req_ch = req_ch;
+		parm->req_bw = req_bw;
+		parm->req_offset = req_offset;
+	}
+
+	if (flags & RTW_CMDF_DIRECTLY) {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != createbss_hdl(adapter, (u8 *)parm))
+			res = _FAIL;
+		rtw_mfree((u8 *)parm, sizeof(*parm));
+	} else {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)parm, sizeof(*parm));
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_CreateBss));
+
+		if (flags & RTW_CMDF_WAIT_ACK) {
+			cmdobj->sctx = &sctx;
+			rtw_sctx_init(&sctx, 2000);
+		}
+
+		res = rtw_enqueue_cmd(pcmdpriv, cmdobj);
+
+		if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
+			rtw_sctx_wait(&sctx, __func__);
+			_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+			if (sctx.status == RTW_SCTX_SUBMITTED)
+				cmdobj->sctx = NULL;
+			_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
+		}
+	}
+
+exit:
+	return res;
+}
+
+inline u8 rtw_create_ibss_cmd(_adapter *adapter, int flags)
+{
+	return rtw_createbss_cmd(adapter, flags
+		, 1
+		, -1, 0, 0 /* for now, adhoc doesn't support ch,bw,offset request */
+	);
+}
+
+inline u8 rtw_startbss_cmd(_adapter *adapter, int flags)
+{
+	return rtw_createbss_cmd(adapter, flags
+		, 0
+		, -1, 0, 0 /* doesn't request ch, bw, offset */
+	);
+}
+
+inline u8 rtw_change_bss_chbw_cmd(_adapter *adapter, int flags, u8 req_ch, u8 req_bw, u8 req_offset)
+{
+	return rtw_createbss_cmd(adapter, flags
+		, 0
+		, req_ch, req_bw, req_offset
+	);
+}
+
+u8 rtw_joinbss_cmd(_adapter  *padapter, struct wlan_network* pnetwork)
+{
+	u8	*auth, res = _SUCCESS;
+	uint	t_len = 0;
+	WLAN_BSSID_EX		*psecnetwork;
+	struct cmd_obj		*pcmd;
+	struct cmd_priv		*pcmdpriv=&padapter->cmdpriv;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct qos_priv		*pqospriv= &pmlmepriv->qospriv;
+	struct security_priv	*psecuritypriv=&padapter->securitypriv;
+	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
+#ifdef CONFIG_80211N_HT
+	struct ht_priv			*phtpriv = &pmlmepriv->htpriv;
+#endif //CONFIG_80211N_HT
+#ifdef CONFIG_80211AC_VHT
+	struct vht_priv		*pvhtpriv = &pmlmepriv->vhtpriv;
+#endif //CONFIG_80211AC_VHT
+	NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u32 tmp_len;
+	u8 *ptmp=NULL;
+_func_enter_;
+
+	rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+	if (pmlmepriv->assoc_ssid.SsidLength == 0){
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
+	} else {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid=[%s]\n", pmlmepriv->assoc_ssid.Ssid));
+	}
+
+	pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(pcmd==NULL){
+		res=_FAIL;
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
+		goto exit;
+	}
+	/* // for IEs is pointer 
+	t_len = sizeof (ULONG) + sizeof (NDIS_802_11_MAC_ADDRESS) + 2 + 
+			sizeof (NDIS_802_11_SSID) + sizeof (ULONG) + 
+			sizeof (NDIS_802_11_RSSI) + sizeof (NDIS_802_11_NETWORK_TYPE) + 
+			sizeof (NDIS_802_11_CONFIGURATION) +	
+			sizeof (NDIS_802_11_NETWORK_INFRASTRUCTURE) +   
+			sizeof (NDIS_802_11_RATES_EX)+ sizeof(WLAN_PHY_INFO)+ sizeof (ULONG) + MAX_IE_SZ;
+	*/
+	//for IEs is fix buf size
+	t_len = sizeof(WLAN_BSSID_EX);
+
+
+	//for hidden ap to set fw_state here
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != _TRUE)
+	{
+		switch(ndis_network_mode)
+		{
+			case Ndis802_11IBSS:
+				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+				break;
+
+			case Ndis802_11Infrastructure:
+				set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+				break;
+
+			case Ndis802_11APMode:
+			case Ndis802_11AutoUnknown:
+			case Ndis802_11InfrastructureMax:
+			case Ndis802_11Monitor:
+				break;
+
+		}
+	}
+
+	pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+	/* 
+		Modified by Arvin 2015/05/13
+		Solution for allocating a new WLAN_BSSID_EX to avoid race condition issue between disconnect and joinbss 
+	*/
+	psecnetwork = (WLAN_BSSID_EX *)rtw_zmalloc(sizeof(WLAN_BSSID_EX));
+	if(psecnetwork==NULL)
+	{
+		if(pcmd !=NULL)
+			rtw_mfree((unsigned char *)pcmd, sizeof(struct	cmd_obj));
+		
+		res=_FAIL;
+		
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork==NULL!!!\n"));
+		
+		goto exit;
+	}
+
+	_rtw_memset(psecnetwork, 0, t_len);
+
+	_rtw_memcpy(psecnetwork, &pnetwork->network, get_WLAN_BSSID_EX_sz(&pnetwork->network));
+	
+	auth=&psecuritypriv->authenticator_ie[0];
+	psecuritypriv->authenticator_ie[0]=(unsigned char)psecnetwork->IELength;
+
+	if((psecnetwork->IELength-12) < (256-1)) {
+		_rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
+	} else {
+		_rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
+	}
+	  
+	psecnetwork->IELength = 0;
+	// Added by Albert 2009/02/18
+	// If the the driver wants to use the bssid to create the connection.
+	// If not,  we have to copy the connecting AP's MAC address to it so that
+	// the driver just has the bssid information for PMKIDList searching.
+        
+	if ( pmlmepriv->assoc_by_bssid == _FALSE )
+	{
+		_rtw_memcpy( &pmlmepriv->assoc_bssid[ 0 ], &pnetwork->network.MacAddress[ 0 ], ETH_ALEN );
+	}
+
+	psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
+
+
+	pqospriv->qos_option = 0;
+	
+	if(pregistrypriv->wmm_enable)	
+	{
+		tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);	
+
+		if (psecnetwork->IELength != tmp_len)		
+		{
+			psecnetwork->IELength = tmp_len;
+			pqospriv->qos_option = 1; //There is WMM IE in this corresp. beacon
+		}
+		else 
+		{
+			pqospriv->qos_option = 0;//There is no WMM IE in this corresp. beacon
+		}		
+	}	
+
+#ifdef CONFIG_80211N_HT
+	phtpriv->ht_option = _FALSE;
+	ptmp = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &tmp_len, pnetwork->network.IELength-12);
+	if(pregistrypriv->ht_enable && ptmp && tmp_len>0)
+	{
+		//	Added by Albert 2010/06/23
+		//	For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue.
+		//	Especially for Realtek 8192u SoftAP.
+		if (	( padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_ ) &&
+			( padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_ ) &&
+			( padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_ ))
+		{
+			rtw_ht_use_default_setting(padapter);
+
+			rtw_build_wmm_ie_ht(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength);
+
+			//rtw_restructure_ht_ie
+			rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[12], &psecnetwork->IEs[0], 
+									pnetwork->network.IELength-12, &psecnetwork->IELength,
+									pnetwork->network.Configuration.DSConfig);
+		}
+	}
+
+#ifdef CONFIG_80211AC_VHT
+	pvhtpriv->vht_option = _FALSE;
+	if (phtpriv->ht_option && pregistrypriv->vht_enable) {
+		rtw_restructure_vht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], 
+								pnetwork->network.IELength, &psecnetwork->IELength);
+	}
+#endif
+
+	rtw_append_exented_cap(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength);
+
+#endif //CONFIG_80211N_HT
+
+	#if 0
+	psecuritypriv->supplicant_ie[0]=(u8)psecnetwork->IELength;
+
+	if(psecnetwork->IELength < (256-1))
+	{
+		_rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], psecnetwork->IELength);
+	}
+	else
+	{
+		_rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], (256-1));
+	}
+	#endif
+	
+	pcmd->cmdsz = sizeof(WLAN_BSSID_EX);
+
+#ifdef CONFIG_RTL8712
+	//wlan_network endian conversion	
+	psecnetwork->Length = cpu_to_le32(psecnetwork->Length);
+	psecnetwork->Ssid.SsidLength= cpu_to_le32(psecnetwork->Ssid.SsidLength);
+	psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy);
+	psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi);
+	psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse);
+	psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow);
+	psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod);
+	psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig);
+	psecnetwork->Configuration.FHConfig.DwellTime=cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime);
+	psecnetwork->Configuration.FHConfig.HopPattern=cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern);
+	psecnetwork->Configuration.FHConfig.HopSet=cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet);
+	psecnetwork->Configuration.FHConfig.Length=cpu_to_le32(psecnetwork->Configuration.FHConfig.Length);	
+	psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length);
+	psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode);
+	psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength);      
+#endif
+
+	_rtw_init_listhead(&pcmd->list);
+	pcmd->cmdcode = _JoinBss_CMD_;//GEN_CMD_CODE(_JoinBss)
+	pcmd->parmbuf = (unsigned char *)psecnetwork;
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+	
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_disassoc_cmd(_adapter*padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
+{
+	struct cmd_obj *cmdobj = NULL;
+	struct disconnect_parm *param = NULL;
+	struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+	u8 res = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n"));
+
+	/* prepare cmd parameter */
+	param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param));
+	if (param == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	param->deauth_timeout_ms = deauth_timeout_ms;
+
+	if (enqueue) {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			rtw_mfree((u8 *)param, sizeof(*param));
+			goto exit;
+		}
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+		res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+	} else {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
+			res = _FAIL;
+		rtw_mfree((u8 *)param, sizeof(*param));
+	}
+
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_setopmode_cmd(_adapter  *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue)
+{
+	struct	cmd_obj*	ph2c;
+	struct	setopmode_parm* psetop;
+
+	struct	cmd_priv   *pcmdpriv= &padapter->cmdpriv;
+	u8	res=_SUCCESS;
+
+_func_enter_;
+	psetop = (struct setopmode_parm*)rtw_zmalloc(sizeof(struct setopmode_parm)); 
+
+	if(psetop==NULL){		
+		res=_FAIL;
+		goto exit;
+	}
+	psetop->mode = (u8)networktype;
+	
+	if(enqueue){
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));			
+		if(ph2c==NULL){		
+			rtw_mfree((u8 *)psetop, sizeof(*psetop));
+			res= _FAIL;
+			goto exit;
+		}	
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+	else{
+		setopmode_hdl(padapter, (u8 *)psetop);
+		rtw_mfree((u8 *)psetop, sizeof(*psetop));
+	}
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_setstakey_cmd(_adapter *padapter, struct sta_info *sta, u8 key_type, bool enqueue)
+{
+	struct cmd_obj*			ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+	struct set_stakey_rsp		*psetstakey_rsp = NULL;
+	
+	struct mlme_priv			*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv 		*psecuritypriv = &padapter->securitypriv;
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if(psetstakey_para==NULL){	
+		res=_FAIL;
+		goto exit;
+	}
+		
+	_rtw_memcpy(psetstakey_para->addr, sta->hwaddr,ETH_ALEN);
+		
+	if(check_fwstate(pmlmepriv, WIFI_STATION_STATE)){
+			psetstakey_para->algorithm =(unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
+	}else{
+		GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, _FALSE);
+	}
+
+	if (key_type == GROUP_KEY) {
+		_rtw_memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+	}
+	else if (key_type == UNICAST_KEY) {
+		_rtw_memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+	}
+#ifdef CONFIG_TDLS
+	else if(key_type == TDLS_KEY){
+			_rtw_memcpy(&psetstakey_para->key, sta->tpk.tk, 16);
+		psetstakey_para->algorithm=(u8)sta->dot118021XPrivacy;
+       }
+#endif /* CONFIG_TDLS */
+
+	//jeff: set this becasue at least sw key is ready
+	padapter->securitypriv.busetkipkey=_TRUE;
+
+	if(enqueue)
+	{
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+		if ( ph2c == NULL){
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			res= _FAIL;
+			goto exit;
+		}	
+
+		psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); 
+		if(psetstakey_rsp == NULL){
+			rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj));
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			res=_FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+		ph2c->rsp = (u8 *) psetstakey_rsp;
+		ph2c->rspsz = sizeof(struct set_stakey_rsp);
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	}
+	else{
+		set_stakey_hdl(padapter, (u8 *)psetstakey_para);
+		rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+	}
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_clearstakey_cmd(_adapter *padapter, struct sta_info *sta, u8 enqueue)
+{
+	struct cmd_obj*			ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+	struct set_stakey_rsp		*psetstakey_rsp = NULL;	
+	struct mlme_priv			*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv 		*psecuritypriv = &padapter->securitypriv;
+	s16 cam_id = 0;
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	if(!enqueue)
+	{
+		while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1, -1)) >= 0) {
+			DBG_871X_LEVEL(_drv_always_, "clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(sta->hwaddr), cam_id);
+			clear_cam_entry(padapter, cam_id);
+			rtw_camid_free(padapter, cam_id);
+		}
+	}
+	else
+	{
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+		if ( ph2c == NULL){
+			res= _FAIL;
+			goto exit;
+		}
+
+		psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm));
+		if(psetstakey_para==NULL){
+			rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+			res=_FAIL;
+			goto exit;
+		}
+
+		psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); 
+		if(psetstakey_rsp == NULL){
+			rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+			rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm));
+			res=_FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+		ph2c->rsp = (u8 *) psetstakey_rsp;
+		ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+		_rtw_memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+		psetstakey_para->algorithm = _NO_PRIVACY_;
+	
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+		
+	}
+	
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_setrttbl_cmd(_adapter  *padapter, struct setratable_parm *prate_table)
+{
+	struct cmd_obj*			ph2c;
+	struct setratable_parm *	psetrttblparm;	
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+		}
+	psetrttblparm = (struct setratable_parm*)rtw_zmalloc(sizeof(struct setratable_parm)); 
+
+	if(psetrttblparm==NULL){
+		rtw_mfree((unsigned char *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+	_rtw_memcpy(psetrttblparm,prate_table,sizeof(struct setratable_parm));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:
+_func_exit_;	
+	return res;
+
+}
+
+u8 rtw_getrttbl_cmd(_adapter  *padapter, struct getratable_rsp *pval)
+{
+	struct cmd_obj*			ph2c;
+	struct getratable_parm *	pgetrttblparm;	
+	struct cmd_priv 			*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	pgetrttblparm = (struct getratable_parm*)rtw_zmalloc(sizeof(struct getratable_parm)); 
+
+	if(pgetrttblparm==NULL){
+		rtw_mfree((unsigned char *) ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+//	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode =GEN_CMD_CODE(_GetRaTable);
+	ph2c->parmbuf = (unsigned char *)pgetrttblparm;
+	ph2c->cmdsz =  sizeof(struct getratable_parm);
+	ph2c->rsp = (u8*)pval;
+	ph2c->rspsz = sizeof(struct getratable_rsp);
+	
+	pgetrttblparm ->rsvd = 0x0;
+	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+exit:
+_func_exit_;	
+	return res;
+
+}
+
+u8 rtw_setassocsta_cmd(_adapter  *padapter, u8 *mac_addr)
+{
+	struct cmd_priv 		*pcmdpriv = &padapter->cmdpriv;
+	struct cmd_obj*			ph2c;
+	struct set_assocsta_parm	*psetassocsta_para;	
+	struct set_stakey_rsp		*psetassocsta_rsp = NULL;
+
+	u8	res=_SUCCESS;
+
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+
+	psetassocsta_para = (struct set_assocsta_parm*)rtw_zmalloc(sizeof(struct set_assocsta_parm));
+	if(psetassocsta_para==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		res=_FAIL;
+		goto exit;
+	}
+
+	psetassocsta_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_assocsta_rsp)); 
+	if(psetassocsta_rsp==NULL){
+		rtw_mfree((u8 *) ph2c, sizeof(struct	cmd_obj));
+		rtw_mfree((u8 *) psetassocsta_para, sizeof(struct set_assocsta_parm));
+		return _FAIL;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
+	ph2c->rsp = (u8 *) psetassocsta_rsp;
+	ph2c->rspsz = sizeof(struct set_assocsta_rsp);
+
+	_rtw_memcpy(psetassocsta_para->addr, mac_addr,ETH_ALEN);
+	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);	
+
+exit:
+
+_func_exit_;	
+
+	return res;
+ }
+
+u8 rtw_addbareq_cmd(_adapter*padapter, u8 tid, u8 *addr)
+{
+	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
+	struct cmd_obj*		ph2c;
+	struct addBaReq_parm	*paddbareq_parm;
+
+	u8	res=_SUCCESS;
+	
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	paddbareq_parm = (struct addBaReq_parm*)rtw_zmalloc(sizeof(struct addBaReq_parm)); 
+	if(paddbareq_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct	cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	paddbareq_parm->tid = tid;
+	_rtw_memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+	//DBG_871X("rtw_addbareq_cmd, tid=%d\n", tid);
+
+	//rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+}
+//add for CONFIG_IEEE80211W, none 11w can use it
+u8 rtw_reset_securitypriv_cmd(_adapter*padapter)
+{
+	struct cmd_obj*		ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+	
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	
+	//rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+
+u8 rtw_free_assoc_resources_cmd(_adapter*padapter)
+{
+	struct cmd_obj*		ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+	
+_func_enter_;	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	
+	//rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+
+u8 rtw_dynamic_chk_wk_cmd(_adapter*padapter)
+{
+	struct cmd_obj*		ph2c;
+	struct drvextra_cmd_parm  *pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv=&padapter->cmdpriv;
+	u8	res=_SUCCESS;
+	
+_func_enter_;	
+
+	//only  primary padapter does this cmd
+/*
+#ifdef CONFIG_CONCURRENT_MODE
+	if (padapter->adapter_type != PRIMARY_ADAPTER && padapter->pbuddy_adapter)
+		pcmdpriv = &(padapter->pbuddy_adapter->cmdpriv);
+#endif
+*/
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+	
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	
+	//rtw_enqueue_cmd(pcmdpriv, ph2c);	
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+
+u8 rtw_set_ch_cmd(_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue)
+{
+	struct cmd_obj *pcmdobj;
+	struct set_ch_parm *set_ch_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	u8 res=_SUCCESS;
+
+_func_enter_;
+
+	DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+	/* check input parameter */
+
+	/* prepare cmd parameter */
+	set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm));
+	if (set_ch_parm == NULL) {
+		res= _FAIL;
+		goto exit;
+	}
+	set_ch_parm->ch = ch;
+	set_ch_parm->bw = bw;
+	set_ch_parm->ch_offset = ch_offset;
+
+	if (enqueue) {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if(pcmdobj == NULL){
+			rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm));
+			res=_FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel));
+		res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	} else {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if( H2C_SUCCESS !=set_ch_hdl(padapter, (u8 *)set_ch_parm) )
+			res = _FAIL;
+		
+		rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm));
+	}
+
+	/* do something based on res... */
+
+exit:
+
+	DBG_871X(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_set_chplan_cmd(_adapter*padapter, u8 chplan, u8 enqueue, u8 swconfig)
+{
+	struct	cmd_obj*	pcmdobj;
+	struct	SetChannelPlan_param *setChannelPlan_param;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n"));
+
+	// check if allow software config
+	if (swconfig && rtw_hal_is_disable_sw_channel_plan(padapter) == _TRUE)
+	{
+		res = _FAIL;
+		goto exit;
+	}
+
+	//check input parameter
+	if(!rtw_is_channel_plan_valid(chplan)) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	//prepare cmd parameter
+	setChannelPlan_param = (struct	SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param));
+	if(setChannelPlan_param == NULL) {
+		res= _FAIL;
+		goto exit;
+	}
+	setChannelPlan_param->channel_plan=chplan;
+
+	if(enqueue)
+	{
+		//need enqueue, prepare cmd_obj and enqueue
+		pcmdobj = (struct	cmd_obj*)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if(pcmdobj == NULL){
+			rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param));
+			res=_FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
+		res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	}
+	else
+	{
+		//no need to enqueue, do the cmd hdl directly and free cmd parameter
+		if( H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param) )
+			res = _FAIL;
+		
+		rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param));
+	}
+	
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_led_blink_cmd(_adapter*padapter, PVOID pLed)
+{
+	struct	cmd_obj*	pcmdobj;
+	struct	LedBlink_param *ledBlink_param;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n"));
+	
+	pcmdobj = (struct	cmd_obj*)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if(pcmdobj == NULL){
+		res=_FAIL;
+		goto exit;
+	}
+
+	ledBlink_param = (struct	LedBlink_param *)rtw_zmalloc(sizeof(struct	LedBlink_param));
+	if(ledBlink_param == NULL) {
+		rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	ledBlink_param->pLed=pLed;
+	
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_set_csa_cmd(_adapter*padapter, u8 new_ch_no)
+{
+	struct	cmd_obj*	pcmdobj;
+	struct	SetChannelSwitch_param*setChannelSwitch_param;
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n"));
+	
+	pcmdobj = (struct	cmd_obj*)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if(pcmdobj == NULL){
+		res=_FAIL;
+		goto exit;
+	}
+
+	setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct	SetChannelSwitch_param));
+	if(setChannelSwitch_param == NULL) {
+		rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	setChannelSwitch_param->new_ch_no=new_ch_no;
+	
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	
+exit:
+
+_func_exit_;	
+
+	return res;
+}
+
+u8 rtw_tdls_cmd(_adapter *padapter, u8 *addr, u8 option)
+{
+	struct	cmd_obj*	pcmdobj;
+	struct	TDLSoption_param	*TDLSoption;
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res=_SUCCESS;
+
+_func_enter_;
+
+#ifdef CONFIG_TDLS
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_tdls_cmd\n"));
+
+	pcmdobj = (struct	cmd_obj*)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if(pcmdobj == NULL){
+		res=_FAIL;
+		goto exit;
+	}
+
+	TDLSoption= (struct TDLSoption_param *)rtw_zmalloc(sizeof(struct TDLSoption_param));
+	if(TDLSoption == NULL) {
+		rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	_rtw_spinlock(&(padapter->tdlsinfo.cmd_lock));
+	if (addr != NULL)
+		_rtw_memcpy(TDLSoption->addr, addr, 6);
+	TDLSoption->option = option;
+	_rtw_spinunlock(&(padapter->tdlsinfo.cmd_lock));
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, TDLSoption, GEN_CMD_CODE(_TDLS));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+#endif	//CONFIG_TDLS
+	
+exit:
+
+
+_func_exit_;	
+
+	return res;
+}
+
+static void collect_traffic_statistics(_adapter *padapter)
+{
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(padapter);
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if (padapter->adapter_type != PRIMARY_ADAPTER)
+		return;
+#endif
+
+	// Tx
+	pdvobjpriv->traffic_stat.tx_bytes = padapter->xmitpriv.tx_bytes;
+	pdvobjpriv->traffic_stat.tx_pkts = padapter->xmitpriv.tx_pkts;
+	pdvobjpriv->traffic_stat.tx_drop = padapter->xmitpriv.tx_drop;
+
+	// Rx
+	pdvobjpriv->traffic_stat.rx_bytes = padapter->recvpriv.rx_bytes;
+	pdvobjpriv->traffic_stat.rx_pkts = padapter->recvpriv.rx_pkts;
+	pdvobjpriv->traffic_stat.rx_drop = padapter->recvpriv.rx_drop;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	// Add secondary adapter statistics
+	if(rtw_buddy_adapter_up(padapter))
+	{
+		// Tx
+		pdvobjpriv->traffic_stat.tx_bytes += padapter->pbuddy_adapter->xmitpriv.tx_bytes;
+		pdvobjpriv->traffic_stat.tx_pkts += padapter->pbuddy_adapter->xmitpriv.tx_pkts;
+		pdvobjpriv->traffic_stat.tx_drop += padapter->pbuddy_adapter->xmitpriv.tx_drop;
+
+		// Rx
+		pdvobjpriv->traffic_stat.rx_bytes += padapter->pbuddy_adapter->recvpriv.rx_bytes;
+		pdvobjpriv->traffic_stat.rx_pkts += padapter->pbuddy_adapter->recvpriv.rx_pkts;
+		pdvobjpriv->traffic_stat.rx_drop += padapter->pbuddy_adapter->recvpriv.rx_drop;
+	}
+#endif
+
+	// Calculate throughput in last interval
+	pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes;
+	pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes;
+	pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes;
+	pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes;
+
+	pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes *8/2/1024/1024);
+	pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes *8/2/1024/1024);
+}
+
+//from_timer == 1 means driver is in LPS
+u8 traffic_status_watchdog(_adapter *padapter, u8 from_timer)
+{
+	u8	bEnterPS = _FALSE;
+#ifdef CONFIG_BT_COEXIST
+	u16	BusyThresholdHigh = 25;
+	u16	BusyThresholdLow = 10;
+#else
+	u16	BusyThresholdHigh = 100;
+	u16	BusyThresholdLow = 75;
+#endif
+	u16	BusyThreshold = BusyThresholdHigh;
+	u8	bBusyTraffic = _FALSE, bTxBusyTraffic = _FALSE, bRxBusyTraffic = _FALSE;
+	u8	bHigherBusyTraffic = _FALSE, bHigherBusyRxTraffic = _FALSE, bHigherBusyTxTraffic = _FALSE;
+
+	struct mlme_priv		*pmlmepriv = &(padapter->mlmepriv);
+#ifdef CONFIG_TDLS
+	struct tdls_info *ptdlsinfo = &(padapter->tdlsinfo);
+	struct tdls_txmgmt txmgmt;
+	u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#endif //CONFIG_TDLS
+
+	RT_LINK_DETECT_T * link_detect = &pmlmepriv->LinkDetectInfo;
+
+	collect_traffic_statistics(padapter);
+
+	//
+	// Determine if our traffic is busy now
+	//
+	if((check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) 
+		/*&& !MgntInitAdapterInProgress(pMgntInfo)*/)
+	{
+		// if we raise bBusyTraffic in last watchdog, using lower threshold.
+		if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
+				BusyThreshold = BusyThresholdLow;
+
+		if( pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold ||
+			pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold )
+		{
+			bBusyTraffic = _TRUE;
+
+			if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+				bRxBusyTraffic = _TRUE;
+			else
+				bTxBusyTraffic = _TRUE;
+		}
+
+		// Higher Tx/Rx data.
+		if( pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+			pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000 )
+		{
+			bHigherBusyTraffic = _TRUE;
+
+			if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+				bHigherBusyRxTraffic = _TRUE;
+			else
+				bHigherBusyTxTraffic = _TRUE;
+		}
+
+#ifdef CONFIG_TRAFFIC_PROTECT
+#define TX_ACTIVE_TH 10
+#define RX_ACTIVE_TH 20
+#define TRAFFIC_PROTECT_PERIOD_MS 4500
+
+	if (link_detect->NumTxOkInPeriod > TX_ACTIVE_TH
+		|| link_detect->NumRxUnicastOkInPeriod > RX_ACTIVE_TH) {
+		
+		DBG_871X_LEVEL(_drv_info_, FUNC_ADPT_FMT" acqiure wake_lock for %u ms(tx:%d,rx_unicast:%d)\n",
+			FUNC_ADPT_ARG(padapter),
+			TRAFFIC_PROTECT_PERIOD_MS,
+			link_detect->NumTxOkInPeriod,
+			link_detect->NumRxUnicastOkInPeriod);
+
+		rtw_lock_traffic_suspend_timeout(TRAFFIC_PROTECT_PERIOD_MS);
+	}
+#endif
+		
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_AUTOSETUP
+		/* TDLS_WATCHDOG_PERIOD * 2sec, periodically send */
+		if ((ptdlsinfo->watchdog_count % TDLS_WATCHDOG_PERIOD ) == 0) {
+			_rtw_memcpy(txmgmt.peer, baddr, ETH_ALEN);
+			issue_tdls_dis_req( padapter, &txmgmt );
+		}
+		ptdlsinfo->watchdog_count++;
+#endif //CONFIG_TDLS_AUTOSETUP
+#endif //CONFIG_TDLS
+
+#ifdef CONFIG_LPS
+		// check traffic for  powersaving.
+		if( ((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8 ) ||
+#ifdef CONFIG_LPS_SLOW_TRANSITION			
+			(pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2) 
+#else //CONFIG_LPS_SLOW_TRANSITION
+			(pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4) 
+#endif //CONFIG_LPS_SLOW_TRANSITION
+			)
+		{
+#ifdef DBG_RX_COUNTER_DUMP
+			if( padapter->dump_rx_cnt_mode & DUMP_DRV_TRX_COUNTER_DATA)
+				DBG_871X("(-)Tx = %d, Rx = %d \n",pmlmepriv->LinkDetectInfo.NumTxOkInPeriod,pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod);
+#endif	
+			bEnterPS= _FALSE;
+#ifdef CONFIG_LPS_SLOW_TRANSITION
+			if(bBusyTraffic == _TRUE)
+			{
+				if(pmlmepriv->LinkDetectInfo.TrafficTransitionCount <= 4)
+					pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 4;
+
+				pmlmepriv->LinkDetectInfo.TrafficTransitionCount++;
+
+				//DBG_871X("Set TrafficTransitionCount to %d\n", pmlmepriv->LinkDetectInfo.TrafficTransitionCount);
+			
+				if(pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/)
+				{
+					pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30;
+				}	
+			}
+#endif //CONFIG_LPS_SLOW_TRANSITION
+	
+		}
+		else
+		{
+#ifdef DBG_RX_COUNTER_DUMP		
+			if( padapter->dump_rx_cnt_mode & DUMP_DRV_TRX_COUNTER_DATA)
+				DBG_871X("(+)Tx = %d, Rx = %d \n",pmlmepriv->LinkDetectInfo.NumTxOkInPeriod,pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod);
+#endif			
+#ifdef CONFIG_LPS_SLOW_TRANSITION
+			if(pmlmepriv->LinkDetectInfo.TrafficTransitionCount>=2)
+				pmlmepriv->LinkDetectInfo.TrafficTransitionCount -=2;
+			else
+				pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
+
+			if(pmlmepriv->LinkDetectInfo.TrafficTransitionCount == 0)
+				bEnterPS= _TRUE;
+#else //CONFIG_LPS_SLOW_TRANSITION
+				bEnterPS= _TRUE;
+#endif //CONFIG_LPS_SLOW_TRANSITION
+		}
+
+#ifdef CONFIG_DYNAMIC_DTIM
+		if(pmlmepriv->LinkDetectInfo.LowPowerTransitionCount == 8)
+			bEnterPS= _FALSE;
+
+		DBG_871X("LowPowerTransitionCount=%d\n", pmlmepriv->LinkDetectInfo.LowPowerTransitionCount);
+#endif //CONFIG_DYNAMIC_DTIM
+
+		// LeisurePS only work in infra mode.
+		if(bEnterPS)
+		{
+			if(!from_timer)
+			{
+#ifdef CONFIG_DYNAMIC_DTIM
+				if(pmlmepriv->LinkDetectInfo.LowPowerTransitionCount < 8)
+				{					
+					adapter_to_pwrctl(padapter)->dtim = 1;
+				}	
+				else
+				{					
+					adapter_to_pwrctl(padapter)->dtim = 3;
+				}
+#endif //CONFIG_DYNAMIC_DTIM
+				LPS_Enter(padapter, "TRAFFIC_IDLE");
+			}	
+			else
+			{
+				//do this at caller
+				//rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 1);
+				//rtw_hal_dm_watchdog_in_lps(padapter);
+			}				
+#ifdef CONFIG_DYNAMIC_DTIM
+			if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode ==_TRUE )
+				pmlmepriv->LinkDetectInfo.LowPowerTransitionCount++;
+#endif //CONFIG_DYNAMIC_DTIM
+		}
+		else
+		{
+#ifdef CONFIG_DYNAMIC_DTIM
+			if(pmlmepriv->LinkDetectInfo.LowPowerTransitionCount != 8)
+				pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
+			else
+				pmlmepriv->LinkDetectInfo.LowPowerTransitionCount++;
+#endif //CONFIG_DYNAMIC_DTIM			
+			if(!from_timer)
+			{
+				LPS_Leave(padapter, "TRAFFIC_BUSY");
+			}
+			else
+			{
+#ifdef CONFIG_CONCURRENT_MODE
+			 	if(padapter->iface_type == IFACE_PORT0) 
+#endif
+					rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1);
+			}
+		}
+	
+#endif // CONFIG_LPS
+	}
+	else
+	{
+#ifdef CONFIG_LPS
+		struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+		int n_assoc_iface = 0;
+		int i;
+
+		for (i = 0; i < dvobj->iface_nums; i++) {
+			if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE))
+				n_assoc_iface++;
+		}
+
+		if(!from_timer && n_assoc_iface == 0)
+			LPS_Leave(padapter, "NON_LINKED");
+#endif
+	}
+
+	pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+
+	return bEnterPS;
+	
+}
+
+void dynamic_chk_wk_hdl(_adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv;
+	pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+#ifdef CONFIG_AP_MODE
+	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
+	{			
+		expire_timeout_chk(padapter);
+	}
+#endif
+#endif //CONFIG_ACTIVE_KEEP_ALIVE_CHECK
+
+#ifdef DBG_CONFIG_ERROR_DETECT	
+	rtw_hal_sreset_xmit_status_check(padapter);		
+	rtw_hal_sreset_linked_status_check(padapter);
+#endif	
+
+	//for debug purpose
+	_linked_info_dump(padapter);
+
+
+	//if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)==_FALSE)
+	{
+		linked_status_chk(padapter, 0);
+		traffic_status_watchdog(padapter, 0);
+		#ifdef DBG_RX_COUNTER_DUMP
+		rtw_dump_rx_counters(padapter);
+		#endif
+		dm_DynamicUsbTxAgg(padapter, 0);
+	}
+
+#ifdef CONFIG_BEAMFORMING
+	beamforming_watchdog(padapter);
+#endif
+
+	rtw_hal_dm_watchdog(padapter);
+
+	//check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type);
+
+#ifdef CONFIG_BT_COEXIST
+	//
+	// BT-Coexist
+	//
+	rtw_btcoex_Handler(padapter);
+#endif
+
+	
+#ifdef CONFIG_IPS_CHECK_IN_WD
+	//always call rtw_ps_processor() at last one.
+	if (is_primary_adapter(padapter))
+		rtw_ps_processor(padapter);
+#endif
+}
+
+#ifdef CONFIG_LPS
+
+void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type);
+void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type)
+{
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8	mstatus;
+	
+_func_enter_;
+
+	if((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)
+		|| (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE))
+	{
+		return;
+	}
+
+	switch(lps_ctrl_type)
+	{
+		case LPS_CTRL_SCAN:
+			//DBG_871X("LPS_CTRL_SCAN \n");
+#ifdef CONFIG_BT_COEXIST
+			rtw_btcoex_ScanNotify(padapter, _TRUE);
+#endif // CONFIG_BT_COEXIST
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
+			{
+				// connect
+				LPS_Leave(padapter, "LPS_CTRL_SCAN");
+			}
+			break;
+		case LPS_CTRL_JOINBSS:
+			//DBG_871X("LPS_CTRL_JOINBSS \n");
+			LPS_Leave(padapter, "LPS_CTRL_JOINBSS");
+			break;
+		case LPS_CTRL_CONNECT:
+			//DBG_871X("LPS_CTRL_CONNECT \n");
+			mstatus = 1;//connect
+			// Reset LPS Setting
+			pwrpriv->LpsIdleCount = 0;
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+#ifdef CONFIG_BT_COEXIST
+			rtw_btcoex_MediaStatusNotify(padapter, mstatus);
+#endif // CONFIG_BT_COEXIST
+			break;
+		case LPS_CTRL_DISCONNECT:
+			//DBG_871X("LPS_CTRL_DISCONNECT \n");
+			mstatus = 0;//disconnect
+#ifdef CONFIG_BT_COEXIST
+			rtw_btcoex_MediaStatusNotify(padapter, mstatus);
+#endif // CONFIG_BT_COEXIST
+			LPS_Leave(padapter, "LPS_CTRL_DISCONNECT");
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+			break;
+		case LPS_CTRL_SPECIAL_PACKET:
+			//DBG_871X("LPS_CTRL_SPECIAL_PACKET \n");
+			pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time();
+#ifdef CONFIG_BT_COEXIST
+			rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP);
+#endif // CONFIG_BT_COEXIST
+			LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET");
+			break;
+		case LPS_CTRL_LEAVE:
+			//DBG_871X("LPS_CTRL_LEAVE \n");
+			LPS_Leave(padapter, "LPS_CTRL_LEAVE");
+			break;
+		case LPS_CTRL_TRAFFIC_BUSY:
+			LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY");
+			break;
+		case LPS_CTRL_TX_TRAFFIC_LEAVE:
+			LPS_Leave(padapter, "LPS_CTRL_TX_TRAFFIC_LEAVE");
+			break;
+		case LPS_CTRL_RX_TRAFFIC_LEAVE:
+			LPS_Leave(padapter, "LPS_CTRL_RX_TRAFFIC_LEAVE");
+			break;
+		case LPS_CTRL_ENTER:
+			LPS_Enter(padapter, "TRAFFIC_IDLE_1");
+			break;
+		default:
+			break;
+	}
+
+_func_exit_;
+}
+
+u8 rtw_lps_ctrl_wk_cmd(_adapter*padapter, u8 lps_ctrl_type, u8 enqueue)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	//struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+	u8	res = _SUCCESS;
+	
+_func_enter_;
+
+	//if(!pwrctrlpriv->bLeisurePs)
+	//	return res;
+
+	if(enqueue)
+	{
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+		if(ph2c==NULL){
+			res= _FAIL;
+			goto exit;
+		}
+		
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+		if(pdrvextra_cmd_parm==NULL){
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res= _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+		pdrvextra_cmd_parm->type = lps_ctrl_type;
+		pdrvextra_cmd_parm->size = 0;
+		pdrvextra_cmd_parm->pbuf = NULL;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+	else
+	{
+		lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+	}
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+
+void rtw_dm_in_lps_hdl(_adapter*padapter)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL);
+}
+
+u8 rtw_dm_in_lps_wk_cmd(_adapter*padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+		
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DM_IN_LPS_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+	return res;
+
+}
+
+void rtw_lps_change_dtim_hdl(_adapter *padapter, u8 dtim)
+{
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+
+	if(dtim <=0 || dtim > 16)
+		return;
+
+#ifdef CONFIG_BT_COEXIST
+	if (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)
+		return;
+#endif
+
+#ifdef CONFIG_LPS_LCLK
+	_enter_pwrlock(&pwrpriv->lock);
+#endif
+
+	if(pwrpriv->dtim!=dtim)
+	{
+		DBG_871X("change DTIM from %d to %d, bFwCurrentInPSMode=%d, ps_mode=%d\n", pwrpriv->dtim, dtim, 
+			pwrpriv->bFwCurrentInPSMode, pwrpriv->pwr_mode);
+		
+		pwrpriv->dtim = dtim;
+	}	
+
+	if((pwrpriv->bFwCurrentInPSMode ==_TRUE) && (pwrpriv->pwr_mode > PS_MODE_ACTIVE))		 
+	{
+		u8 ps_mode = pwrpriv->pwr_mode;
+
+		//DBG_871X("change DTIM from %d to %d, ps_mode=%d\n", pwrpriv->dtim, dtim, ps_mode);
+	
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+	}
+	
+#ifdef CONFIG_LPS_LCLK
+	_exit_pwrlock(&pwrpriv->lock);
+#endif
+
+}
+
+#endif
+
+u8 rtw_lps_change_dtim_cmd(_adapter*padapter, u8 dtim)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+/*
+#ifdef CONFIG_CONCURRENT_MODE
+	if (padapter->iface_type != IFACE_PORT0)
+		return res;
+#endif
+*/
+	{
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+		if(ph2c==NULL){
+			res= _FAIL;
+			goto exit;
+		}
+		
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+		if(pdrvextra_cmd_parm==NULL){
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res= _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = LPS_CHANGE_DTIM_CID;
+		pdrvextra_cmd_parm->type = dtim;
+		pdrvextra_cmd_parm->size = 0;
+		pdrvextra_cmd_parm->pbuf = NULL;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+	
+exit:
+	
+	return res;
+
+}
+
+#if (RATE_ADAPTIVE_SUPPORT==1)
+void rpt_timer_setting_wk_hdl(_adapter *padapter, u16 minRptTime)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&minRptTime));
+}
+
+u8 rtw_rpt_timer_cfg_cmd(_adapter*padapter, u16 minRptTime)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
+	pdrvextra_cmd_parm->type = minRptTime;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+
+}
+
+#endif
+
+#ifdef CONFIG_ANTENNA_DIVERSITY
+void antenna_select_wk_hdl(_adapter *padapter, u8 antenna)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
+}
+
+u8 rtw_antenna_select_cmd(_adapter*padapter, u8 antenna,u8 enqueue)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8 	bSupportAntDiv = _FALSE;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv));
+	if(_FALSE == bSupportAntDiv )	return res;
+
+	if(_TRUE == enqueue)
+	{
+		ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+		if(ph2c==NULL){
+			res= _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+		if(pdrvextra_cmd_parm==NULL){
+			rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+			res= _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
+		pdrvextra_cmd_parm->type = antenna;
+		pdrvextra_cmd_parm->size = 0;
+		pdrvextra_cmd_parm->pbuf = NULL;
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+	else{
+		antenna_select_wk_hdl(padapter,antenna );
+	}
+exit:
+
+_func_exit_;
+
+	return res;
+
+}
+#endif
+
+void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta)
+{
+	if (psta) {
+		set_sta_rate(padapter, psta);
+	}
+}
+
+u8 rtw_dm_ra_mask_wk_cmd(_adapter*padapter, u8 *psta)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+		
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = psta;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+	return res;
+
+}
+
+void power_saving_wk_hdl(_adapter *padapter)
+{
+	 rtw_ps_processor(padapter);
+}
+
+//add for CONFIG_IEEE80211W, none 11w can use it
+void reset_securitypriv_hdl(_adapter *padapter)
+{
+	 rtw_reset_securitypriv(padapter);
+}
+
+void free_assoc_resources_hdl(_adapter *padapter)
+{
+	 rtw_free_assoc_resources(padapter, 1);
+}
+
+#ifdef CONFIG_P2P
+u8 p2p_protocol_wk_cmd(_adapter*padapter, int intCmdType )
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct wifidirect_info	*pwdinfo= &(padapter->wdinfo);
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	
+_func_enter_;
+
+	if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+	{
+		return res;
+	}
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+			
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+	pdrvextra_cmd_parm->type = intCmdType;	//	As the command tppe.
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;		//	Must be NULL here
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+#endif //CONFIG_P2P
+
+u8 rtw_ps_cmd(_adapter*padapter)
+{
+	struct cmd_obj		*ppscmd;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	
+	u8	res = _SUCCESS;
+_func_enter_;
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if (padapter->adapter_type != PRIMARY_ADAPTER)
+		goto exit;
+#endif
+	
+	ppscmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ppscmd==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+		
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ppscmd, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
+	
+exit:
+	
+_func_exit_;
+
+	return res;
+
+}
+
+#ifdef CONFIG_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(_adapter *padapter)
+{
+	struct sta_info *psta_bmc;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u32 start = rtw_get_current_time();
+	u8 empty = _FALSE;
+
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if(!psta_bmc)
+		return;
+
+	rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+
+	while(_FALSE == empty && rtw_get_passing_time_ms(start) < rtw_get_wait_hiq_empty_ms())
+	{
+		rtw_msleep_os(100);
+		rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty);
+	}
+
+	if(psta_bmc->sleepq_len==0)
+	{
+		if(empty == _SUCCESS)
+		{
+			bool update_tim = _FALSE;
+
+			if (pstapriv->tim_bitmap & BIT(0))
+				update_tim = _TRUE;
+
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			if (update_tim == _TRUE)
+				_update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty");
+		}
+		else //re check again
+		{
+			rtw_chk_hi_queue_cmd(padapter);
+		}
+		
+	}	
+	
+}
+
+u8 rtw_chk_hi_queue_cmd(_adapter*padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;	
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+	
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));	
+	if(ph2c==NULL){
+		res= _FAIL;
+		goto exit;
+	}
+			
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+	if(pdrvextra_cmd_parm==NULL){
+		rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj));
+		res= _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+	return res;
+
+}
+
+#ifdef CONFIG_DFS_MASTER
+u8 rtw_dfs_master_hdl(_adapter *adapter)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+
+	if (!rfctl->dfs_master_enabled)
+		goto exit;
+
+	if (rtw_get_on_cur_ch_time(adapter) == 0
+		|| rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) < 300
+	) {
+		/* offchannel , by pass radar detect */
+		goto cac_status_chk;
+	}
+
+	if (rfctl->dbg_dfs_master_fake_radar_detect_cnt
+		|| rtw_odm_radar_detect(adapter) == _TRUE
+	) {
+		if (rfctl->dbg_dfs_master_fake_radar_detect_cnt != 0) {
+			DBG_871X(FUNC_ADPT_FMT" fake radar detect, cnt:%d\n", FUNC_ADPT_ARG(adapter)
+				, rfctl->dbg_dfs_master_fake_radar_detect_cnt);
+			rfctl->dbg_dfs_master_fake_radar_detect_cnt--;
+		}
+	
+		if (rfctl->dbg_dfs_master_radar_detect_trigger_non) {
+			/* radar detect debug mode, trigger no mlme flow */
+			DBG_871X(FUNC_ADPT_FMT" radar detected, trigger no mlme flow for debug\n", FUNC_ADPT_ARG(adapter));
+		} else {
+			/* TODO: move timer to rfctl */
+			struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+			int i;
+
+			for (i = 0; i < dvobj->iface_nums; i++) {
+				if (!dvobj->padapters[i])
+					continue;
+				if (check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_AP_STATE)
+					&& check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_AP_STATE))
+					break;
+			}
+
+			if (i >= dvobj->iface_nums) {
+				/* what? */
+				rtw_warn_on(1);
+			} else {
+				rtw_chset_update_non_ocp(dvobj->padapters[i]->mlmeextpriv.channel_set
+					, rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset);
+
+				/* change op ch, inform ch switch */
+				rtw_change_bss_chbw_cmd(dvobj->padapters[i], RTW_CMDF_DIRECTLY, 0, 0, 0);
+			}
+
+			if (rfctl->dfs_master_enabled)
+				goto set_timer;
+			goto exit;
+		}
+	}
+
+cac_status_chk:
+
+	if (!IS_UNDER_CAC(rfctl) && !IS_CAC_STOPPED(rfctl)) {
+		u8 pause = 0x00;
+
+		rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause);
+		rfctl->cac_end_time = RTW_CAC_STOPPED;
+	}
+
+set_timer:
+	_set_timer(&mlme->dfs_master_timer, DFS_MASTER_TIMER_MS);
+
+exit:
+	return H2C_SUCCESS;
+}
+
+u8 rtw_dfs_master_cmd(_adapter *adapter, bool enqueue)
+{
+	struct cmd_obj *cmdobj;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	u8 res = _FAIL;
+
+	if (enqueue) {
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));	
+		if (cmdobj == NULL)
+			goto exit;
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); 
+		if (pdrvextra_cmd_parm == NULL) {
+			rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj));
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = DFS_MASTER_WK_CID;
+		pdrvextra_cmd_parm->type = 0;
+		pdrvextra_cmd_parm->size = 0;
+		pdrvextra_cmd_parm->pbuf = NULL;
+
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+		res = rtw_enqueue_cmd(pcmdpriv, cmdobj);
+	} else {
+		rtw_dfs_master_hdl(adapter);
+		res = _SUCCESS;
+	}
+
+exit:
+	return res;
+}
+
+void rtw_dfs_master_timer_hdl(RTW_TIMER_HDL_ARGS)
+{
+	_adapter *adapter = (_adapter *)FunctionContext;
+
+	rtw_dfs_master_cmd(adapter, _TRUE);
+}
+
+void rtw_dfs_master_enable(_adapter *adapter, u8 ch, u8 bw, u8 offset)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+
+	/* TODO: move timer to rfctl */
+	adapter = GET_PRIMARY_ADAPTER(adapter);
+
+	DBG_871X(FUNC_ADPT_FMT" on %u,%u,%u\n", FUNC_ADPT_ARG(adapter), ch, bw, offset);
+
+	rfctl->pre_radar_detect_by_sta_link = rfctl->radar_detect_by_sta_link;
+	rfctl->radar_detect_by_sta_link = _FALSE;
+
+	rfctl->pre_radar_detect_ch = rfctl->radar_detect_ch;
+	rfctl->pre_radar_detect_bw = rfctl->radar_detect_bw;
+	rfctl->pre_radar_detect_offset = rfctl->radar_detect_offset;
+	rfctl->radar_detect_ch = ch;
+	rfctl->radar_detect_bw = bw;
+	rfctl->radar_detect_offset = offset;
+
+	if (rtw_is_cac_reset_needed(adapter) == _TRUE)
+		rtw_rfctl_reset_cac(adapter_to_rfctl(adapter));
+
+	if (!rfctl->dfs_master_enabled) {
+		DBG_871X(FUNC_ADPT_FMT" set dfs_master_enabled\n", FUNC_ADPT_ARG(adapter));
+		rfctl->dfs_master_enabled = 1;
+		_set_timer(&adapter->mlmepriv.dfs_master_timer, DFS_MASTER_TIMER_MS);
+
+		if (rtw_rfctl_overlap_radar_detect_ch(rfctl)) {
+			if (IS_UNDER_CAC(rfctl)) {
+				u8 pause = 0xFF;
+
+				rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause);
+			}
+			rtw_odm_radar_detect_enable(adapter);
+		}
+	}
+}
+
+void rtw_dfs_master_disable(_adapter *adapter, bool ld_sta_in_dfs)
+{
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	
+	/* TODO: move timer to rfctl */
+	adapter = GET_PRIMARY_ADAPTER(adapter);
+
+	rfctl->pre_radar_detect_by_sta_link = rfctl->radar_detect_by_sta_link;
+	rfctl->radar_detect_by_sta_link = ld_sta_in_dfs;
+
+	if (rfctl->dfs_master_enabled) {
+		bool overlap_radar_detect_ch = rtw_rfctl_overlap_radar_detect_ch(rfctl);
+
+		DBG_871X(FUNC_ADPT_FMT" clear dfs_master_enabled\n", FUNC_ADPT_ARG(adapter));
+
+		rfctl->dfs_master_enabled = 0;
+		rfctl->radar_detect_ch = rfctl->pre_radar_detect_ch = 0;
+		rfctl->radar_detect_bw = rfctl->pre_radar_detect_bw = 0;
+		rfctl->radar_detect_offset = rfctl->pre_radar_detect_offset = 0;
+		rfctl->cac_end_time = RTW_CAC_STOPPED;
+		_cancel_timer_ex(&adapter->mlmepriv.dfs_master_timer);
+
+		if (overlap_radar_detect_ch) {
+			u8 pause = 0x00;
+
+			rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause);
+			rtw_odm_radar_detect_disable(adapter);
+		}
+	}
+}
+
+void rtw_dfs_master_status_apply(_adapter *adapter, u8 self_action)
+{
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	u8 ld_sta_num, lg_sta_num, ap_num;
+	u8 u_ch, u_bw, u_offset;
+	bool ld_sta_in_dfs = _FALSE;
+	bool sync_ch = _FALSE; /* _FALSE: asign channel directly */
+	bool needed = _FALSE;
+
+	rtw_dev_iface_status_no_self(adapter, NULL, &ld_sta_num, &lg_sta_num, &ap_num, NULL);
+	rtw_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset);
+	if (u_ch != 0)
+		sync_ch = _TRUE;
+
+	switch (self_action) {
+	case MLME_STA_CONNECTING:
+		lg_sta_num++;
+		break;
+	case MLME_STA_CONNECTED:
+		ld_sta_num++;
+		break;
+	case MLME_AP_STARTED:
+		ap_num++;
+		break;
+	case MLME_AP_STOPPED:
+	case MLME_STA_DISCONNECTED:
+	default:
+		break;
+	}
+
+	if (sync_ch == _TRUE) {
+		if (!rtw_is_chbw_grouped(mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset, u_ch, u_bw, u_offset)) {
+			DBG_871X(FUNC_ADPT_FMT" can't sync %u,%u,%u with %u,%u,%u\n", FUNC_ADPT_ARG(adapter)
+				, mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset, u_ch, u_bw, u_offset);
+			goto apply;
+		}
+
+		rtw_sync_chbw(&mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset
+			, &u_ch, &u_bw, &u_offset);
+	} else {
+		u_ch = mlmeext->cur_channel;
+		u_bw = mlmeext->cur_bwmode;
+		u_offset = mlmeext->cur_ch_offset;
+	}
+
+	if (ld_sta_num > 0) {
+		/* rely on AP on which STA mode connects */
+		if (rtw_is_dfs_ch(u_ch, u_bw, u_offset))
+			ld_sta_in_dfs = _TRUE;
+		goto apply;
+	}
+
+	if (lg_sta_num > 0) {
+		/* STA mode is linking */
+		goto apply;
+	}
+
+	if (ap_num == 0) {
+		/* No working AP mode */
+		goto apply;
+	}
+
+	if (rtw_is_dfs_ch(u_ch, u_bw, u_offset))
+		needed = _TRUE;
+
+apply:
+
+	DBG_871X(FUNC_ADPT_FMT" needed:%d, self_action:%u\n"
+		, FUNC_ADPT_ARG(adapter), needed, self_action);
+	DBG_871X(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num:%u, ap_num:%u, %u,%u,%u\n"
+		, FUNC_ADPT_ARG(adapter), ld_sta_num, lg_sta_num, ap_num, u_ch, u_bw, u_offset);
+
+	if (needed == _TRUE)
+		rtw_dfs_master_enable(adapter, u_ch, u_bw, u_offset);
+	else
+		rtw_dfs_master_disable(adapter, ld_sta_in_dfs);
+}
+#endif /* CONFIG_DFS_MASTER */
+
+#endif /* CONFIG_AP_MODE */
+
+#ifdef CONFIG_BT_COEXIST
+struct btinfo {
+	u8 cid;
+	u8 len;
+
+	u8 bConnection:1;
+	u8 bSCOeSCO:1;
+	u8 bInQPage:1;
+	u8 bACLBusy:1;
+	u8 bSCOBusy:1;
+	u8 bHID:1;
+	u8 bA2DP:1;
+	u8 bFTP:1;
+
+	u8 retry_cnt:4;
+	u8 rsvd_34:1;
+	u8 rsvd_35:1;
+	u8 rsvd_36:1;
+	u8 rsvd_37:1;
+
+	u8 rssi;
+
+	u8 rsvd_50:1;
+	u8 rsvd_51:1;
+	u8 rsvd_52:1;
+	u8 rsvd_53:1;
+	u8 rsvd_54:1;
+	u8 rsvd_55:1;
+	u8 eSCO_SCO:1;
+	u8 Master_Slave:1;
+
+	u8 rsvd_6;
+	u8 rsvd_7;
+};
+
+void btinfo_evt_dump(void *sel, void *buf)
+{
+	struct btinfo *info = (struct btinfo *)buf;
+	
+	DBG_871X_SEL_NL(sel, "cid:0x%02x, len:%u\n", info->cid, info->len);
+
+	if (info->len > 2)
+		DBG_871X_SEL_NL(sel, "byte2:%s%s%s%s%s%s%s%s\n"
+			, info->bConnection?"bConnection ":""
+			, info->bSCOeSCO?"bSCOeSCO ":""
+			, info->bInQPage?"bInQPage ":""
+			, info->bACLBusy?"bACLBusy ":""
+			, info->bSCOBusy?"bSCOBusy ":""
+			, info->bHID?"bHID ":""
+			, info->bA2DP?"bA2DP ":""
+			, info->bFTP?"bFTP":""
+		);
+
+	if (info->len > 3)
+		DBG_871X_SEL_NL(sel, "retry_cnt:%u\n", info->retry_cnt);
+
+	if (info->len > 4)
+		DBG_871X_SEL_NL(sel, "rssi:%u\n", info->rssi);
+
+	if (info->len > 5)
+		DBG_871X_SEL_NL(sel, "byte5:%s%s\n"
+			, info->eSCO_SCO?"eSCO_SCO ":""
+			, info->Master_Slave?"Master_Slave ":""
+		);
+}
+
+static void rtw_btinfo_hdl(_adapter *adapter, u8 *buf, u16 buf_len)
+{
+	#define BTINFO_WIFI_FETCH 0x23
+	#define BTINFO_BT_AUTO_RPT 0x27
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+	struct btinfo_8761ATV *info = (struct btinfo_8761ATV *)buf;
+#else //!CONFIG_BT_COEXIST_SOCKET_TRX
+	struct btinfo *info = (struct btinfo *)buf;
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX
+	u8 cmd_idx;
+	u8 len;
+
+	cmd_idx = info->cid;
+
+	if (info->len > buf_len-2) {
+		rtw_warn_on(1);
+		len = buf_len-2;
+	} else {
+		len = info->len;
+	}
+
+//#define DBG_PROC_SET_BTINFO_EVT
+#ifdef DBG_PROC_SET_BTINFO_EVT
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+	DBG_871X("%s: btinfo[0]=%x,btinfo[1]=%x,btinfo[2]=%x,btinfo[3]=%x btinfo[4]=%x,btinfo[5]=%x,btinfo[6]=%x,btinfo[7]=%x\n"
+				, __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+#else//!CONFIG_BT_COEXIST_SOCKET_TRX
+	btinfo_evt_dump(RTW_DBGDUMP, info);
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX
+#endif // DBG_PROC_SET_BTINFO_EVT
+
+	/* transform BT-FW btinfo to WiFI-FW C2H format and notify */
+	if (cmd_idx == BTINFO_WIFI_FETCH)
+		buf[1] = 0;
+	else if (cmd_idx == BTINFO_BT_AUTO_RPT)
+		buf[1] = 2;
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+	else if(0x01 == cmd_idx || 0x02 == cmd_idx)
+		buf[1] = buf[0];
+#endif //CONFIG_BT_COEXIST_SOCKET_TRX
+	rtw_btcoex_BtInfoNotify(adapter ,len+1, &buf[1]);
+}
+
+u8 rtw_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	u8 *btinfo;
+	struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	btinfo = rtw_zmalloc(len);
+	if (btinfo == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		rtw_mfree((u8*)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = len;
+	pdrvextra_cmd_parm->pbuf = btinfo;
+
+	_rtw_memcpy(btinfo, buf, len);
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+	return res;
+}
+#endif //CONFIG_BT_COEXIST
+
+//#ifdef CONFIG_C2H_PACKET_EN
+u8 rtw_c2h_packet_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size = length;
+	pdrvextra_cmd_parm->pbuf = pbuf;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+	return res;
+}
+
+//#else //CONFIG_C2H_PACKET_EN
+/* dont call R/W in this function, beucase SDIO interrupt have claim host */
+/* or deadlock will happen and cause special-systemserver-died in android */
+
+u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *c2h_evt)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+	pdrvextra_cmd_parm->type = 0;
+	pdrvextra_cmd_parm->size =  c2h_evt?16:0;
+	pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	
+exit:
+	
+	return res;
+}
+//#endif //CONFIG_C2H_PACKET_EN
+
+u8 rtw_run_in_thread_cmd(PADAPTER padapter, void (*func)(void*), void* context)
+{
+	struct cmd_priv *pcmdpriv;
+	struct cmd_obj *ph2c;
+	struct RunInThread_param *parm;
+	s32 res = _SUCCESS;
+
+_func_enter_;
+
+	pcmdpriv = &padapter->cmdpriv;
+
+	ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (NULL == ph2c) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	parm = (struct RunInThread_param*)rtw_zmalloc(sizeof(struct RunInThread_param));
+	if (NULL == parm) {
+		rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj));
+		res = _FAIL;
+		goto exit;
+	}
+
+	parm->func = func;
+	parm->context = context;
+	init_h2fwcmd_w_parm_no_rsp(ph2c, parm, GEN_CMD_CODE(_RunInThreadCMD));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+s32 c2h_evt_hdl(_adapter *adapter, u8 *c2h_evt, c2h_id_filter filter)
+{
+	s32 ret = _FAIL;
+	u8 buf[16];
+
+	if (!c2h_evt) {
+		/* No c2h event in cmd_obj, read c2h event before handling*/
+		if (rtw_hal_c2h_evt_read(adapter, buf) == _SUCCESS) {
+			c2h_evt = buf;
+			
+			if (filter && filter(c2h_evt) == _FALSE)
+				goto exit;
+
+			ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+		}
+	} else {
+
+		if (filter && filter(c2h_evt) == _FALSE)
+			goto exit;
+
+		ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+	}
+exit:
+	return ret;
+}
+
+#ifdef CONFIG_C2H_WK
+static void c2h_wk_callback(_workitem *work)
+{
+	struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
+	_adapter *adapter = container_of(evtpriv, _adapter, evtpriv);
+	u8 *c2h_evt;
+	c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
+
+	evtpriv->c2h_wk_alive = _TRUE;
+
+	while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
+		if ((c2h_evt = (u8 *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+			/* This C2H event is read, clear it */
+			c2h_evt_clear(adapter);
+		} else if ((c2h_evt = (u8 *)rtw_malloc(16)) != NULL) {
+			/* This C2H event is not read, read & clear now */
+			if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) {
+				rtw_mfree(c2h_evt, 16);
+				continue;
+			}
+		} else {
+			rtw_warn_on(1);
+			continue;
+		}
+
+		/* Special pointer to trigger c2h_evt_clear only */
+		if ((void *)c2h_evt == (void *)evtpriv)
+			continue;
+
+		if (!rtw_hal_c2h_valid(adapter, c2h_evt)) {
+			rtw_mfree(c2h_evt, 16);
+			continue;
+		}
+		
+		if (ccx_id_filter(c2h_evt) == _TRUE) {
+			/* Handle CCX report here */
+			rtw_hal_c2h_handler(adapter, c2h_evt);
+			rtw_mfree(c2h_evt, 16);
+		} else {
+			/* Enqueue into cmd_thread for others */
+			rtw_c2h_wk_cmd(adapter, c2h_evt);
+		}
+	}
+
+	evtpriv->c2h_wk_alive = _FALSE;
+}
+#endif
+
+u8 rtw_drvextra_cmd_hdl(_adapter *padapter, unsigned char *pbuf)
+{
+	struct drvextra_cmd_parm *pdrvextra_cmd;
+
+	if(!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	pdrvextra_cmd = (struct drvextra_cmd_parm*)pbuf;
+	
+	switch(pdrvextra_cmd->ec_id)
+	{
+		case DYNAMIC_CHK_WK_CID://only  primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces
+#ifdef CONFIG_CONCURRENT_MODE
+			if(padapter->pbuddy_adapter)
+			{
+				dynamic_chk_wk_hdl(padapter->pbuddy_adapter);
+			}	
+#endif //CONFIG_CONCURRENT_MODE
+			dynamic_chk_wk_hdl(padapter);
+			break;
+		case POWER_SAVING_CTRL_WK_CID:
+			power_saving_wk_hdl(padapter);	
+			break;
+#ifdef CONFIG_LPS
+		case LPS_CTRL_WK_CID:
+			lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type);
+			break;
+		case DM_IN_LPS_WK_CID:			
+			rtw_dm_in_lps_hdl(padapter);	
+			break;
+		case LPS_CHANGE_DTIM_CID:
+			rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type);
+			break;
+#endif
+#if (RATE_ADAPTIVE_SUPPORT==1)
+		case RTP_TIMER_CFG_WK_CID:
+			rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type);
+			break;
+#endif
+#ifdef CONFIG_ANTENNA_DIVERSITY
+		case ANT_SELECT_WK_CID:
+			antenna_select_wk_hdl(padapter, pdrvextra_cmd->type);
+			break;
+#endif
+#ifdef CONFIG_P2P_PS
+		case P2P_PS_WK_CID:
+			p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type);
+			break;
+#endif //CONFIG_P2P_PS
+#ifdef CONFIG_P2P
+		case P2P_PROTO_WK_CID:
+			//	Commented by Albert 2011/07/01
+			//	I used the type_size as the type command
+			p2p_protocol_wk_hdl( padapter, pdrvextra_cmd->type );
+			break;
+#endif //CONFIG_P2P
+#ifdef CONFIG_AP_MODE
+		case CHECK_HIQ_WK_CID:
+			rtw_chk_hi_queue_hdl(padapter);
+			break;
+#endif //CONFIG_AP_MODE
+#ifdef CONFIG_INTEL_WIDI
+		case INTEl_WIDI_WK_CID:
+			intel_widi_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf);
+			break;
+#endif //CONFIG_INTEL_WIDI
+		//add for CONFIG_IEEE80211W, none 11w can use it
+		case RESET_SECURITYPRIV:
+			reset_securitypriv_hdl(padapter);
+			break;
+		case FREE_ASSOC_RESOURCES:
+			free_assoc_resources_hdl(padapter);
+			break;
+		case C2H_WK_CID:
+#ifdef CONFIG_C2H_PACKET_EN
+			rtw_hal_set_hwreg_with_buf(padapter, HW_VAR_C2H_HANDLE, pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+#else		
+			c2h_evt_hdl(padapter, pdrvextra_cmd->pbuf, NULL);
+#endif
+			break;
+#ifdef CONFIG_BEAMFORMING
+		case BEAMFORMING_WK_CID:
+			beamforming_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf);
+			break;
+#endif //CONFIG_BEAMFORMING
+		case DM_RA_MSK_WK_CID:
+			rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf);
+			break;
+#ifdef CONFIG_BT_COEXIST
+		case BTINFO_WK_CID:
+			rtw_btinfo_hdl(padapter ,pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+			break;
+#endif
+#ifdef CONFIG_DFS_MASTER
+		case DFS_MASTER_WK_CID:
+			rtw_dfs_master_hdl(padapter);
+			break;
+#endif
+		default:
+			break;
+	}
+
+	if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size>0)
+	{
+		rtw_mfree(pdrvextra_cmd->pbuf, pdrvextra_cmd->size);
+	}
+
+	return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback(_adapter*	padapter ,  struct cmd_obj *pcmd)
+{
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	if(pcmd->res == H2C_DROPPED)
+	{
+		//TODO: cancel timer and do timeout handler directly...
+		//need to make timeout handlerOS independent
+		mlme_set_scan_to_timer(pmlmepriv, 1);
+	}
+	else if (pcmd->res != H2C_SUCCESS) {
+		mlme_set_scan_to_timer(pmlmepriv, 1);
+		RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
+	} 
+
+	// free cmd
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;	
+}
+void rtw_disassoc_cmd_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{
+	_irqL	irqL;
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	
+_func_enter_;	
+
+	if (pcmd->res != H2C_SUCCESS)
+	{
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+		set_fwstate(pmlmepriv, _FW_LINKED);
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+				
+		RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ***Error: disconnect_cmd_callback Fail ***\n."));
+
+		goto exit;
+	}
+#ifdef CONFIG_BR_EXT
+	else //clear bridge database
+		nat25_db_cleanup(padapter);
+#endif //CONFIG_BR_EXT
+
+	// free cmd
+	rtw_free_cmd_obj(pcmd);
+	
+exit:
+	
+_func_exit_;	
+}
+
+
+void rtw_joinbss_cmd_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;	
+
+	if(pcmd->res == H2C_DROPPED)
+	{
+		//TODO: cancel timer and do timeout handler directly...
+		//need to make timeout handlerOS independent
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+	}
+	else if(pcmd->res != H2C_SUCCESS)
+	{
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+	}
+
+	rtw_free_cmd_obj(pcmd);
+	
+_func_exit_;	
+}
+
+void rtw_create_ibss_post_hdl(_adapter *padapter, int status)
+{	
+	_irqL irqL;
+	u8 timer_cancelled;
+	struct sta_info *psta = NULL;
+	struct wlan_network *pwlan = NULL;		
+	struct 	mlme_priv *pmlmepriv = &padapter->mlmepriv;	
+	WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network;
+	struct wlan_network *mlme_cur_network = &(pmlmepriv->cur_network);
+
+	if (status != H2C_SUCCESS)
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+
+	_cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	{	
+		_irqL irqL;
+
+		pwlan = _rtw_alloc_network(pmlmepriv);
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		if (pwlan == NULL) {
+			pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
+			if (pwlan == NULL) {
+				RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("Error:  can't get pwlan in rtw_joinbss_event_callback\n"));
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+				goto createbss_cmd_fail;
+			}
+			pwlan->last_scanned = rtw_get_current_time();
+		} else {
+			rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
+		}
+
+		pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network);
+		_rtw_memcpy(&(pwlan->network), pdev_network, pdev_network->Length);
+		//pwlan->fixed = _TRUE;
+
+		/* copy pdev_network information to pmlmepriv->cur_network */
+		_rtw_memcpy(&mlme_cur_network->network, pdev_network, (get_WLAN_BSSID_EX_sz(pdev_network)));
+
+		#if 0
+		/* reset DSConfig */
+		mlme_cur_network->network.Configuration.DSConfig = (u32)rtw_ch2freq(pdev_network->Configuration.DSConfig);
+		#endif
+
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		/* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
+	}
+
+createbss_cmd_fail:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+exit:
+	return;
+}
+
+
+
+void rtw_setstaKey_cmdrsp_callback(_adapter*	padapter ,  struct cmd_obj *pcmd)
+{
+	
+	struct sta_priv * pstapriv = &padapter->stapriv;
+	struct set_stakey_rsp* psetstakey_rsp = (struct set_stakey_rsp*) (pcmd->rsp);
+	struct sta_info*	psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
+
+_func_enter_;	
+
+	if(psta==NULL)
+	{
+		RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info \n\n"));
+		goto exit;
+	}
+	
+	//psta->aid = psta->mac_id = psetstakey_rsp->keyid; //CAM_ID(CAM_ENTRY)
+	
+exit:	
+
+	rtw_free_cmd_obj(pcmd);
+	
+_func_exit_;	
+
+}
+void rtw_setassocsta_cmdrsp_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{
+	_irqL	irqL;
+	struct sta_priv * pstapriv = &padapter->stapriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;	
+	struct set_assocsta_parm* passocsta_parm = (struct set_assocsta_parm*)(pcmd->parmbuf);
+	struct set_assocsta_rsp* passocsta_rsp = (struct set_assocsta_rsp*) (pcmd->rsp);		
+	struct sta_info*	psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
+
+_func_enter_;	
+	
+	if(psta==NULL)
+	{
+		RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info \n\n"));
+		goto exit;
+	}
+	
+	psta->aid = psta->mac_id = passocsta_rsp->cam_id;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE))           	
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+	set_fwstate(pmlmepriv, _FW_LINKED);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_getrttbl_cmd_cmdrsp_callback(_adapter*	padapter,  struct cmd_obj *pcmd);
+void rtw_getrttbl_cmd_cmdrsp_callback(_adapter*	padapter,  struct cmd_obj *pcmd)
+{
+_func_enter_;
+
+	rtw_free_cmd_obj(pcmd);
+#ifdef CONFIG_MP_INCLUDED
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted=_TRUE;
+#endif
+
+_func_exit_;
+
+}
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_debug.c b/drivers/net/wireless/rtl8189es/core/rtw_debug.c
new file mode 100644
index 000000000000..fd47a5e615b3
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_debug.c
@@ -0,0 +1,3793 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_DEBUG_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+u32 GlobalDebugLevel = _drv_err_;
+
+#ifdef CONFIG_DEBUG_RTL871X
+
+	u64 GlobalDebugComponents = \
+			_module_rtl871x_xmit_c_ |
+			_module_xmit_osdep_c_ |
+			_module_rtl871x_recv_c_ |
+			_module_recv_osdep_c_ |
+			_module_rtl871x_mlme_c_ |
+			_module_mlme_osdep_c_ |
+			_module_rtl871x_sta_mgt_c_ |
+			_module_rtl871x_cmd_c_ |
+			_module_cmd_osdep_c_ |
+			_module_rtl871x_io_c_ |
+			_module_io_osdep_c_ |
+			_module_os_intfs_c_|
+			_module_rtl871x_security_c_|
+			_module_rtl871x_eeprom_c_|
+			_module_hal_init_c_|
+			_module_hci_hal_init_c_|
+			_module_rtl871x_ioctl_c_|
+			_module_rtl871x_ioctl_set_c_|
+			_module_rtl871x_ioctl_query_c_|
+			_module_rtl871x_pwrctrl_c_|
+			_module_hci_intfs_c_|
+			_module_hci_ops_c_|
+			_module_hci_ops_os_c_|
+			_module_rtl871x_ioctl_os_c|
+			_module_rtl8712_cmd_c_|
+			_module_hal_xmit_c_|
+			_module_rtl8712_recv_c_ |
+			_module_mp_ |
+			_module_efuse_;
+
+#endif /* CONFIG_DEBUG_RTL871X */
+
+#include <rtw_version.h>
+
+#ifdef CONFIG_TDLS
+#define TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE	41
+#endif
+
+void dump_drv_version(void *sel)
+{
+	DBG_871X_SEL_NL(sel, "%s %s\n", DRV_NAME, DRIVERVERSION);
+//	DBG_871X_SEL_NL(sel, "build time: %s %s\n", __DATE__, __TIME__);
+}
+
+void dump_drv_cfg(void *sel)
+{
+	char *kernel_version = utsname()->release;
+	
+	DBG_871X_SEL_NL(sel, "\nKernel Version: %s\n", kernel_version);
+	DBG_871X_SEL_NL(sel, "Driver Version: %s\n", DRIVERVERSION);
+	DBG_871X_SEL_NL(sel, "------------------------------------------------\n");
+#ifdef CONFIG_IOCTL_CFG80211
+	DBG_871X_SEL_NL(sel, "CFG80211\n");
+	#ifdef RTW_USE_CFG80211_STA_EVENT
+	DBG_871X_SEL_NL(sel, "RTW_USE_CFG80211_STA_EVENT\n");
+	#endif
+#else
+	DBG_871X_SEL_NL(sel, "WEXT\n");
+#endif
+
+	DBG_871X_SEL_NL(sel, "DBG:%d\n", DBG);
+#ifdef CONFIG_DEBUG
+	DBG_871X_SEL_NL(sel, "CONFIG_DEBUG\n");
+#endif
+
+#ifdef CONFIG_CONCURRENT_MODE
+	DBG_871X_SEL_NL(sel, "CONFIG_CONCURRENT_MODE\n");
+#endif
+
+#ifdef CONFIG_POWER_SAVING
+	DBG_871X_SEL_NL(sel, "CONFIG_POWER_SAVING\n");
+#endif
+
+#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
+	DBG_871X_SEL_NL(sel, "LOAD_PHY_PARA_FROM_FILE - REALTEK_CONFIG_PATH=%s\n", REALTEK_CONFIG_PATH);
+	#ifdef CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY
+	DBG_871X_SEL_NL(sel, "CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY\n");
+	#endif
+	#ifdef CONFIG_CALIBRATE_TX_POWER_TO_MAX
+	DBG_871X_SEL_NL(sel, "CONFIG_CALIBRATE_TX_POWER_TO_MAX\n");
+	#endif
+#endif
+
+#ifdef CONFIG_DISABLE_ODM
+	DBG_871X_SEL_NL(sel, "CONFIG_DISABLE_ODM\n");
+#endif
+
+#ifdef CONFIG_MINIMAL_MEMORY_USAGE
+	DBG_871X_SEL_NL(sel, "CONFIG_MINIMAL_MEMORY_USAGE\n");
+#endif
+
+	DBG_871X_SEL_NL(sel, "CONFIG_RTW_ADAPTIVITY_EN = %d\n", CONFIG_RTW_ADAPTIVITY_EN);
+#if (CONFIG_RTW_ADAPTIVITY_EN)
+	DBG_871X_SEL_NL(sel, "ADAPTIVITY_MODE = %s\n", (CONFIG_RTW_ADAPTIVITY_MODE) ? "carrier_sense" : "normal");
+#endif
+
+#ifdef CONFIG_WOWLAN
+	DBG_871X_SEL_NL(sel, "CONFIG_WOWLAN - ");
+
+	#ifdef CONFIG_GPIO_WAKEUP
+	DBG_871X_SEL_NL(sel, "CONFIG_GPIO_WAKEUP - WAKEUP_GPIO_IDX:%d\n", WAKEUP_GPIO_IDX);
+	#endif
+#endif	
+
+#ifdef CONFIG_USB_HCI
+	#ifdef CONFIG_SUPPORT_USB_INT	
+	DBG_871X_SEL_NL(sel, "CONFIG_SUPPORT_USB_INT\n");
+	#endif
+	#ifdef CONFIG_USB_INTERRUPT_IN_PIPE		
+	DBG_871X_SEL_NL(sel, "CONFIG_USB_INTERRUPT_IN_PIPE\n");
+	#endif
+	#ifdef CONFIG_USB_TX_AGGREGATION
+	DBG_871X_SEL_NL(sel, "CONFIG_USB_TX_AGGREGATION\n");
+	#endif
+	#ifdef CONFIG_USB_RX_AGGREGATION
+	DBG_871X_SEL_NL(sel, "CONFIG_USB_RX_AGGREGATION\n");
+	#endif
+	#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
+	DBG_871X_SEL_NL(sel, "CONFIG_USE_USB_BUFFER_ALLOC_TX\n");
+	#endif
+	#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
+	DBG_871X_SEL_NL(sel, "CONFIG_USE_USB_BUFFER_ALLOC_RX\n");
+	#endif	
+	#ifdef CONFIG_PREALLOC_RECV_SKB
+	DBG_871X_SEL_NL(sel, "CONFIG_PREALLOC_RECV_SKB\n");
+	#endif
+	#ifdef CONFIG_FIX_NR_BULKIN_BUFFER
+	DBG_871X_SEL_NL(sel, "CONFIG_FIX_NR_BULKIN_BUFFER\n");
+	#endif
+#endif /*CONFIG_USB_HCI*/
+	
+#ifdef CONFIG_SDIO_HCI
+	#ifdef CONFIG_TX_AGGREGATION
+	DBG_871X_SEL_NL(sel, "CONFIG_TX_AGGREGATION\n");
+	#endif
+	#ifdef CONFIG_RX_AGGREGATION
+	DBG_871X_SEL_NL(sel, "CONFIG_RX_AGGREGATION\n");
+	#endif
+#endif /*CONFIG_SDIO_HCI*/
+
+#ifdef CONFIG_PCI_HCI
+#endif
+	
+	DBG_871X_SEL_NL(sel, "MAX_XMITBUF_SZ = %d\n", MAX_XMITBUF_SZ);
+	DBG_871X_SEL_NL(sel, "MAX_RECVBUF_SZ = %d\n", MAX_RECVBUF_SZ);
+	
+}
+
+void dump_log_level(void *sel)
+{
+	DBG_871X_SEL_NL(sel, "log_level:%d\n", GlobalDebugLevel);
+}
+
+#ifdef CONFIG_SDIO_HCI
+void sd_f0_reg_dump(void *sel, _adapter *adapter)
+{
+	int i;
+
+	for(i=0x0;i<=0xff;i++)
+	{	
+		if(i%16==0)
+			DBG_871X_SEL_NL(sel, "0x%02x ",i);
+
+		DBG_871X_SEL(sel, "%02x ", rtw_sd_f0_read8(adapter, i));
+
+		if(i%16==15)
+			DBG_871X_SEL(sel, "\n");
+		else if(i%8==7)
+			DBG_871X_SEL(sel, "\t");
+	}
+}
+
+void sdio_local_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	for (i = 0x0; i < 0x100; i += 4) {
+		if (j % 4 == 1)
+			DBG_871X_SEL_NL(sel, "0x%02x", i);
+		DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, (0x1025 << 16) | i));
+		if ((j++) % 4 == 0)
+			DBG_871X_SEL(sel, "\n");
+	}
+}
+#endif /* CONFIG_SDIO_HCI */
+
+void mac_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	DBG_871X_SEL_NL(sel, "======= MAC REG =======\n");
+
+	for(i=0x0;i<0x800;i+=4)
+	{
+		if(j%4==1)
+			DBG_871X_SEL_NL(sel, "0x%03x",i);
+		DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter,i));
+		if((j++)%4 == 0)
+			DBG_871X_SEL(sel, "\n");
+	}
+	
+#ifdef CONFIG_RTL8814A
+	{
+		for(i=0x1000;i<0x1650;i+=4)
+		{
+			if(j%4==1)
+				DBG_871X_SEL_NL(sel, "0x%03x",i);
+			DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter,i));
+			if((j++)%4 == 0)
+				DBG_871X_SEL(sel, "\n");
+		}
+	}
+#endif /* CONFIG_RTL8814A */
+}
+
+void bb_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1;
+
+	DBG_871X_SEL_NL(sel, "======= BB REG =======\n");
+	for(i=0x800;i<0x1000;i+=4)
+	{
+		if(j%4==1)
+			DBG_871X_SEL_NL(sel, "0x%03x",i);
+		DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter,i));
+		if((j++)%4 == 0)
+			DBG_871X_SEL(sel, "\n");
+	}
+}
+
+void rf_reg_dump(void *sel, _adapter *adapter)
+{
+	int i, j = 1, path;
+	u32 value;
+	u8 rf_type = 0;
+	u8 path_nums = 0;
+
+	rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+	if((RF_1T2R == rf_type) ||(RF_1T1R ==rf_type ))
+		path_nums = 1;
+	else
+		path_nums = 2;
+
+	DBG_871X_SEL_NL(sel, "======= RF REG =======\n");
+
+	for (path=0;path<path_nums;path++) {
+		DBG_871X_SEL_NL(sel, "RF_Path(%x)\n",path);
+		for (i=0;i<0x100;i++) {
+			//value = PHY_QueryRFReg(adapter, (RF90_RADIO_PATH_E)path,i, bMaskDWord);
+			value = rtw_hal_read_rfreg(adapter, path, i, 0xffffffff);
+			if(j%4==1)
+				DBG_871X_SEL_NL(sel, "0x%02x ",i);
+			DBG_871X_SEL(sel, " 0x%08x ",value);
+			if((j++)%4==0)
+				DBG_871X_SEL(sel, "\n");
+		}
+	}
+}
+
+static u8 fwdl_test_chksum_fail = 0;
+static u8 fwdl_test_wintint_rdy_fail = 0;
+
+bool rtw_fwdl_test_trigger_chksum_fail(void)
+{
+	if (fwdl_test_chksum_fail) {
+		DBG_871X_LEVEL(_drv_always_, "fwdl test case: trigger chksum_fail\n");
+		fwdl_test_chksum_fail--;
+		return _TRUE;
+	}
+	return _FALSE;
+}
+
+bool rtw_fwdl_test_trigger_wintint_rdy_fail(void)
+{
+	if (fwdl_test_wintint_rdy_fail) {
+		DBG_871X_LEVEL(_drv_always_, "fwdl test case: trigger wintint_rdy_fail\n");
+		fwdl_test_wintint_rdy_fail--;
+		return _TRUE;
+	}
+	return _FALSE;
+}
+
+static u32 g_wait_hiq_empty_ms = 0;
+
+u32 rtw_get_wait_hiq_empty_ms(void)
+{
+	return g_wait_hiq_empty_ms;
+}
+
+static u8 del_rx_ampdu_test_no_tx_fail = 0;
+
+bool rtw_del_rx_ampdu_test_trigger_no_tx_fail(void)
+{
+	if (del_rx_ampdu_test_no_tx_fail) {
+		DBG_871X_LEVEL(_drv_always_, "del_rx_ampdu test case: trigger no_tx_fail\n");
+		del_rx_ampdu_test_no_tx_fail--;
+		return _TRUE;
+	}
+	return _FALSE;
+}
+
+void rtw_sink_rtp_seq_dbg( _adapter *adapter,_pkt *pkt)
+{
+	struct recv_priv *precvpriv = &(adapter->recvpriv);
+	if( precvpriv->sink_udpport > 0)
+	{
+		if(*((u16*)((pkt->data)+0x24)) == cpu_to_be16(precvpriv->sink_udpport))
+		{
+			precvpriv->pre_rtp_rxseq= precvpriv->cur_rtp_rxseq;
+			precvpriv->cur_rtp_rxseq = be16_to_cpu(*((u16*)((pkt->data)+0x2C)));
+			if( precvpriv->pre_rtp_rxseq+1 != precvpriv->cur_rtp_rxseq)
+				DBG_871X("%s : RTP Seq num from %d to %d\n",__FUNCTION__,precvpriv->pre_rtp_rxseq,precvpriv->cur_rtp_rxseq);
+		}
+	}
+}
+
+void sta_rx_reorder_ctl_dump(void *sel, struct sta_info *sta)
+{
+	struct recv_reorder_ctrl *reorder_ctl;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		reorder_ctl = &sta->recvreorder_ctrl[i];
+		if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID || reorder_ctl->indicate_seq != 0xFFFF) {
+			DBG_871X_SEL_NL(sel, "tid=%d, enable=%d, ampdu_size=%u, indicate_seq=%u\n"
+				, i, reorder_ctl->enable, reorder_ctl->ampdu_size, reorder_ctl->indicate_seq
+			);
+		}
+	}
+}
+
+void dump_adapters_status(void *sel, struct dvobj_priv *dvobj)
+{
+	struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj);
+	int i;
+	_adapter *iface;
+	u8 u_ch, u_bw, u_offset;
+
+	DBG_871X_SEL_NL(sel, "%-2s %-8s %-4s %-7s %s\n"
+		, "id", "ifname", "port", "ch", "status");
+
+	DBG_871X_SEL_NL(sel, "------------------------\n");
+
+	for (i = 0; i < dvobj->iface_nums; i++) {
+		iface = dvobj->padapters[i];
+		if (iface) {
+			DBG_871X_SEL_NL(sel, "%2d %-8s %4hhu %3u,%u,%u "MLME_STATE_FMT" %s%s\n"
+				, i, ADPT_ARG(iface)
+				, get_iface_type(iface)
+				, iface->mlmeextpriv.cur_channel
+				, iface->mlmeextpriv.cur_bwmode
+				, iface->mlmeextpriv.cur_ch_offset
+				, ADPT_MLME_S_ARG(iface)
+				, rtw_is_surprise_removed(iface)?" SR":""
+				, rtw_is_drv_stopped(iface)?" DS":""
+			);
+		}
+	}
+
+	DBG_871X_SEL_NL(sel, "------------------------\n");
+
+	rtw_get_ch_setting_union(dvobj->padapters[IFACE_ID0], &u_ch, &u_bw, &u_offset);
+	DBG_871X_SEL_NL(sel, "%16s %3u,%u,%u\n"
+		, "union:"
+		, u_ch, u_bw, u_offset
+	);
+
+	DBG_871X_SEL_NL(sel, "%16s %3u,%u,%u\n"
+		, "oper:"
+		, dvobj->oper_channel
+		, dvobj->oper_bwmode
+		, dvobj->oper_ch_offset
+	);
+
+	#ifdef CONFIG_DFS_MASTER
+	if (rfctl->radar_detect_ch != 0) {
+		DBG_871X_SEL_NL(sel, "%16s %3u,%u,%u"
+			, "radar_detect:"
+			, rfctl->radar_detect_ch
+			, rfctl->radar_detect_bw
+			, rfctl->radar_detect_offset
+		);
+
+		if (IS_UNDER_CAC(rfctl))
+			DBG_871X_SEL(sel, ", cac:%d\n", rtw_systime_to_ms(rfctl->cac_end_time - rtw_get_current_time()));
+		else
+			DBG_871X_SEL(sel, "\n");
+	}
+	#endif
+}
+
+#ifdef CONFIG_PROC_DEBUG
+ssize_t proc_set_write_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 addr, val, len;
+
+	if (count < 3)
+	{
+		DBG_871X("argument size is less than 3\n");
+		return -EFAULT;
+	}	
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
+
+		if (num !=  3) {
+			DBG_871X("invalid write_reg parameter!\n");
+			return count;
+		}
+
+		switch(len)
+		{
+			case 1:
+				rtw_write8(padapter, addr, (u8)val);				
+				break;
+			case 2:
+				rtw_write16(padapter, addr, (u16)val);				
+				break;
+			case 4:
+				rtw_write32(padapter, addr, val);				
+				break;
+			default:
+				DBG_871X("error write length=%d", len);
+				break;
+		}			
+		
+	}
+	
+	return count;
+	
+}
+
+static u32 proc_get_read_addr=0xeeeeeeee;
+static u32 proc_get_read_len=0x4;
+
+int proc_get_read_reg(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+	if (proc_get_read_addr==0xeeeeeeee) {
+		DBG_871X_SEL_NL(m, "address not initialized\n");
+		return 0;
+	}	
+
+	switch(proc_get_read_len)
+	{
+		case 1:			
+			DBG_871X_SEL_NL(m, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr));
+			break;
+		case 2:
+			DBG_871X_SEL_NL(m, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr));
+			break;
+		case 4:
+			DBG_871X_SEL_NL(m, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr));
+			break;
+		default:
+			DBG_871X_SEL_NL(m, "error read length=%d\n", proc_get_read_len);
+			break;
+	}
+
+	return 0;
+}
+
+ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	char tmp[16];
+	u32 addr, len;
+
+	if (count < 2)
+	{
+		DBG_871X("argument size is less than 2\n");
+		return -EFAULT;
+	}	
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%x %x", &addr, &len);
+
+		if (num !=  2) {
+			DBG_871X("invalid read_reg parameter!\n");
+			return count;
+		}
+
+		proc_get_read_addr = addr;
+		
+		proc_get_read_len = len;
+	}
+	
+	return count;
+
+}
+
+int proc_get_fwstate(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	DBG_871X_SEL_NL(m, "fwstate=0x%x\n", get_fwstate(pmlmepriv));
+
+	return 0;
+}
+
+int proc_get_sec_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);	
+	struct security_priv *sec = &padapter->securitypriv;
+
+	DBG_871X_SEL_NL(m, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", 
+						sec->dot11AuthAlgrthm, sec->dot11PrivacyAlgrthm,
+						sec->ndisauthtype, sec->ndisencryptstatus);
+
+	DBG_871X_SEL_NL(m, "hw_decrypted=%d\n", sec->hw_decrypted);
+
+#ifdef DBG_SW_SEC_CNT
+	DBG_871X_SEL_NL(m, "wep_sw_enc_cnt=%llu, %llu, %llu\n"
+		, sec->wep_sw_enc_cnt_bc , sec->wep_sw_enc_cnt_mc, sec->wep_sw_enc_cnt_uc);
+	DBG_871X_SEL_NL(m, "wep_sw_dec_cnt=%llu, %llu, %llu\n"
+		, sec->wep_sw_dec_cnt_bc , sec->wep_sw_dec_cnt_mc, sec->wep_sw_dec_cnt_uc);
+
+	DBG_871X_SEL_NL(m, "tkip_sw_enc_cnt=%llu, %llu, %llu\n"
+		, sec->tkip_sw_enc_cnt_bc , sec->tkip_sw_enc_cnt_mc, sec->tkip_sw_enc_cnt_uc);	
+	DBG_871X_SEL_NL(m, "tkip_sw_dec_cnt=%llu, %llu, %llu\n"
+		, sec->tkip_sw_dec_cnt_bc , sec->tkip_sw_dec_cnt_mc, sec->tkip_sw_dec_cnt_uc);
+
+	DBG_871X_SEL_NL(m, "aes_sw_enc_cnt=%llu, %llu, %llu\n"
+		, sec->aes_sw_enc_cnt_bc , sec->aes_sw_enc_cnt_mc, sec->aes_sw_enc_cnt_uc);
+	DBG_871X_SEL_NL(m, "aes_sw_dec_cnt=%llu, %llu, %llu\n"
+		, sec->aes_sw_dec_cnt_bc , sec->aes_sw_dec_cnt_mc, sec->aes_sw_dec_cnt_uc);
+#endif /* DBG_SW_SEC_CNT */
+
+	return 0;
+}
+
+int proc_get_mlmext_state(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);	
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	DBG_871X_SEL_NL(m, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state);
+
+	return 0;
+}
+
+#ifdef CONFIG_LAYER2_ROAMING
+int proc_get_roam_flags(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+	DBG_871X_SEL_NL(m, "0x%02x\n", rtw_roam_flags(adapter));
+
+	return 0;
+}
+
+ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+	char tmp[32];
+	u8 flags;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx", &flags);
+
+		if (num == 1)
+			rtw_assign_roam_flags(adapter, flags);
+	}
+	
+	return count;
+	
+}
+
+int proc_get_roam_param(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+
+	DBG_871X_SEL_NL(m, "%12s %12s %11s\n", "rssi_diff_th", "scanr_exp_ms", "scan_int_ms");
+	DBG_871X_SEL_NL(m, "%-12u %-12u %-11u\n"
+		, mlme->roam_rssi_diff_th
+		, mlme->roam_scanr_exp_ms
+		, mlme->roam_scan_int_ms
+	);
+
+	return 0;
+}
+
+ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *mlme = &adapter->mlmepriv;
+
+	char tmp[32];
+	u8 rssi_diff_th;
+	u32 scanr_exp_ms;
+	u32 scan_int_ms;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhu %u %u", &rssi_diff_th, &scanr_exp_ms, &scan_int_ms);
+
+		if (num >= 1)
+			mlme->roam_rssi_diff_th = rssi_diff_th;
+		if (num >= 2)
+			mlme->roam_scanr_exp_ms = scanr_exp_ms;
+		if (num >= 3)
+			mlme->roam_scan_int_ms = scan_int_ms;
+	}
+	
+	return count;
+	
+}
+
+ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+	char tmp[32];
+	u8 addr[ETH_ALEN];
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr+1, addr+2, addr+3, addr+4, addr+5);
+		if (num == 6)
+			_rtw_memcpy(adapter->mlmepriv.roam_tgt_addr, addr, ETH_ALEN);
+
+		DBG_871X("set roam_tgt_addr to "MAC_FMT"\n", MAC_ARG(adapter->mlmepriv.roam_tgt_addr));
+	}
+
+	return count;
+}
+#endif /* CONFIG_LAYER2_ROAMING */
+
+int proc_get_qos_option(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	DBG_871X_SEL_NL(m, "qos_option=%d\n", pmlmepriv->qospriv.qos_option);
+
+	return 0;
+}
+
+int proc_get_ht_option(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	
+#ifdef CONFIG_80211N_HT
+	DBG_871X_SEL_NL(m, "ht_option=%d\n", pmlmepriv->htpriv.ht_option);
+#endif //CONFIG_80211N_HT
+
+	return 0;
+}
+
+int proc_get_rf_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);	
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;	
+
+	DBG_871X_SEL_NL(m, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", 
+					pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+	
+	DBG_871X_SEL_NL(m, "oper_ch=%d, oper_bw=%d, oper_ch_offet=%d\n", 
+					rtw_get_oper_ch(padapter), rtw_get_oper_bw(padapter),  rtw_get_oper_choffset(padapter));
+
+	return 0;
+}
+
+int proc_get_scan_param(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct ss_res *ss = &mlmeext->sitesurvey_res;
+
+#define SCAN_PARAM_TITLE_FMT "%10s"
+#define SCAN_PARAM_VALUE_FMT "%-10u"
+#define SCAN_PARAM_TITLE_ARG , "scan_ch_ms"
+#define SCAN_PARAM_VALUE_ARG , ss->scan_ch_ms
+#ifdef CONFIG_80211N_HT
+	#define SCAN_PARAM_TITLE_FMT_HT " %15s %13s"
+	#define SCAN_PARAM_VALUE_FMT_HT " %-15u %-13u"
+	#define SCAN_PARAM_TITLE_ARG_HT , "rx_ampdu_accept", "rx_ampdu_size"
+	#define SCAN_PARAM_VALUE_ARG_HT , ss->rx_ampdu_accept, ss->rx_ampdu_size
+#else
+	#define SCAN_PARAM_TITLE_FMT_HT ""
+	#define SCAN_PARAM_VALUE_FMT_HT ""
+	#define SCAN_PARAM_TITLE_ARG_HT
+	#define SCAN_PARAM_VALUE_ARG_HT
+#endif
+#ifdef CONFIG_SCAN_BACKOP
+	#define SCAN_PARAM_TITLE_FMT_BACKOP " %9s %12s"
+	#define SCAN_PARAM_VALUE_FMT_BACKOP " %-9u %-12u"
+	#define SCAN_PARAM_TITLE_ARG_BACKOP , "backop_ms", "scan_cnt_max"
+	#define SCAN_PARAM_VALUE_ARG_BACKOP , ss->backop_ms, ss->scan_cnt_max
+#else
+	#define SCAN_PARAM_TITLE_FMT_BACKOP ""
+	#define SCAN_PARAM_VALUE_FMT_BACKOP ""
+	#define SCAN_PARAM_TITLE_ARG_BACKOP
+	#define SCAN_PARAM_VALUE_ARG_BACKOP
+#endif
+
+	DBG_871X_SEL_NL(m,
+		SCAN_PARAM_TITLE_FMT
+		SCAN_PARAM_TITLE_FMT_HT
+		SCAN_PARAM_TITLE_FMT_BACKOP
+		"\n"
+		SCAN_PARAM_TITLE_ARG
+		SCAN_PARAM_TITLE_ARG_HT
+		SCAN_PARAM_TITLE_ARG_BACKOP
+	);
+
+	DBG_871X_SEL_NL(m,
+		SCAN_PARAM_VALUE_FMT
+		SCAN_PARAM_VALUE_FMT_HT
+		SCAN_PARAM_VALUE_FMT_BACKOP
+		"\n"
+		SCAN_PARAM_VALUE_ARG
+		SCAN_PARAM_VALUE_ARG_HT
+		SCAN_PARAM_VALUE_ARG_BACKOP
+	);
+
+	return 0;
+}
+
+ssize_t proc_set_scan_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+	struct ss_res *ss = &mlmeext->sitesurvey_res;
+
+	char tmp[32] = {0};
+
+u16 scan_ch_ms;
+#define SCAN_PARAM_INPUT_FMT "%hu"
+#define SCAN_PARAM_INPUT_ARG , &scan_ch_ms
+#ifdef CONFIG_80211N_HT
+	u8 rx_ampdu_accept;
+	u8 rx_ampdu_size;
+	#define SCAN_PARAM_INPUT_FMT_HT " %hhu %hhu"
+	#define SCAN_PARAM_INPUT_ARG_HT , &rx_ampdu_accept, &rx_ampdu_size
+#else
+	#define SCAN_PARAM_INPUT_FMT_HT ""
+	#define SCAN_PARAM_INPUT_ARG_HT
+#endif
+#ifdef CONFIG_SCAN_BACKOP
+	u16 backop_ms;
+	u8 scan_cnt_max;
+	#define SCAN_PARAM_INPUT_FMT_BACKOP " %hu %hhu"
+	#define SCAN_PARAM_INPUT_ARG_BACKOP , &backop_ms, &scan_cnt_max
+#else
+	#define SCAN_PARAM_INPUT_FMT_BACKOP ""
+	#define SCAN_PARAM_INPUT_ARG_BACKOP
+#endif
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp,
+			SCAN_PARAM_INPUT_FMT
+			SCAN_PARAM_INPUT_FMT_HT
+			SCAN_PARAM_INPUT_FMT_BACKOP
+			SCAN_PARAM_INPUT_ARG
+			SCAN_PARAM_INPUT_ARG_HT
+			SCAN_PARAM_INPUT_ARG_BACKOP
+		);
+
+		if (num-- > 0)
+			ss->scan_ch_ms = scan_ch_ms;
+		#ifdef CONFIG_80211N_HT
+		if (num-- > 0)
+			ss->rx_ampdu_accept = rx_ampdu_accept;
+		if (num-- > 0)
+			ss->rx_ampdu_size = rx_ampdu_size;
+		#endif
+		#ifdef CONFIG_SCAN_BACKOP
+		if (num-- > 0)
+			ss->backop_ms = backop_ms;
+		if (num-- > 0)
+			ss->scan_cnt_max = scan_cnt_max;
+		#endif
+	}
+	
+	return count;	
+}
+
+int proc_get_scan_abort(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	u32 pass_ms;
+
+	pass_ms = rtw_scan_abort_timeout(adapter, 10000);
+
+	DBG_871X_SEL_NL(m, "%u\n", pass_ms);
+
+	return 0;
+}
+
+#ifdef CONFIG_SCAN_BACKOP
+int proc_get_backop_flags_sta(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	DBG_871X_SEL_NL(m, "0x%02x\n", mlmeext_scan_backop_flags_sta(mlmeext));
+
+	return 0;
+}
+
+ssize_t proc_set_backop_flags_sta(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	char tmp[32];
+	u8 flags;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx", &flags);
+
+		if (num == 1)
+			mlmeext_assign_scan_backop_flags_sta(mlmeext, flags);
+	}
+	
+	return count;
+}
+
+int proc_get_backop_flags_ap(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	DBG_871X_SEL_NL(m, "0x%02x\n", mlmeext_scan_backop_flags_ap(mlmeext));
+
+	return 0;
+}
+
+ssize_t proc_set_backop_flags_ap(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+
+	char tmp[32];
+	u8 flags;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx", &flags);
+
+		if (num == 1)
+			mlmeext_assign_scan_backop_flags_ap(mlmeext, flags);
+	}
+	
+	return count;
+}
+
+#endif /* CONFIG_SCAN_BACKOP */
+
+int proc_get_survey_info(struct seq_file *m, void *v)
+{
+	_irqL irqL;
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	_queue	*queue	= &(pmlmepriv->scanned_queue);
+	struct wlan_network	*pnetwork = NULL;
+	_list	*plist, *phead;
+	s32 notify_signal;
+	s16 notify_noise = 0;
+	u16  index = 0, ie_cap = 0;
+	unsigned char *ie_wpa = NULL, *ie_wpa2 = NULL, *ie_wps = NULL;
+	unsigned char *ie_p2p = NULL, *ssid = NULL;
+	char flag_str[64];
+	int ielen = 0;
+	u32 wpsielen = 0;
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);	
+	phead = get_list_head(queue);
+	if(!phead)
+		return 0;
+	plist = get_next(phead);
+	if (!plist)
+		return 0;
+
+	DBG_871X_SEL_NL(m, "%5s  %-17s  %3s  %-3s  %-4s  %-4s  %5s  %32s  %32s\n", "index", "bssid", "ch", "RSSI", "SdBm", "Noise", "age", "flag", "ssid");
+	while(1)
+	{
+		if (rtw_end_of_queue_search(phead,plist)== _TRUE)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+                if (!pnetwork)
+			break;
+	
+		if ( check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE &&
+			is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) {
+			notify_signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);//dbm
+		} else {
+			notify_signal = translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);//dbm
+		}
+
+		#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
+		rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(pnetwork->network.Configuration.DSConfig), &(notify_noise));
+		#endif
+	
+		ie_wpa = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &ielen, pnetwork->network.IELength-12);	
+		ie_wpa2 = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &ielen, pnetwork->network.IELength-12);
+		ie_cap = rtw_get_capability(&pnetwork->network);
+		ie_wps = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength-12, NULL, &wpsielen);
+		ie_p2p = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength-12, NULL, &ielen);
+		ssid = pnetwork->network.Ssid.Ssid;
+		sprintf(flag_str, "%s%s%s%s%s%s%s",
+					(ie_wpa) ? "[WPA]":"",
+					(ie_wpa2) ? "[WPA2]":"",
+					(!ie_wpa && !ie_wpa && ie_cap & BIT(4)) ? "[WEP]":"",
+					(ie_wps) ? "[WPS]":"",
+					(pnetwork->network.InfrastructureMode == Ndis802_11IBSS) ? "[IBSS]":"",
+					(ie_cap & BIT(0)) ? "[ESS]":"",
+					(ie_p2p) ? "[P2P]":"");
+		DBG_871X_SEL_NL(m, "%5d  "MAC_FMT"  %3d  %3d  %4d  %4d    %5d  %32s  %32s\n", 
+			++index,
+			MAC_ARG(pnetwork->network.MacAddress), 
+			pnetwork->network.Configuration.DSConfig,
+			(int)pnetwork->network.Rssi,
+			notify_signal,
+			notify_noise,
+			rtw_get_passing_time_ms((u32)pnetwork->last_scanned),
+			flag_str,
+			pnetwork->network.Ssid.Ssid);
+		plist = get_next(plist);
+	}
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	return 0;
+}
+
+ssize_t proc_set_survey_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	_irqL irqL;
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	bool need_indicate_scan_done = _FALSE;
+	u8 _status = _FALSE;
+	NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT];
+
+	if (count < 1)
+		return -EFAULT;
+
+#ifdef CONFIG_MP_INCLUDED
+		if ((padapter->registrypriv.mp_mode == 1)
+#ifdef CONFIG_CONCURRENT_MODE
+		|| ((padapter->pbuddy_adapter) && (padapter->pbuddy_adapter->registrypriv.mp_mode == 1))
+#endif			
+		){
+			DBG_871X(FUNC_ADPT_FMT ": MP mode block Scan request\n", FUNC_ADPT_ARG(padapter));	
+			goto exit;
+		}
+#endif
+	rtw_ps_deny(padapter, PS_DENY_SCAN);
+	if (_FAIL == rtw_pwr_wakeup(padapter))
+		goto exit;
+
+	if (rtw_is_drv_stopped(padapter)) {
+		DBG_871X("scan abort!! bDriverStopped=_TRUE\n");
+		goto exit;
+	}
+	
+	if (!padapter->bup) {
+		DBG_871X("scan abort!! bup=%d\n", padapter->bup);
+		goto exit;
+	}
+	
+	if (!rtw_is_hw_init_completed(padapter)) {
+		DBG_871X("scan abort!! hw_init_completed=FALSE\n");
+		goto exit;
+	}
+	
+	if (rtw_is_scan_deny(padapter)) {
+		DBG_871X(FUNC_ADPT_FMT  ": scan deny\n", FUNC_ADPT_ARG(padapter));
+		goto exit;
+	}
+	
+	if ((pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE)
+#ifdef CONFIG_CONCURRENT_MODE
+	|| (rtw_get_buddy_bBusyTraffic(padapter) == _TRUE)
+#endif
+	) {
+		DBG_871X("scan abort!! BusyTraffic == _TRUE\n");
+		goto exit;
+	}
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) {
+		DBG_8192C("scan abort!! fwstate=0x%x\n", pmlmepriv->fw_state);
+		goto exit;
+	}
+
+#ifdef CONFIG_CONCURRENT_MODE
+	if (check_buddy_fwstate(padapter,
+		_FW_UNDER_SURVEY|_FW_UNDER_LINKING|WIFI_UNDER_WPS) == _TRUE) {
+		DBG_871X("scan abort!! buddy_fwstate=0x%x\n",
+				get_fwstate(&(padapter->pbuddy_adapter->mlmepriv)));
+		goto exit;
+	}
+#endif
+	_status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
+
+exit:
+	rtw_ps_deny_cancel(padapter, PS_DENY_SCAN);
+	return count;
+}
+
+int proc_get_ap_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	struct sta_info *psta;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+	if(psta)
+	{
+		int i;
+		struct recv_reorder_ctrl *preorder_ctrl;
+					
+		DBG_871X_SEL_NL(m, "SSID=%s\n", cur_network->network.Ssid.Ssid);		
+		DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr));
+		DBG_871X_SEL_NL(m, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);		
+		DBG_871X_SEL_NL(m, "wireless_mode=0x%x, rtsen=%d, cts2slef=%d\n", psta->wireless_mode, psta->rtsen, psta->cts2self);
+		DBG_871X_SEL_NL(m, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+#ifdef CONFIG_80211N_HT
+		DBG_871X_SEL_NL(m, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);		
+		DBG_871X_SEL_NL(m, "bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m);
+		DBG_871X_SEL_NL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);	
+		DBG_871X_SEL_NL(m, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+		DBG_871X_SEL_NL(m, "ldpc_cap=0x%x, stbc_cap=0x%x, beamform_cap=0x%x\n", psta->htpriv.ldpc_cap, psta->htpriv.stbc_cap, psta->htpriv.beamform_cap);
+#endif //CONFIG_80211N_HT
+#ifdef CONFIG_80211AC_VHT
+		DBG_871X_SEL_NL(m, "vht_en=%d, vht_sgi_80m=%d\n", psta->vhtpriv.vht_option, psta->vhtpriv.sgi_80m);
+		DBG_871X_SEL_NL(m, "vht_ldpc_cap=0x%x, vht_stbc_cap=0x%x, vht_beamform_cap=0x%x\n", psta->vhtpriv.ldpc_cap, psta->vhtpriv.stbc_cap, psta->vhtpriv.beamform_cap);
+		DBG_871X_SEL_NL(m, "vht_mcs_map=0x%x, vht_highest_rate=0x%x, vht_ampdu_len=%d\n", *(u16*)psta->vhtpriv.vht_mcs_map, psta->vhtpriv.vht_highest_rate, psta->vhtpriv.ampdu_len);
+#endif
+
+		sta_rx_reorder_ctl_dump(m, psta);
+	}
+	else
+	{							
+		DBG_871X_SEL_NL(m, "can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress));
+	}
+
+	return 0;
+}
+
+ssize_t proc_reset_trx_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct dvobj_priv *psdpriv = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+	char cmd[32] = {'0'};
+
+	if (count > sizeof(cmd)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(cmd, buffer, count)) {
+		if('0' == cmd[0]){
+			pdbgpriv->dbg_rx_ampdu_drop_count = 0;
+			pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0;
+			pdbgpriv->dbg_rx_ampdu_loss_count = 0;
+			pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0;
+			pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0;
+			pdbgpriv->dbg_rx_conflic_mac_addr_cnt = 0;
+		}
+	}
+
+	return count;
+}
+	
+int proc_get_trx_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	int i;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct recv_priv  *precvpriv = &padapter->recvpriv;
+	struct dvobj_priv *psdpriv = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+	struct hw_xmit *phwxmit;
+
+	dump_os_queue(m, padapter);
+
+	DBG_871X_SEL_NL(m, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d\n"
+		, pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt);
+	DBG_871X_SEL_NL(m, "free_ext_xmitbuf_cnt=%d, free_xframe_ext_cnt=%d\n"
+		, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt);
+	DBG_871X_SEL_NL(m, "free_recvframe_cnt=%d\n"
+		, precvpriv->free_recvframe_cnt);
+
+	for(i = 0; i < 4; i++) 
+	{
+		phwxmit = pxmitpriv->hwxmits + i;
+		DBG_871X_SEL_NL(m, "%d, hwq.accnt=%d\n", i, phwxmit->accnt);
+	}
+
+#ifdef CONFIG_USB_HCI
+	DBG_871X_SEL_NL(m, "rx_urb_pending_cn=%d\n", ATOMIC_READ(&(precvpriv->rx_pending_cnt)));
+#endif
+
+	//Folowing are RX info
+	//Counts of packets whose seq_num is less than preorder_ctrl->indicate_seq, Ex delay, retransmission, redundant packets and so on
+	DBG_871X_SEL_NL(m,"Rx: Counts of Packets Whose Seq_Num Less Than Reorder Control Seq_Num: %llu\n",(unsigned long long)pdbgpriv->dbg_rx_ampdu_drop_count);
+	//How many times the Rx Reorder Timer is triggered.
+	DBG_871X_SEL_NL(m,"Rx: Reorder Time-out Trigger Counts: %llu\n",(unsigned long long)pdbgpriv->dbg_rx_ampdu_forced_indicate_count);
+	//Total counts of packets loss
+	DBG_871X_SEL_NL(m,"Rx: Packet Loss Counts: %llu\n",(unsigned long long)pdbgpriv->dbg_rx_ampdu_loss_count);
+	DBG_871X_SEL_NL(m,"Rx: Duplicate Management Frame Drop Count: %llu\n",(unsigned long long)pdbgpriv->dbg_rx_dup_mgt_frame_drop_count);
+	DBG_871X_SEL_NL(m,"Rx: AMPDU BA window shift Count: %llu\n",(unsigned long long)pdbgpriv->dbg_rx_ampdu_window_shift_cnt);
+	/*The same mac addr counts*/
+	DBG_871X_SEL_NL(m, "Rx: Conflict MAC Address Frames Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_conflic_mac_addr_cnt);
+	return 0;
+}
+
+int proc_get_dis_pwt(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	u8 dis_pwt = 0;
+	rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DIS_PWT, &(dis_pwt));
+	DBG_871X_SEL_NL(m, " Tx Power training mode:%s \n",(dis_pwt==_TRUE)?"Disable":"Enable");
+	return 0;
+}
+ssize_t proc_set_dis_pwt(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[4]={0};
+	u8 dis_pwt = 0;
+	
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx", &dis_pwt);
+		DBG_871X("Set Tx Power training mode:%s\n", (dis_pwt == _TRUE)?"Disable":"Enable");
+		
+		if (num >= 1)
+			rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DIS_PWT, &(dis_pwt));
+	}
+
+	return count;
+	
+}
+
+int proc_get_rate_ctl(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	int i;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	u8 data_rate = 0, sgi=0, data_fb = 0;
+		
+	if (adapter->fix_rate != 0xff) {
+		data_rate = adapter->fix_rate & 0x7F;
+		sgi = adapter->fix_rate >>7;
+		data_fb = adapter->data_fb?1:0;
+		DBG_871X_SEL_NL(m, "FIXED %s%s%s\n"
+			, HDATA_RATE(data_rate)
+			, data_rate>DESC_RATE54M?(sgi?" SGI":" LGI"):""
+			, data_fb?" FB":""
+		);
+		DBG_871X_SEL_NL(m, "0x%02x %u\n", adapter->fix_rate, adapter->data_fb);
+	} else {
+		DBG_871X_SEL_NL(m, "RA\n");
+	}
+
+	return 0;
+}
+
+ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u8 fix_rate;
+	u8 data_fb;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx %hhu", &fix_rate, &data_fb);
+
+		if (num >= 1)
+			adapter->fix_rate = fix_rate;
+		if (num >= 2)
+			adapter->data_fb = data_fb?1:0;
+	}
+
+	return count;
+}
+#ifdef DBG_RX_COUNTER_DUMP
+int proc_get_rx_cnt_dump(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	int i;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+	DBG_871X_SEL_NL(m, "BIT0- Dump RX counters of DRV \n");
+	DBG_871X_SEL_NL(m, "BIT1- Dump RX counters of MAC \n");
+	DBG_871X_SEL_NL(m, "BIT2- Dump RX counters of PHY \n");
+	DBG_871X_SEL_NL(m, "BIT3- Dump TRX data frame of DRV \n");
+	DBG_871X_SEL_NL(m, "dump_rx_cnt_mode = 0x%02x \n", adapter->dump_rx_cnt_mode);
+
+	return 0;
+}
+ssize_t proc_set_rx_cnt_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u8 dump_rx_cnt_mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhx", &dump_rx_cnt_mode);
+
+		rtw_dump_phy_rxcnts_preprocess(adapter,dump_rx_cnt_mode);
+		adapter->dump_rx_cnt_mode = dump_rx_cnt_mode;
+		
+	}
+
+	return count;
+}
+#endif
+ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	int num;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count))
+		num = sscanf(tmp, "%hhu %hhu", &fwdl_test_chksum_fail, &fwdl_test_wintint_rdy_fail);
+
+	return count;
+}
+
+ssize_t proc_set_del_rx_ampdu_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	int num;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count))
+		num = sscanf(tmp, "%hhu", &del_rx_ampdu_test_no_tx_fail);
+
+	return count;
+}
+
+#ifdef CONFIG_DFS_MASTER
+int proc_get_dfs_master_test_case(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+
+	DBG_871X_SEL_NL(m, "%-24s %-19s\n", "radar_detect_trigger_non", "choose_dfs_ch_first");
+	DBG_871X_SEL_NL(m, "%24hhu %19hhu\n"
+		, rfctl->dbg_dfs_master_radar_detect_trigger_non
+		, rfctl->dbg_dfs_master_choose_dfs_ch_first
+	);
+
+	return 0;
+}
+
+ssize_t proc_set_dfs_master_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+	struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+	char tmp[32];
+	u8 radar_detect_trigger_non;
+	u8 choose_dfs_ch_first;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+		int num = sscanf(tmp, "%hhu %hhu", &radar_detect_trigger_non, &choose_dfs_ch_first);
+
+		if (num >= 1)
+			rfctl->dbg_dfs_master_radar_detect_trigger_non = radar_detect_trigger_non;
+		if (num >= 2)
+			rfctl->dbg_dfs_master_choose_dfs_ch_first = choose_dfs_ch_first;
+	}
+
+	return count;
+}
+#endif /* CONFIG_DFS_MASTER */
+
+ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	int num;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count))
+		num = sscanf(tmp, "%u", &g_wait_hiq_empty_ms);
+
+	return count;
+}
+
+int proc_get_suspend_resume_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct dvobj_priv *dvobj = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
+
+	DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_cnt=%d\n", pdbgpriv->dbg_sdio_alloc_irq_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_cnt=%d\n", pdbgpriv->dbg_sdio_free_irq_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sdio_alloc_irq_error_cnt=%d\n",pdbgpriv->dbg_sdio_alloc_irq_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sdio_free_irq_error_cnt=%d\n", pdbgpriv->dbg_sdio_free_irq_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sdio_init_error_cnt=%d\n",pdbgpriv->dbg_sdio_init_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sdio_deinit_error_cnt=%d\n", pdbgpriv->dbg_sdio_deinit_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_suspend_error_cnt=%d\n", pdbgpriv->dbg_suspend_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_suspend_cnt=%d\n",pdbgpriv->dbg_suspend_cnt);
+	DBG_871X_SEL_NL(m, "dbg_resume_cnt=%d\n", pdbgpriv->dbg_resume_cnt);
+	DBG_871X_SEL_NL(m, "dbg_resume_error_cnt=%d\n", pdbgpriv->dbg_resume_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_deinit_fail_cnt=%d\n",pdbgpriv->dbg_deinit_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_carddisable_cnt=%d\n", pdbgpriv->dbg_carddisable_cnt);
+	DBG_871X_SEL_NL(m, "dbg_ps_insuspend_cnt=%d\n",pdbgpriv->dbg_ps_insuspend_cnt);
+	DBG_871X_SEL_NL(m, "dbg_dev_unload_inIPS_cnt=%d\n", pdbgpriv->dbg_dev_unload_inIPS_cnt);
+	DBG_871X_SEL_NL(m, "dbg_scan_pwr_state_cnt=%d\n", pdbgpriv->dbg_scan_pwr_state_cnt);
+	DBG_871X_SEL_NL(m, "dbg_downloadfw_pwr_state_cnt=%d\n", pdbgpriv->dbg_downloadfw_pwr_state_cnt);
+	DBG_871X_SEL_NL(m, "dbg_carddisable_error_cnt=%d\n", pdbgpriv->dbg_carddisable_error_cnt);
+	DBG_871X_SEL_NL(m, "dbg_fw_read_ps_state_fail_cnt=%d\n", pdbgpriv->dbg_fw_read_ps_state_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_leave_ips_fail_cnt=%d\n", pdbgpriv->dbg_leave_ips_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_leave_lps_fail_cnt=%d\n", pdbgpriv->dbg_leave_lps_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_h2c_leave32k_fail_cnt=%d\n", pdbgpriv->dbg_h2c_leave32k_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_diswow_dload_fw_fail_cnt=%d\n", pdbgpriv->dbg_diswow_dload_fw_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_enwow_dload_fw_fail_cnt=%d\n", pdbgpriv->dbg_enwow_dload_fw_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_ips_drvopen_fail_cnt=%d\n", pdbgpriv->dbg_ips_drvopen_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_poll_fail_cnt=%d\n", pdbgpriv->dbg_poll_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_rpwm_toogle_cnt=%d\n", pdbgpriv->dbg_rpwm_toogle_cnt);
+	DBG_871X_SEL_NL(m, "dbg_rpwm_timeout_fail_cnt=%d\n", pdbgpriv->dbg_rpwm_timeout_fail_cnt);
+	DBG_871X_SEL_NL(m, "dbg_sreset_cnt=%d\n", pdbgpriv->dbg_sreset_cnt);
+
+	return 0;
+}
+
+#ifdef CONFIG_DBG_COUNTER
+
+int proc_get_rx_logs(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct rx_logs *rx_logs = &padapter->rx_logs;
+
+	DBG_871X_SEL_NL(m, 
+		"intf_rx=%d\n"
+		"intf_rx_err_recvframe=%d\n"
+		"intf_rx_err_skb=%d\n"
+		"intf_rx_report=%d\n"
+		"core_rx=%d\n"
+		"core_rx_pre=%d\n"
+		"core_rx_pre_ver_err=%d\n"
+		"core_rx_pre_mgmt=%d\n"
+		"core_rx_pre_mgmt_err_80211w=%d\n"
+		"core_rx_pre_mgmt_err=%d\n"
+		"core_rx_pre_ctrl=%d\n"
+		"core_rx_pre_ctrl_err=%d\n"
+		"core_rx_pre_data=%d\n"
+		"core_rx_pre_data_wapi_seq_err=%d\n"
+		"core_rx_pre_data_wapi_key_err=%d\n"
+		"core_rx_pre_data_handled=%d\n"
+		"core_rx_pre_data_err=%d\n"
+		"core_rx_pre_data_unknown=%d\n"
+		"core_rx_pre_unknown=%d\n"
+		"core_rx_enqueue=%d\n"
+		"core_rx_dequeue=%d\n"
+		"core_rx_post=%d\n"
+		"core_rx_post_decrypt=%d\n"
+		"core_rx_post_decrypt_wep=%d\n"
+		"core_rx_post_decrypt_tkip=%d\n"
+		"core_rx_post_decrypt_aes=%d\n"
+		"core_rx_post_decrypt_wapi=%d\n"
+		"core_rx_post_decrypt_hw=%d\n"
+		"core_rx_post_decrypt_unknown=%d\n"
+		"core_rx_post_decrypt_err=%d\n"
+		"core_rx_post_defrag_err=%d\n"
+		"core_rx_post_portctrl_err=%d\n"
+		"core_rx_post_indicate=%d\n"
+		"core_rx_post_indicate_in_oder=%d\n"
+		"core_rx_post_indicate_reoder=%d\n"
+		"core_rx_post_indicate_err=%d\n"
+		"os_indicate=%d\n"
+		"os_indicate_ap_mcast=%d\n"
+		"os_indicate_ap_forward=%d\n"
+		"os_indicate_ap_self=%d\n"
+		"os_indicate_err=%d\n"
+		"os_netif_ok=%d\n"
+		"os_netif_err=%d\n",
+		rx_logs->intf_rx,
+		rx_logs->intf_rx_err_recvframe,
+		rx_logs->intf_rx_err_skb,
+		rx_logs->intf_rx_report,
+		rx_logs->core_rx,
+		rx_logs->core_rx_pre,
+		rx_logs->core_rx_pre_ver_err,
+		rx_logs->core_rx_pre_mgmt,
+		rx_logs->core_rx_pre_mgmt_err_80211w,
+		rx_logs->core_rx_pre_mgmt_err,
+		rx_logs->core_rx_pre_ctrl,
+		rx_logs->core_rx_pre_ctrl_err,
+		rx_logs->core_rx_pre_data,
+		rx_logs->core_rx_pre_data_wapi_seq_err,
+		rx_logs->core_rx_pre_data_wapi_key_err,
+		rx_logs->core_rx_pre_data_handled,
+		rx_logs->core_rx_pre_data_err,
+		rx_logs->core_rx_pre_data_unknown,
+		rx_logs->core_rx_pre_unknown,
+		rx_logs->core_rx_enqueue,
+		rx_logs->core_rx_dequeue,
+		rx_logs->core_rx_post,
+		rx_logs->core_rx_post_decrypt,
+		rx_logs->core_rx_post_decrypt_wep,
+		rx_logs->core_rx_post_decrypt_tkip,
+		rx_logs->core_rx_post_decrypt_aes,
+		rx_logs->core_rx_post_decrypt_wapi,
+		rx_logs->core_rx_post_decrypt_hw,
+		rx_logs->core_rx_post_decrypt_unknown,
+		rx_logs->core_rx_post_decrypt_err,
+		rx_logs->core_rx_post_defrag_err,
+		rx_logs->core_rx_post_portctrl_err,
+		rx_logs->core_rx_post_indicate,
+		rx_logs->core_rx_post_indicate_in_oder,
+		rx_logs->core_rx_post_indicate_reoder,
+		rx_logs->core_rx_post_indicate_err,
+		rx_logs->os_indicate,
+		rx_logs->os_indicate_ap_mcast,
+		rx_logs->os_indicate_ap_forward,
+		rx_logs->os_indicate_ap_self,
+		rx_logs->os_indicate_err,
+		rx_logs->os_netif_ok,
+		rx_logs->os_netif_err
+	);
+
+	return 0;
+}
+
+int proc_get_tx_logs(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct tx_logs *tx_logs = &padapter->tx_logs;
+	
+	DBG_871X_SEL_NL(m,
+		"os_tx=%d\n"
+		"os_tx_err_up=%d\n"
+		"os_tx_err_xmit=%d\n"
+		"os_tx_m2u=%d\n"
+		"os_tx_m2u_ignore_fw_linked=%d\n"
+		"os_tx_m2u_ignore_self=%d\n"
+		"os_tx_m2u_entry=%d\n"
+		"os_tx_m2u_entry_err_xmit=%d\n"
+		"os_tx_m2u_entry_err_skb=%d\n"
+		"os_tx_m2u_stop=%d\n"
+		"core_tx=%d\n"
+		"core_tx_err_pxmitframe=%d\n"
+		"core_tx_err_brtx=%d\n"
+		"core_tx_upd_attrib=%d\n"
+		"core_tx_upd_attrib_adhoc=%d\n"
+		"core_tx_upd_attrib_sta=%d\n"
+		"core_tx_upd_attrib_ap=%d\n"
+		"core_tx_upd_attrib_unknown=%d\n"
+		"core_tx_upd_attrib_dhcp=%d\n"
+		"core_tx_upd_attrib_icmp=%d\n"
+		"core_tx_upd_attrib_active=%d\n"
+		"core_tx_upd_attrib_err_ucast_sta=%d\n"
+		"core_tx_upd_attrib_err_ucast_ap_link=%d\n"
+		"core_tx_upd_attrib_err_sta=%d\n"
+		"core_tx_upd_attrib_err_link=%d\n"
+		"core_tx_upd_attrib_err_sec=%d\n"
+		"core_tx_ap_enqueue_warn_fwstate=%d\n"
+		"core_tx_ap_enqueue_warn_sta=%d\n"
+		"core_tx_ap_enqueue_warn_nosta=%d\n"
+		"core_tx_ap_enqueue_warn_link=%d\n"
+		"core_tx_ap_enqueue_warn_trigger=%d\n"
+		"core_tx_ap_enqueue_mcast=%d\n"
+		"core_tx_ap_enqueue_ucast=%d\n"
+		"core_tx_ap_enqueue=%d\n"
+		"intf_tx=%d\n"
+		"intf_tx_pending_ac=%d\n"
+		"intf_tx_pending_fw_under_survey=%d\n"
+		"intf_tx_pending_fw_under_linking=%d\n"
+		"intf_tx_pending_xmitbuf=%d\n"
+		"intf_tx_enqueue=%d\n"
+		"core_tx_enqueue=%d\n"
+		"core_tx_enqueue_class=%d\n"
+		"core_tx_enqueue_class_err_sta=%d\n"
+		"core_tx_enqueue_class_err_nosta=%d\n"
+		"core_tx_enqueue_class_err_fwlink=%d\n"
+		"intf_tx_direct=%d\n"
+		"intf_tx_direct_err_coalesce=%d\n"
+		"intf_tx_dequeue=%d\n"
+		"intf_tx_dequeue_err_coalesce=%d\n"
+		"intf_tx_dump_xframe=%d\n"
+		"intf_tx_dump_xframe_err_txdesc=%d\n"
+		"intf_tx_dump_xframe_err_port=%d\n",
+		tx_logs->os_tx,
+		tx_logs->os_tx_err_up,
+		tx_logs->os_tx_err_xmit,
+		tx_logs->os_tx_m2u,
+		tx_logs->os_tx_m2u_ignore_fw_linked,
+		tx_logs->os_tx_m2u_ignore_self,
+		tx_logs->os_tx_m2u_entry,
+		tx_logs->os_tx_m2u_entry_err_xmit,
+		tx_logs->os_tx_m2u_entry_err_skb,
+		tx_logs->os_tx_m2u_stop,
+		tx_logs->core_tx,
+		tx_logs->core_tx_err_pxmitframe,
+		tx_logs->core_tx_err_brtx,
+		tx_logs->core_tx_upd_attrib,
+		tx_logs->core_tx_upd_attrib_adhoc,
+		tx_logs->core_tx_upd_attrib_sta,
+		tx_logs->core_tx_upd_attrib_ap,
+		tx_logs->core_tx_upd_attrib_unknown,
+		tx_logs->core_tx_upd_attrib_dhcp,
+		tx_logs->core_tx_upd_attrib_icmp,
+		tx_logs->core_tx_upd_attrib_active,
+		tx_logs->core_tx_upd_attrib_err_ucast_sta,
+		tx_logs->core_tx_upd_attrib_err_ucast_ap_link,
+		tx_logs->core_tx_upd_attrib_err_sta,
+		tx_logs->core_tx_upd_attrib_err_link,
+		tx_logs->core_tx_upd_attrib_err_sec,
+		tx_logs->core_tx_ap_enqueue_warn_fwstate,
+		tx_logs->core_tx_ap_enqueue_warn_sta,
+		tx_logs->core_tx_ap_enqueue_warn_nosta,
+		tx_logs->core_tx_ap_enqueue_warn_link,
+		tx_logs->core_tx_ap_enqueue_warn_trigger,
+		tx_logs->core_tx_ap_enqueue_mcast,
+		tx_logs->core_tx_ap_enqueue_ucast,
+		tx_logs->core_tx_ap_enqueue,
+		tx_logs->intf_tx,
+		tx_logs->intf_tx_pending_ac,
+		tx_logs->intf_tx_pending_fw_under_survey,
+		tx_logs->intf_tx_pending_fw_under_linking,
+		tx_logs->intf_tx_pending_xmitbuf,
+		tx_logs->intf_tx_enqueue,
+		tx_logs->core_tx_enqueue,
+		tx_logs->core_tx_enqueue_class,
+		tx_logs->core_tx_enqueue_class_err_sta,
+		tx_logs->core_tx_enqueue_class_err_nosta,
+		tx_logs->core_tx_enqueue_class_err_fwlink,
+		tx_logs->intf_tx_direct,
+		tx_logs->intf_tx_direct_err_coalesce,
+		tx_logs->intf_tx_dequeue,
+		tx_logs->intf_tx_dequeue_err_coalesce,
+		tx_logs->intf_tx_dump_xframe,
+		tx_logs->intf_tx_dump_xframe_err_txdesc,
+		tx_logs->intf_tx_dump_xframe_err_port
+	);
+
+	return 0;
+}
+
+int proc_get_int_logs(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+	DBG_871X_SEL_NL(m,
+		"all=%d\n"
+		"err=%d\n"
+		"tbdok=%d\n"
+		"tbder=%d\n"
+		"bcnderr=%d\n"
+		"bcndma=%d\n"
+		"bcndma_e=%d\n"
+		"rx=%d\n"
+		"rx_rdu=%d\n"
+		"rx_fovw=%d\n"
+		"txfovw=%d\n"
+		"mgntok=%d\n"
+		"highdok=%d\n"
+		"bkdok=%d\n"
+		"bedok=%d\n"
+		"vidok=%d\n"
+		"vodok=%d\n",
+		padapter->int_logs.all,
+		padapter->int_logs.err,
+		padapter->int_logs.tbdok,
+		padapter->int_logs.tbder,
+		padapter->int_logs.bcnderr,
+		padapter->int_logs.bcndma,
+		padapter->int_logs.bcndma_e,
+		padapter->int_logs.rx,
+		padapter->int_logs.rx_rdu,
+		padapter->int_logs.rx_fovw,
+		padapter->int_logs.txfovw,
+		padapter->int_logs.mgntok,
+		padapter->int_logs.highdok,
+		padapter->int_logs.bkdok,
+		padapter->int_logs.bedok,
+		padapter->int_logs.vidok,
+		padapter->int_logs.vodok
+	);
+
+	return 0;
+}
+
+#endif // CONFIG_DBG_COUNTER
+
+int proc_get_hw_status(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct dvobj_priv *dvobj = padapter->dvobj;
+	struct debug_priv *pdbgpriv = &dvobj->drv_dbg;
+
+	if (pdbgpriv->dbg_rx_fifo_last_overflow == 1
+		&& pdbgpriv->dbg_rx_fifo_curr_overflow == 1
+		&& pdbgpriv->dbg_rx_fifo_diff_overflow == 1
+	) {
+		DBG_871X_SEL_NL(m, "RX FIFO full count: no implementation\n");
+	} else {
+		DBG_871X_SEL_NL(m, "RX FIFO full count: last_time=%llu, current_time=%llu, differential=%llu\n"
+			, pdbgpriv->dbg_rx_fifo_last_overflow, pdbgpriv->dbg_rx_fifo_curr_overflow, pdbgpriv->dbg_rx_fifo_diff_overflow);
+	}
+
+	return 0;
+}
+
+int proc_get_rx_signal(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	DBG_871X_SEL_NL(m, "rssi:%d\n", padapter->recvpriv.rssi);
+	//DBG_871X_SEL_NL(m, "rxpwdb:%d\n", padapter->recvpriv.rxpwdb);
+	DBG_871X_SEL_NL(m, "signal_strength:%u\n", padapter->recvpriv.signal_strength);
+	DBG_871X_SEL_NL(m, "signal_qual:%u\n", padapter->recvpriv.signal_qual);
+
+	rtw_get_noise(padapter);
+	DBG_871X_SEL_NL(m, "noise:%d\n", padapter->recvpriv.noise);
+	#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
+	rtw_odm_get_perpkt_rssi(m,padapter);
+	rtw_get_raw_rssi_info(m,padapter);
+	#endif
+	return 0;
+}
+
+ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 is_signal_dbg, signal_strength;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength);
+
+		is_signal_dbg = is_signal_dbg==0?0:1;
+		
+		if(is_signal_dbg && num!=2)
+			return count;
+			
+		signal_strength = signal_strength>100?100:signal_strength;
+
+		padapter->recvpriv.is_signal_dbg = is_signal_dbg;
+		padapter->recvpriv.signal_strength_dbg=signal_strength;
+
+		if(is_signal_dbg)
+			DBG_871X("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength);
+		else
+			DBG_871X("set %s\n", "HW_SIGNAL_STRENGTH");
+		
+	}
+	
+	return count;
+	
+}
+#ifdef CONFIG_80211N_HT
+
+int proc_get_ht_enable(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	if(pregpriv)
+		DBG_871X_SEL_NL(m, "%d\n", pregpriv->ht_enable);
+
+	return 0;
+}
+
+ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	u32 mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &mode);
+
+		if( pregpriv && mode < 2 )
+		{
+			pregpriv->ht_enable= mode;
+			DBG_871X("ht_enable=%d\n", pregpriv->ht_enable);
+		}
+	}
+	
+	return count;
+	
+}
+
+int proc_get_bw_mode(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	if(pregpriv)
+		DBG_871X_SEL_NL(m, "0x%02x\n", pregpriv->bw_mode);
+
+	return 0;
+}
+
+ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	u32 mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &mode);
+
+		if( pregpriv &&  mode < 2 )
+		{
+
+			pregpriv->bw_mode = mode;
+			printk("bw_mode=%d\n", mode);
+
+		}
+	}
+	
+	return count;
+	
+}
+
+int proc_get_ampdu_enable(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	if(pregpriv)
+		DBG_871X_SEL_NL(m, "%d\n", pregpriv->ampdu_enable);
+
+	return 0;
+}
+
+ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	u32 mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &mode);
+
+		if( pregpriv && mode < 3 )
+		{
+			pregpriv->ampdu_enable= mode;
+			printk("ampdu_enable=%d\n", mode);
+		}
+
+	}
+	
+	return count;
+	
+}
+
+int proc_get_mac_rptbuf(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	u16 i;
+	u16 mac_id;
+	u32 shcut_addr = 0;
+	u32 read_addr = 0;
+#ifdef CONFIG_RTL8814A
+	DBG_871X_SEL_NL(m, "TX ShortCut:\n");
+	for (mac_id = 0; mac_id < 64; mac_id++) {
+		rtw_write16(padapter, 0x140, 0x662 | ((mac_id & BIT5)>>5));
+		shcut_addr = 0x8000;
+		shcut_addr = shcut_addr | ((mac_id&0x1f) << 7);
+		DBG_871X_SEL_NL(m, "mac_id=%d, 0x140=%x =>\n", mac_id, 0x662 | ((mac_id & BIT5)>>5));
+		for (i = 0; i < 30; i++) {
+			read_addr = 0;
+			read_addr = shcut_addr | (i<<2);
+			DBG_871X_SEL_NL(m, "i=%02d: MAC_%04x= %08x ", i, read_addr, rtw_read32(padapter, read_addr));
+			if (!((i+1) % 4))
+				DBG_871X_SEL_NL(m, "\n");
+			if (i == 29)
+				DBG_871X_SEL_NL(m, "\n");
+		}
+	}
+#endif /* CONFIG_RTL8814A */
+	return 0;
+}
+
+
+int proc_get_rx_ampdu(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+	DBG_871X_SEL(m, "accept: ");
+	if (padapter->fix_rx_ampdu_accept == RX_AMPDU_ACCEPT_INVALID)
+		DBG_871X_SEL_NL(m, "%u%s\n", rtw_rx_ampdu_is_accept(padapter), "(auto)");
+	else
+		DBG_871X_SEL_NL(m, "%u%s\n", padapter->fix_rx_ampdu_accept, "(fixed)");
+
+	DBG_871X_SEL(m, "size: ");
+	if (padapter->fix_rx_ampdu_size == RX_AMPDU_SIZE_INVALID)
+		DBG_871X_SEL_NL(m, "%u%s\n", rtw_rx_ampdu_size(padapter), "(auto)");
+	else
+		DBG_871X_SEL_NL(m, "%u%s\n", padapter->fix_rx_ampdu_size, "(fixed)");
+
+	DBG_871X_SEL_NL(m, "%19s %17s\n", "fix_rx_ampdu_accept", "fix_rx_ampdu_size");
+
+	DBG_871X_SEL(m, "%-19d %-17u\n"
+		, padapter->fix_rx_ampdu_accept
+		, padapter->fix_rx_ampdu_size);
+
+	return 0;
+}
+
+ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	char tmp[32];
+	u8 accept;
+	u8 size;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%hhu %hhu", &accept, &size);
+
+		if (num >= 1)
+			rtw_rx_ampdu_set_accept(padapter, accept, RX_AMPDU_DRV_FIXED);
+		if (num >= 2)
+			rtw_rx_ampdu_set_size(padapter, size, RX_AMPDU_DRV_FIXED);
+
+		rtw_rx_ampdu_apply(padapter);
+	}
+
+exit:
+	return count;
+}
+int proc_get_rx_ampdu_factor(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+	if(padapter)
+	{
+		DBG_871X_SEL_NL(m,"rx ampdu factor = %x\n",padapter->driver_rx_ampdu_factor);
+	}
+	
+	return 0;
+}
+
+ssize_t proc_set_rx_ampdu_factor(struct file *file, const char __user *buffer
+                                 , size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 factor;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &factor);
+
+		if( padapter && (num == 1) )
+		{
+			DBG_871X("padapter->driver_rx_ampdu_factor = %x\n", factor);
+
+			if(factor  > 0x03)
+				padapter->driver_rx_ampdu_factor = 0xFF;
+			else
+				padapter->driver_rx_ampdu_factor = factor;			
+		}
+	}
+
+	return count;
+}
+
+int proc_get_rx_ampdu_density(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+	if(padapter)
+	{
+		DBG_871X_SEL_NL(m,"rx ampdu densityg = %x\n",padapter->driver_rx_ampdu_spacing);
+	}
+
+	return 0;
+}
+
+ssize_t proc_set_rx_ampdu_density(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 density;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &density);
+
+		if( padapter && (num == 1) )
+		{
+			DBG_871X("padapter->driver_rx_ampdu_spacing = %x\n", density);
+
+			if(density > 0x07)
+				padapter->driver_rx_ampdu_spacing = 0xFF;
+			else
+				padapter->driver_rx_ampdu_spacing = density;
+		}
+	}
+
+	return count;
+}
+
+int proc_get_tx_ampdu_density(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+	if(padapter)
+	{
+		DBG_871X_SEL_NL(m,"tx ampdu density = %x\n",padapter->driver_ampdu_spacing);
+	}
+
+	return 0;
+}
+
+ssize_t proc_set_tx_ampdu_density(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 density;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &density);
+
+		if( padapter && (num == 1) )
+		{
+			DBG_871X("padapter->driver_ampdu_spacing = %x\n", density);
+
+			if(density > 0x07)
+				padapter->driver_ampdu_spacing = 0xFF;
+			else
+				padapter->driver_ampdu_spacing = density;
+		}
+	}
+
+	return count;
+}
+#endif //CONFIG_80211N_HT
+
+int proc_get_en_fwps(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if(pregpriv)
+		DBG_871X_SEL_NL(m, "check_fw_ps = %d , 1:enable get FW PS state , 0: disable get FW PS state\n"
+			, pregpriv->check_fw_ps);
+
+	return 0;
+}
+
+ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	char tmp[32];
+	u32 mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &mode);
+
+		if( pregpriv &&  mode < 2 )
+		{
+			pregpriv->check_fw_ps = mode;
+			DBG_871X("pregpriv->check_fw_ps=%d \n",pregpriv->check_fw_ps);
+		}
+
+	}
+
+	return count;
+}
+
+/*
+int proc_get_two_path_rssi(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+	if(padapter)
+		DBG_871X_SEL_NL(m, "%d %d\n",
+			padapter->recvpriv.RxRssi[0], padapter->recvpriv.RxRssi[1]);
+
+	return 0;
+}
+*/
+#ifdef CONFIG_80211N_HT
+int proc_get_rx_stbc(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	if(pregpriv)
+		DBG_871X_SEL_NL(m, "%d\n", pregpriv->rx_stbc);
+
+	return 0;
+}
+
+ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	u32 mode;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d ", &mode);
+
+		if( pregpriv && (mode == 0 || mode == 1|| mode == 2|| mode == 3))
+		{
+			pregpriv->rx_stbc= mode;
+			printk("rx_stbc=%d\n", mode);
+		}
+	}
+	
+	return count;
+	
+}
+#endif //CONFIG_80211N_HT
+
+/*int proc_get_rssi_disp(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	return 0;
+}
+*/
+
+/*ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 enable=0;
+
+	if (count < 1)
+	{
+		DBG_8192C("argument size is less than 1\n");
+		return -EFAULT;
+	}	
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%x", &enable);
+
+		if (num !=  1) {
+			DBG_8192C("invalid set_rssi_disp parameter!\n");
+			return count;
+		}
+		
+		if(enable)
+		{			
+			DBG_8192C("Linked info Function Enable\n");
+			padapter->bLinkInfoDump = enable ;			
+		}
+		else
+		{
+			DBG_8192C("Linked info Function Disable\n");
+			padapter->bLinkInfoDump = 0 ;
+		}
+	
+	}
+	
+	return count;
+	
+}	
+
+*/		
+#ifdef CONFIG_AP_MODE
+
+int proc_get_all_sta_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_irqL irqL;
+	struct sta_info *psta;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	int i;
+	_list	*plist, *phead;
+
+	DBG_871X_SEL_NL(m, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+	for(i=0; i< NUM_STA; i++)
+	{
+		phead = &(pstapriv->sta_hash[i]);
+		plist = get_next(phead);
+		
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+		{
+			psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+			plist = get_next(plist);
+
+			//if(extra_arg == psta->aid)
+			{
+				DBG_871X_SEL_NL(m, "==============================\n");
+				DBG_871X_SEL_NL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr));
+				DBG_871X_SEL_NL(m, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+				DBG_871X_SEL_NL(m, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+#ifdef CONFIG_80211N_HT
+				DBG_871X_SEL_NL(m, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);	
+				DBG_871X_SEL_NL(m, "bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m);
+				DBG_871X_SEL_NL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);									
+				DBG_871X_SEL_NL(m, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+#endif //CONFIG_80211N_HT
+				DBG_871X_SEL_NL(m, "sleepq_len=%d\n", psta->sleepq_len);
+				DBG_871X_SEL_NL(m, "sta_xmitpriv.vo_q_qcnt=%d\n", psta->sta_xmitpriv.vo_q.qcnt);
+				DBG_871X_SEL_NL(m, "sta_xmitpriv.vi_q_qcnt=%d\n", psta->sta_xmitpriv.vi_q.qcnt);
+				DBG_871X_SEL_NL(m, "sta_xmitpriv.be_q_qcnt=%d\n", psta->sta_xmitpriv.be_q.qcnt);
+				DBG_871X_SEL_NL(m, "sta_xmitpriv.bk_q_qcnt=%d\n", psta->sta_xmitpriv.bk_q.qcnt);
+
+				DBG_871X_SEL_NL(m, "capability=0x%x\n", psta->capability);
+				DBG_871X_SEL_NL(m, "flags=0x%x\n", psta->flags);
+				DBG_871X_SEL_NL(m, "wpa_psk=0x%x\n", psta->wpa_psk);
+				DBG_871X_SEL_NL(m, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher);
+				DBG_871X_SEL_NL(m, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher);
+				DBG_871X_SEL_NL(m, "qos_info=0x%x\n", psta->qos_info);
+				DBG_871X_SEL_NL(m, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy);
+
+				sta_rx_reorder_ctl_dump(m, psta);
+
+#ifdef CONFIG_TDLS
+				DBG_871X_SEL_NL(m, "tdls_sta_state=0x%08x\n", psta->tdls_sta_state);
+				DBG_871X_SEL_NL(m, "PeerKey_Lifetime=%d\n", psta->TDLS_PeerKey_Lifetime);
+				DBG_871X_SEL_NL(m, "rx_data_pkts=%llu\n", psta->sta_stats.rx_data_pkts);
+				DBG_871X_SEL_NL(m, "rx_bytes=%llu\n", psta->sta_stats.rx_bytes);
+				DBG_871X_SEL_NL(m, "tx_data_pkts=%llu\n", psta->sta_stats.tx_pkts);
+				DBG_871X_SEL_NL(m, "tx_bytes=%llu\n", psta->sta_stats.tx_bytes);
+#endif //CONFIG_TDLS
+				DBG_871X_SEL_NL(m, "==============================\n");
+			}
+
+		}
+
+	}
+
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+	return 0;
+}
+
+#endif		
+
+#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
+int proc_get_rtkm_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct recv_priv	*precvpriv = &padapter->recvpriv;
+	struct recv_buf *precvbuf;
+	
+	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+	DBG_871X_SEL_NL(m, "============[RTKM Info]============\n");
+	DBG_871X_SEL_NL(m, "MAX_RTKM_NR_PREALLOC_RECV_SKB: %d\n", rtw_rtkm_get_nr_recv_skb());
+	DBG_871X_SEL_NL(m, "MAX_RTKM_RECVBUF_SZ: %d\n", rtw_rtkm_get_buff_size());
+
+	DBG_871X_SEL_NL(m, "============[Driver Info]============\n");
+	DBG_871X_SEL_NL(m, "NR_PREALLOC_RECV_SKB: %d\n", NR_PREALLOC_RECV_SKB);
+	DBG_871X_SEL_NL(m, "MAX_RECVBUF_SZ: %d\n", precvbuf->alloc_sz);
+
+	return 0;
+}
+#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */
+
+#ifdef DBG_MEMORY_LEAK
+#include <asm/atomic.h>
+extern atomic_t _malloc_cnt;;
+extern atomic_t _malloc_size;;
+
+int proc_get_malloc_cnt(struct seq_file *m, void *v)
+{
+	DBG_871X_SEL_NL(m, "_malloc_cnt=%d\n", atomic_read(&_malloc_cnt));
+	DBG_871X_SEL_NL(m, "_malloc_size=%d\n", atomic_read(&_malloc_size));
+
+	return 0;
+}
+#endif /* DBG_MEMORY_LEAK */
+
+#ifdef CONFIG_FIND_BEST_CHANNEL
+int proc_get_best_channel(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0;
+
+	for (i=0; pmlmeext->channel_set[i].ChannelNum !=0; i++) {
+		if ( pmlmeext->channel_set[i].ChannelNum == 1)
+			index_24G = i;
+		if ( pmlmeext->channel_set[i].ChannelNum == 36)
+			index_5G = i;
+	}	
+	
+	for (i=0; (i < MAX_CHANNEL_NUM) && (pmlmeext->channel_set[i].ChannelNum !=0) ; i++) {
+		// 2.4G
+		if ( pmlmeext->channel_set[i].ChannelNum == 6 ) {
+			if ( pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count ) {
+				index_24G = i;
+				best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+
+		// 5G
+		if ( pmlmeext->channel_set[i].ChannelNum >= 36
+			&& pmlmeext->channel_set[i].ChannelNum < 140 ) {
+			 // Find primary channel
+			if ( (( pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0)
+				&& (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count) ) {
+				index_5G = i;
+				best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+
+		if ( pmlmeext->channel_set[i].ChannelNum >= 149
+			&& pmlmeext->channel_set[i].ChannelNum < 165) {
+			 // find primary channel
+			if ( (( pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0)
+				&& (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count) ) {
+				index_5G = i;
+				best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+#if 1 // debug
+		DBG_871X_SEL_NL(m, "The rx cnt of channel %3d = %d\n", 
+					pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
+#endif
+	}
+	
+	DBG_871X_SEL_NL(m, "best_channel_5G = %d\n", best_channel_5G);
+	DBG_871X_SEL_NL(m, "best_channel_24G = %d\n", best_channel_24G);
+
+	return 0;
+}
+
+ssize_t proc_set_best_channel(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	char tmp[32];
+
+	if(count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+		int i;
+		for(i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++)
+		{
+			pmlmeext->channel_set[i].rx_count = 0;
+		}
+
+		DBG_871X("set %s\n", "Clean Best Channel Count");
+	}
+
+	return count;
+}
+#endif /* CONFIG_FIND_BEST_CHANNEL */
+
+#ifdef CONFIG_BT_COEXIST
+int proc_get_btcoex_dbg(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	PADAPTER padapter;
+	char buf[512] = {0};
+	padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+	rtw_btcoex_GetDBG(padapter, buf, 512);
+
+	DBG_871X_SEL(m, "%s", buf);
+
+	return 0;
+}
+
+ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	PADAPTER padapter;
+	u8 tmp[80] = {0};
+	u32 module[2] = {0};
+	u32 num;
+
+	padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+//	DBG_871X("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter));
+
+	if (NULL == buffer)
+	{
+		DBG_871X(FUNC_ADPT_FMT ": input buffer is NULL!\n",
+			FUNC_ADPT_ARG(padapter));
+		
+		return -EFAULT;
+	}
+
+	if (count < 1)
+	{
+		DBG_871X(FUNC_ADPT_FMT ": input length is 0!\n",
+			FUNC_ADPT_ARG(padapter));
+
+		return -EFAULT;
+	}
+
+	num = count;
+	if (num > (sizeof(tmp) - 1))
+		num = (sizeof(tmp) - 1);
+
+	if (copy_from_user(tmp, buffer, num))
+	{
+		DBG_871X(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n",
+			FUNC_ADPT_ARG(padapter));
+
+		return -EFAULT;
+	}
+
+	num = sscanf(tmp, "%x %x", module, module+1);
+	if (1 == num)
+	{
+		if (0 == module[0])
+			_rtw_memset(module, 0, sizeof(module));
+		else
+			_rtw_memset(module, 0xFF, sizeof(module));
+	}
+	else if (2 != num)
+	{
+		DBG_871X(FUNC_ADPT_FMT ": input(\"%s\") format incorrect!\n",
+			FUNC_ADPT_ARG(padapter), tmp);
+
+		if (0 == num)
+			return -EFAULT;
+	}
+
+	DBG_871X(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n",
+		FUNC_ADPT_ARG(padapter), module[0], module[1]);
+	rtw_btcoex_SetDBG(padapter, module);
+
+	return count;
+}
+
+int proc_get_btcoex_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	PADAPTER padapter;
+	const u32 bufsize = 30*100;
+	u8 *pbuf = NULL;
+
+	padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+	pbuf = rtw_zmalloc(bufsize);
+	if (NULL == pbuf) {
+		return -ENOMEM;
+	}
+
+	rtw_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize);
+
+	DBG_871X_SEL(m, "%s\n", pbuf);
+	
+	rtw_mfree(pbuf, bufsize);
+
+	return 0;
+}
+#endif /* CONFIG_BT_COEXIST */
+
+#if defined(DBG_CONFIG_ERROR_DETECT)
+int proc_get_sreset(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	return 0;
+}
+
+ssize_t proc_set_sreset(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	s32 trigger_point;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%d", &trigger_point);
+
+		if (trigger_point == SRESET_TGP_NULL)
+			rtw_hal_sreset_reset(padapter);
+		else
+			sreset_set_trigger_point(padapter, trigger_point);
+	}
+	
+	return count;
+	
+}
+#endif /* DBG_CONFIG_ERROR_DETECT */
+
+#ifdef CONFIG_PCI_HCI
+
+int proc_get_rx_ring(struct seq_file *m, void *v)
+{
+	_irqL irqL;
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *) rtw_netdev_priv(dev);
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+	struct rtw_rx_ring *rx_ring = &precvpriv->rx_ring[RX_MPDU_QUEUE];
+	int i, j;
+
+	DBG_871X_SEL_NL(m, "rx ring (%p)\n", rx_ring);
+	DBG_871X_SEL_NL(m, "  dma: 0x%08x\n", (int) rx_ring->dma);
+	DBG_871X_SEL_NL(m, "  idx: %d\n", rx_ring->idx);
+
+	_enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
+	for (i=0; i<precvpriv->rxringcount; i++)
+	{
+		struct recv_stat *entry = &rx_ring->desc[i];
+		struct sk_buff *skb = rx_ring->rx_buf[i];
+
+		DBG_871X_SEL_NL(m, "  desc[%03d]: %p, rx_buf[%03d]: 0x%08x\n",
+			i, entry, i, cpu_to_le32(*((dma_addr_t *)skb->cb)));
+
+		for (j=0; j<sizeof(*entry)/4; j++)
+		{
+			if ((j % 4) == 0)
+				DBG_871X_SEL_NL(m, "  0x%03x", j);
+
+			DBG_871X_SEL_NL(m, " 0x%08x ", ((int *) entry)[j]);
+
+			if ((j % 4) == 3)
+				DBG_871X_SEL_NL(m, "\n");
+		}
+	}
+	_exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
+
+	return 0;
+}
+
+int proc_get_tx_ring(struct seq_file *m, void *v)
+{
+	_irqL irqL;
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *) rtw_netdev_priv(dev);
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	int i, j, k;
+
+	_enter_critical(&pdvobjpriv->irq_th_lock, &irqL);
+	for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++)
+	{
+		struct rtw_tx_ring *tx_ring = &pxmitpriv->tx_ring[i];
+
+		DBG_871X_SEL_NL(m, "tx ring[%d] (%p)\n", i, tx_ring);
+		DBG_871X_SEL_NL(m, "  dma: 0x%08x\n", (int) tx_ring->dma);
+		DBG_871X_SEL_NL(m, "  idx: %d\n", tx_ring->idx);
+		DBG_871X_SEL_NL(m, "  entries: %d\n", tx_ring->entries);
+//		DBG_871X_SEL_NL(m, "  queue: %d\n", tx_ring->queue);
+		DBG_871X_SEL_NL(m, "  qlen: %d\n", tx_ring->qlen);
+
+		for (j=0; j < pxmitpriv->txringcount[i]; j++)
+		{
+			struct tx_desc *entry = &tx_ring->desc[j];
+
+			DBG_871X_SEL_NL(m, "  desc[%03d]: %p\n", j, entry);
+			for (k=0; k < sizeof(*entry)/4; k++)
+			{
+				if ((k % 4) == 0)
+					DBG_871X_SEL_NL(m, "  0x%03x", k);
+
+				DBG_871X_SEL_NL(m, " 0x%08x ", ((int *) entry)[k]);
+
+				if ((k % 4) == 3)
+					DBG_871X_SEL_NL(m, "\n");
+			}
+		}
+	}
+	_exit_critical(&pdvobjpriv->irq_th_lock, &irqL);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_GPIO_WAKEUP
+int proc_get_wowlan_gpio_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+	u8 val = pwrpriv->is_high_active;
+
+	DBG_871X_SEL_NL(m, "wakeup_gpio_idx: %d\n", WAKEUP_GPIO_IDX);
+	DBG_871X_SEL_NL(m, "high_active: %d\n", val);
+
+	return 0;
+}
+
+ssize_t proc_set_wowlan_gpio_info(struct file *file, const char __user *buffer,
+		size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+	char tmp[32] = {0};
+	int num = 0;
+	u32 is_high_active = 0;
+	u8 val8 = 0;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		num = sscanf(tmp, "%u", &is_high_active);
+
+		is_high_active = is_high_active == 0 ? 0 : 1;
+
+		pwrpriv->is_high_active = is_high_active;
+
+		rtw_ps_deny(padapter, PS_DENY_IOCTL);
+		LeaveAllPowerSaveModeDirect(padapter);
+		val8 = (pwrpriv->is_high_active == 0) ? 1 : 0;
+		rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, val8);
+		rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL);
+
+		DBG_871X("set %s %d\n", "gpio_high_active",
+				pwrpriv->is_high_active);
+		DBG_871X("%s: set GPIO_%d %d as default.\n",
+			 __func__, WAKEUP_GPIO_IDX, val8);
+	}
+	
+	return count;
+}
+#endif /* CONFIG_GPIO_WAKEUP */
+
+#ifdef CONFIG_P2P_WOWLAN
+int proc_get_p2p_wowlan_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info	*pwdinfo = &( padapter->wdinfo );
+	struct p2p_wowlan_info	 peerinfo = pwdinfo->p2p_wow_info;
+	if(_TRUE == peerinfo.is_trigger)
+	{
+		DBG_871X_SEL_NL(m,"is_trigger: TRUE\n");
+		switch(peerinfo.wowlan_recv_frame_type)
+		{
+			case P2P_WOWLAN_RECV_NEGO_REQ:
+				DBG_871X_SEL_NL(m,"Frame Type: Nego Request\n");
+				break;
+			case P2P_WOWLAN_RECV_INVITE_REQ:
+				DBG_871X_SEL_NL(m,"Frame Type: Invitation Request\n");
+				break;
+			case P2P_WOWLAN_RECV_PROVISION_REQ:
+				DBG_871X_SEL_NL(m,"Frame Type: Provision Request\n");
+				break;
+			default:
+				break;
+		}
+		DBG_871X_SEL_NL(m,"Peer Addr: "MAC_FMT"\n", MAC_ARG(peerinfo.wowlan_peer_addr));
+		DBG_871X_SEL_NL(m,"Peer WPS Config: %x\n", peerinfo.wowlan_peer_wpsconfig);
+		DBG_871X_SEL_NL(m,"Persistent Group: %d\n", peerinfo.wowlan_peer_is_persistent);
+		DBG_871X_SEL_NL(m,"Intivation Type: %d\n", peerinfo.wowlan_peer_invitation_type);
+	}
+	else
+	{
+		DBG_871X_SEL_NL(m,"is_trigger: False\n");
+	}
+	return 0;
+}
+#endif /* CONFIG_P2P_WOWLAN */
+
+int proc_get_new_bcn_max(struct seq_file *m, void *v)
+{
+	extern int new_bcn_max;
+
+	DBG_871X_SEL_NL(m, "%d", new_bcn_max);
+	return 0;
+}
+
+ssize_t proc_set_new_bcn_max(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	char tmp[32];
+	extern int new_bcn_max;
+
+	if(count < 1)
+		return -EFAULT;
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count))
+		sscanf(tmp, "%d ", &new_bcn_max);
+
+	return count;
+}
+
+#ifdef CONFIG_POWER_SAVING
+int proc_get_ps_info(struct seq_file *m, void *v)
+{	
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+	u8 ips_mode = pwrpriv->ips_mode;
+	u8 lps_mode = pwrpriv->power_mgnt;
+	char *str = "";
+
+	DBG_871X_SEL_NL(m, "======Power Saving Info:======\n");
+	DBG_871X_SEL_NL(m, "*IPS:\n");
+
+	if (ips_mode == IPS_NORMAL) {
+#ifdef CONFIG_FWLPS_IN_IPS
+		str = "FW_LPS_IN_IPS";
+#else
+		str = "Card Disable";
+#endif
+	} else if (ips_mode == IPS_NONE) {
+		str = "NO IPS";
+	} else if (ips_mode == IPS_LEVEL_2) {
+		str = "IPS_LEVEL_2";
+	} else {
+		str = "invalid ips_mode";
+	}
+
+	DBG_871X_SEL_NL(m, " IPS mode: %s\n", str);
+	DBG_871X_SEL_NL(m, " IPS enter count:%d, IPS leave count:%d\n",
+			pwrpriv->ips_enter_cnts, pwrpriv->ips_leave_cnts);
+	DBG_871X_SEL_NL(m, "------------------------------\n");
+	DBG_871X_SEL_NL(m, "*LPS:\n");
+
+	if (lps_mode == PS_MODE_ACTIVE) {
+		str = "NO LPS";
+	} else if (lps_mode == PS_MODE_MIN) {
+		str = "MIN";
+	} else if (lps_mode == PS_MODE_MAX) {
+		str = "MAX";
+	} else if (lps_mode == PS_MODE_DTIM) {
+		str = "DTIM";
+	} else {
+		sprintf(str, "%d", lps_mode);
+	}
+
+	DBG_871X_SEL_NL(m, " LPS mode: %s\n", str);
+
+	if (pwrpriv->dtim != 0)
+		DBG_871X_SEL_NL(m, " DTIM: %d\n", pwrpriv->dtim);
+	DBG_871X_SEL_NL(m, " LPS enter count:%d, LPS leave count:%d\n",
+			pwrpriv->lps_enter_cnts, pwrpriv->lps_leave_cnts);
+	DBG_871X_SEL_NL(m, "=============================\n");
+	return 0;
+}
+#endif //CONFIG_POWER_SAVING
+
+#ifdef CONFIG_TDLS
+static int proc_tdls_display_tdls_function_info(struct seq_file *m)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+	u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE;
+	u8 SpaceBtwnItemAndValueTmp = 0;
+	BOOLEAN FirstMatchFound = _FALSE;
+	int j= 0;
+	
+	DBG_871X_SEL_NL(m, "============[TDLS Function Info]============\n");
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Prohibited", (ptdlsinfo->ap_prohibited == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Channel Switch Prohibited", (ptdlsinfo->ch_switch_prohibited == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Link Established", (ptdlsinfo->link_established == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %d/%d\n", SpaceBtwnItemAndValue, "TDLS STA Num (Linked/Allowed)", ptdlsinfo->sta_cnt, MAX_ALLOWED_TDLS_STA_NUM);
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Allowed STA Num Reached", (ptdlsinfo->sta_maximum == _TRUE) ? "_TRUE" : "_FALSE");
+
+#ifdef CONFIG_TDLS_CH_SW
+	DBG_871X_SEL_NL(m, "%-*s =", SpaceBtwnItemAndValue, "TDLS CH SW State");
+	if (ptdlsinfo->chsw_info.ch_sw_state == TDLS_STATE_NONE)
+	{
+		DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_STATE_NONE");
+	}
+	else
+	{
+		for (j = 0; j < 32; j++)
+		{
+			if (ptdlsinfo->chsw_info.ch_sw_state & BIT(j))
+			{
+				if (FirstMatchFound ==  _FALSE)
+				{
+					SpaceBtwnItemAndValueTmp = 1;
+					FirstMatchFound = _TRUE;
+				}
+				else
+				{
+					SpaceBtwnItemAndValueTmp = SpaceBtwnItemAndValue + 3;
+				}
+				switch (BIT(j))
+				{
+					case TDLS_INITIATOR_STATE:
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_INITIATOR_STATE");
+						break;
+					case TDLS_RESPONDER_STATE:
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_RESPONDER_STATE");
+						break;
+					case TDLS_LINKED_STATE:
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_LINKED_STATE");
+						break;
+					case TDLS_WAIT_PTR_STATE:		
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_WAIT_PTR_STATE");
+						break;
+					case TDLS_ALIVE_STATE:		
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_ALIVE_STATE");
+						break;
+					case TDLS_CH_SWITCH_ON_STATE:	
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SWITCH_ON_STATE");
+						break;
+					case TDLS_PEER_AT_OFF_STATE:		
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_PEER_AT_OFF_STATE");
+						break;
+					case TDLS_CH_SW_INITIATOR_STATE:		
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SW_INITIATOR_STATE");
+						break;
+					case TDLS_WAIT_CH_RSP_STATE:		
+						DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValue, " ", "TDLS_WAIT_CH_RSP_STATE");
+						break;
+					default:
+						DBG_871X_SEL_NL(m, "%-*sBIT(%d)\n", SpaceBtwnItemAndValueTmp, " ", j);
+						break;
+				}
+			}
+		}
+	}
+
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS CH SW On", (ATOMIC_READ(&ptdlsinfo->chsw_info.chsw_on) == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Off-Channel Num", ptdlsinfo->chsw_info.off_ch_num);
+	DBG_871X_SEL_NL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Channel Offset", ptdlsinfo->chsw_info.ch_offset);
+	DBG_871X_SEL_NL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Current Time", ptdlsinfo->chsw_info.cur_time);
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS CH SW Delay Switch Back", (ptdlsinfo->chsw_info.delay_switch_back == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Dump Back", ptdlsinfo->chsw_info.dump_stack);
+#endif
+
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Device Discovered", (ptdlsinfo->dev_discovered == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Enable", (ptdlsinfo->tdls_enable == _TRUE) ? "_TRUE" : "_FALSE");
+	DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Driver Setup", (ptdlsinfo->driver_setup == _TRUE) ? "_TRUE" : "_FALSE");
+	
+	return 0;
+}
+
+static int proc_tdls_display_network_info(struct seq_file *m)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+	int i = 0;
+	u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE;
+
+	/* Display the linked AP/GO info */
+	DBG_871X_SEL_NL(m, "============[Associated AP/GO Info]============\n");
+	
+	if ((pmlmepriv->fw_state & WIFI_STATION_STATE) && (pmlmepriv->fw_state & _FW_LINKED))
+	{
+		DBG_871X_SEL_NL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "BSSID", cur_network->network.Ssid.Ssid);
+		DBG_871X_SEL_NL(m, "%-*s = "MAC_FMT"\n", SpaceBtwnItemAndValue, "Mac Address", MAC_ARG(cur_network->network.MacAddress));
+		
+		DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Wireless Mode");
+		for (i = 0; i < 8; i++)
+		{
+			if (pmlmeext->cur_wireless_mode & BIT(i))
+			{
+				switch (BIT(i))
+				{
+					case WIRELESS_11B: 
+						DBG_871X_SEL_NL(m, "%4s", "11B ");
+						break;
+					case WIRELESS_11G:
+						DBG_871X_SEL_NL(m, "%4s", "11G ");
+						break;
+					case WIRELESS_11A:
+						DBG_871X_SEL_NL(m, "%4s", "11A ");
+						break;
+					case WIRELESS_11_24N:
+						DBG_871X_SEL_NL(m, "%7s", "11_24N ");
+						break;
+					case WIRELESS_11_5N:
+						DBG_871X_SEL_NL(m, "%6s", "11_5N ");
+						break;
+					case WIRELESS_AUTO:
+						DBG_871X_SEL_NL(m, "%5s", "AUTO ");
+						break;
+					case WIRELESS_11AC:
+						DBG_871X_SEL_NL(m, "%5s", "11AC ");
+						break;
+				}
+			}
+		}
+		DBG_871X_SEL_NL(m, "\n");
+
+		DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Privacy");
+		switch (padapter->securitypriv.dot11PrivacyAlgrthm)
+		{
+			case _NO_PRIVACY_:
+				DBG_871X_SEL_NL(m, "%s\n", "NO PRIVACY");
+				break;
+			case _WEP40_:	
+				DBG_871X_SEL_NL(m, "%s\n", "WEP 40");
+				break;
+			case _TKIP_:
+				DBG_871X_SEL_NL(m, "%s\n", "TKIP");
+				break;
+			case _TKIP_WTMIC_:
+				DBG_871X_SEL_NL(m, "%s\n", "TKIP WTMIC");
+				break;
+			case _AES_:				
+				DBG_871X_SEL_NL(m, "%s\n", "AES");
+				break;
+			case _WEP104_:
+				DBG_871X_SEL_NL(m, "%s\n", "WEP 104");
+				break;
+			case _WEP_WPA_MIXED_:
+				DBG_871X_SEL_NL(m, "%s\n", "WEP/WPA Mixed");
+				break;
+			case _SMS4_:
+				DBG_871X_SEL_NL(m, "%s\n", "SMS4");
+				break;
+#ifdef CONFIG_IEEE80211W
+			case _BIP_:
+				DBG_871X_SEL_NL(m, "%s\n", "BIP");
+				break;	
+#endif //CONFIG_IEEE80211W
+		}
+		
+		DBG_871X_SEL_NL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "Channel", pmlmeext->cur_channel);
+		DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Channel Offset");
+		switch (pmlmeext->cur_ch_offset)
+		{
+			case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+				DBG_871X_SEL_NL(m, "%s\n", "N/A");
+				break;
+			case HAL_PRIME_CHNL_OFFSET_LOWER:
+				DBG_871X_SEL_NL(m, "%s\n", "Lower");
+				break;
+			case HAL_PRIME_CHNL_OFFSET_UPPER:
+				DBG_871X_SEL_NL(m, "%s\n", "Upper");
+				break;
+		}
+		
+		DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Bandwidth Mode");
+		switch (pmlmeext->cur_bwmode)
+		{
+			case CHANNEL_WIDTH_20:
+				DBG_871X_SEL_NL(m, "%s\n", "20MHz");
+				break;
+			case CHANNEL_WIDTH_40:
+				DBG_871X_SEL_NL(m, "%s\n", "40MHz");
+				break;
+			case CHANNEL_WIDTH_80:
+				DBG_871X_SEL_NL(m, "%s\n", "80MHz");
+				break;
+			case CHANNEL_WIDTH_160:
+				DBG_871X_SEL_NL(m, "%s\n", "160MHz");
+				break;
+			case CHANNEL_WIDTH_80_80:
+				DBG_871X_SEL_NL(m, "%s\n", "80MHz + 80MHz");
+				break;
+		}
+	}
+	else
+	{
+		DBG_871X_SEL_NL(m, "No association with AP/GO exists!\n");
+	}
+
+	return 0;
+}
+
+static int proc_tdls_display_tdls_sta_info(struct seq_file *m)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+	struct sta_info *psta;
+	int i = 0, j = 0;
+	_irqL irqL;
+	_list	*plist, *phead;
+	u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE;
+	u8 SpaceBtwnItemAndValueTmp = 0;
+	u8 NumOfTdlsStaToShow = 0;
+	BOOLEAN FirstMatchFound = _FALSE;
+	
+	/* Search for TDLS sta info to display */
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+	for (i=0; i< NUM_STA; i++)
+	{
+		phead = &(pstapriv->sta_hash[i]);
+		plist = get_next(phead);	
+		while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)
+		{
+				psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+				plist = get_next(plist);
+				if (psta->tdls_sta_state != TDLS_STATE_NONE)
+				{
+					/* We got one TDLS sta info to show */
+					DBG_871X_SEL_NL(m, "============[TDLS Peer STA Info: STA %d]============\n", ++NumOfTdlsStaToShow);
+					DBG_871X_SEL_NL(m, "%-*s = "MAC_FMT"\n", SpaceBtwnItemAndValue, "Mac Address", MAC_ARG(psta->hwaddr));
+					DBG_871X_SEL_NL(m, "%-*s =", SpaceBtwnItemAndValue, "TDLS STA State");
+					SpaceBtwnItemAndValueTmp = 0;
+					FirstMatchFound = _FALSE;
+					for (j = 0; j < 32; j++)
+					{
+						if (psta->tdls_sta_state & BIT(j))
+						{
+							if (FirstMatchFound ==  _FALSE)
+							{
+								SpaceBtwnItemAndValueTmp = 1;
+								FirstMatchFound = _TRUE;
+							}
+							else
+							{
+								SpaceBtwnItemAndValueTmp = SpaceBtwnItemAndValue + 3;
+							}
+							switch (BIT(j))
+							{
+								case TDLS_INITIATOR_STATE:
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_INITIATOR_STATE");
+									break;
+								case TDLS_RESPONDER_STATE:
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_RESPONDER_STATE");
+									break;
+								case TDLS_LINKED_STATE:
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_LINKED_STATE");
+									break;
+								case TDLS_WAIT_PTR_STATE:		
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_WAIT_PTR_STATE");
+									break;
+								case TDLS_ALIVE_STATE:		
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_ALIVE_STATE");
+									break;
+								case TDLS_CH_SWITCH_ON_STATE:	
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SWITCH_ON_STATE");
+									break;
+								case TDLS_PEER_AT_OFF_STATE:		
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_PEER_AT_OFF_STATE");
+									break;
+								case TDLS_CH_SW_INITIATOR_STATE:		
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SW_INITIATOR_STATE");
+									break;
+								case TDLS_WAIT_CH_RSP_STATE:		
+									DBG_871X_SEL_NL(m, "%-*s%s\n", SpaceBtwnItemAndValue, " ", "TDLS_WAIT_CH_RSP_STATE");
+									break;
+								default:
+									DBG_871X_SEL_NL(m, "%-*sBIT(%d)\n", SpaceBtwnItemAndValueTmp, " ", j);
+									break;
+							}
+						}
+					}
+
+					DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Wireless Mode");
+					for (j = 0; j < 8; j++)
+					{
+						if (psta->wireless_mode & BIT(j))
+						{
+							switch (BIT(j))
+							{
+								case WIRELESS_11B: 
+									DBG_871X_SEL_NL(m, "%4s", "11B ");
+									break;
+								case WIRELESS_11G:
+									DBG_871X_SEL_NL(m, "%4s", "11G ");
+									break;
+								case WIRELESS_11A:
+									DBG_871X_SEL_NL(m, "%4s", "11A ");
+									break;
+								case WIRELESS_11_24N:
+									DBG_871X_SEL_NL(m, "%7s", "11_24N ");
+									break;
+								case WIRELESS_11_5N:
+									DBG_871X_SEL_NL(m, "%6s", "11_5N ");
+									break;
+								case WIRELESS_AUTO:
+									DBG_871X_SEL_NL(m, "%5s", "AUTO ");
+									break;
+								case WIRELESS_11AC:
+									DBG_871X_SEL_NL(m, "%5s", "11AC ");
+									break;
+							}
+						}
+					}
+					DBG_871X_SEL_NL(m, "\n");
+
+					DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Bandwidth Mode");
+					switch (psta->bw_mode)
+					{
+						case CHANNEL_WIDTH_20:
+							DBG_871X_SEL_NL(m, "%s\n", "20MHz");
+							break;
+						case CHANNEL_WIDTH_40:
+							DBG_871X_SEL_NL(m, "%s\n", "40MHz");
+							break;
+						case CHANNEL_WIDTH_80:
+							DBG_871X_SEL_NL(m, "%s\n", "80MHz");
+							break;
+						case CHANNEL_WIDTH_160:
+							DBG_871X_SEL_NL(m, "%s\n", "160MHz");
+							break;
+						case CHANNEL_WIDTH_80_80:
+							DBG_871X_SEL_NL(m, "%s\n", "80MHz + 80MHz");
+							break;
+					}
+
+					DBG_871X_SEL_NL(m, "%-*s = ", SpaceBtwnItemAndValue, "Privacy");
+					switch (psta->dot118021XPrivacy)
+					{
+						case _NO_PRIVACY_:
+							DBG_871X_SEL_NL(m, "%s\n", "NO PRIVACY");
+							break;
+						case _WEP40_:	
+							DBG_871X_SEL_NL(m, "%s\n", "WEP 40");
+							break;
+						case _TKIP_:
+							DBG_871X_SEL_NL(m, "%s\n", "TKIP");
+							break;
+						case _TKIP_WTMIC_:
+							DBG_871X_SEL_NL(m, "%s\n", "TKIP WTMIC");
+							break;
+						case _AES_:				
+							DBG_871X_SEL_NL(m, "%s\n", "AES");
+							break;
+						case _WEP104_:
+							DBG_871X_SEL_NL(m, "%s\n", "WEP 104");
+							break;
+						case _WEP_WPA_MIXED_:
+							DBG_871X_SEL_NL(m, "%s\n", "WEP/WPA Mixed");
+							break;
+						case _SMS4_:
+							DBG_871X_SEL_NL(m, "%s\n", "SMS4");
+							break;
+#ifdef CONFIG_IEEE80211W
+						case _BIP_:
+							DBG_871X_SEL_NL(m, "%s\n", "BIP");
+							break;
+#endif //CONFIG_IEEE80211W
+					}
+
+					DBG_871X_SEL_NL(m, "%-*s = %d sec/%d sec\n", SpaceBtwnItemAndValue, "TPK Lifetime (Current/Expire)", psta->TPK_count, psta->TDLS_PeerKey_Lifetime);
+					DBG_871X_SEL_NL(m, "%-*s = %llu\n", SpaceBtwnItemAndValue, "Tx Packets Over Direct Link", psta->sta_stats.tx_pkts);
+					DBG_871X_SEL_NL(m, "%-*s = %llu\n", SpaceBtwnItemAndValue, "Rx Packets Over Direct Link", psta->sta_stats.rx_data_pkts);
+				}
+		}
+	}
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+	if (NumOfTdlsStaToShow == 0)
+	{
+		DBG_871X_SEL_NL(m, "============[TDLS Peer STA Info]============\n");
+		DBG_871X_SEL_NL(m, "No TDLS direct link exists!\n");
+	}
+
+	return 0;
+}
+
+int proc_get_tdls_info(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+	struct sta_info *psta;
+	int i = 0, j = 0;
+	_irqL irqL;
+	_list	*plist, *phead;
+	u8 SpaceBtwnItemAndValue = 41;
+	u8 SpaceBtwnItemAndValueTmp = 0;
+	u8 NumOfTdlsStaToShow = 0;
+	BOOLEAN FirstMatchFound = _FALSE;
+
+	proc_tdls_display_tdls_function_info(m);
+	proc_tdls_display_network_info(m);
+	proc_tdls_display_tdls_sta_info(m);	
+
+	return 0;
+}
+#endif
+
+int proc_get_monitor(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	if (WIFI_MONITOR_STATE == get_fwstate(pmlmepriv)) {
+		DBG_871X_SEL_NL(m, "Monitor mode : Enable\n");
+
+		DBG_871X_SEL_NL(m, "ch=%d, ch_offset=%d, bw=%d\n",
+						rtw_get_oper_ch(padapter), rtw_get_oper_choffset(padapter), rtw_get_oper_bw(padapter));
+	} else {
+		DBG_871X_SEL_NL(m, "Monitor mode : Disable\n");
+	}
+
+	return 0;
+}
+
+ssize_t proc_set_monitor(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	char tmp[32];
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	u8 target_chan, target_offset, target_bw;
+
+	if (count < 3) {
+		DBG_871X("argument size is less than 3\n");
+		return -EFAULT;
+	}
+
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+		int num = sscanf(tmp, "%hhu %hhu %hhu", &target_chan, &target_offset, &target_bw);
+
+		if (num != 3) {
+			DBG_871X("invalid write_reg parameter!\n");
+			return count;
+		}
+
+		padapter->mlmeextpriv.cur_channel  = target_chan;
+		set_channel_bwmode(padapter, target_chan, target_offset, target_bw);
+	}
+
+	return count;
+}
+
+#include <hal_data.h>
+int proc_get_efuse_map(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
+	struct pwrctrl_priv *pwrctrlpriv  = adapter_to_pwrctl(padapter);
+	PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal;
+	int i, j;
+	u8 ips_mode = IPS_NUM; 
+	int mapLen = EFUSE_MAP_SIZE;
+
+	ips_mode = pwrctrlpriv->ips_mode;
+	rtw_pm_set_ips(padapter, IPS_NONE);
+	if (rtw_efuse_map_read(padapter, EFUSE_WIFI, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL)
+		DBG_871X_SEL_NL(m, "WARN - Read Realmap Failed\n");	
+	
+	DBG_871X_SEL_NL(m, "\n");
+	for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+		DBG_871X_SEL_NL(m, "0x%02x\t", i);
+		for (j = 0; j < 8; j++) 
+			DBG_871X_SEL_NL(m, "%02X ", pEfuseHal->fakeEfuseInitMap[i+j]);
+		
+		DBG_871X_SEL_NL(m, "\t");
+				
+		for (; j < 16; j++)
+			DBG_871X_SEL_NL(m, "%02X ", pEfuseHal->fakeEfuseInitMap[i+j]);
+		
+		DBG_871X_SEL_NL(m, "\n");
+				
+	}
+	rtw_pm_set_ips(padapter, ips_mode);
+	return 0;
+}
+
+ssize_t proc_set_efuse_map(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+#if 0
+	char tmp[256] = {0};
+	u32 addr, cnts;
+	u8 efuse_data;
+	
+	int jj, kk;
+
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct pwrctrl_priv *pwrctrlpriv  = adapter_to_pwrctl(padapter);
+	u8 ips_mode = IPS_NUM;
+	
+	if (count < 3) {
+		DBG_871X("argument size is less than 3\n");
+		return -EFAULT;
+	}
+	
+	if (count > sizeof(tmp)) {
+		rtw_warn_on(1);
+		return -EFAULT;
+	}
+	
+	if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+		int num = sscanf(tmp, "%x %d %x", &addr, &cnts, &efuse_data);
+	
+		if (num != 3) {
+			DBG_871X("invalid write_reg parameter!\n");
+			return count;
+		}
+	}
+	ips_mode = pwrctrlpriv->ips_mode;
+	rtw_pm_set_ips(padapter, IPS_NONE);
+	if (rtw_efuse_map_write(padapter, addr, cnts, &efuse_data) == _FAIL) 
+		DBG_871X("WARN - rtw_efuse_map_write error!!\n");		
+	rtw_pm_set_ips(padapter, ips_mode);
+#endif	
+	return count;
+}
+
+#ifdef CONFIG_IEEE80211W
+ssize_t proc_set_tx_sa_query(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+	struct sta_info *psta;
+	_list	*plist, *phead;
+	_irqL	 irqL;
+	char tmp[16];
+	u8	mac_addr[NUM_STA][ETH_ALEN];
+	u32 key_type;
+	u8 index;
+
+	if (count > 2) {
+		DBG_871X("argument size is more than 2\n");
+		return -EFAULT;
+	}	
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {		
+
+		int num = sscanf(tmp, "%x", &key_type);
+
+		if (num !=  1) {
+			DBG_871X("invalid read_reg parameter!\n");
+			return count;
+		}
+		DBG_871X("0: set sa query request , key_type=%d\n", key_type);
+	}
+	
+	if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
+		&& (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && padapter->securitypriv.binstallBIPkey == _TRUE) {
+		DBG_871X("STA:"MAC_FMT"\n", MAC_ARG(get_my_bssid(&(pmlmeinfo->network))));
+		/* TX unicast sa_query to AP */
+		issue_action_SA_Query(padapter, get_my_bssid(&(pmlmeinfo->network)), 0, 0, (u8)key_type);
+	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE && padapter->securitypriv.binstallBIPkey == _TRUE) {
+		/* TX unicast sa_query to every client STA */
+		_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+		for (index = 0; index < NUM_STA; index++) {
+			psta = NULL;
+			
+			phead = &(pstapriv->sta_hash[index]);
+			plist = get_next(phead);
+			
+			while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+				psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+				plist = get_next(plist);
+				_rtw_memcpy(&mac_addr[psta->mac_id][0], psta->hwaddr, ETH_ALEN);
+			}
+		}
+		_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+		
+		for (index = 0; index < macid_ctl->num && index < NUM_STA; index++) {
+			if (rtw_macid_is_used(macid_ctl, index) && !rtw_macid_is_bmc(macid_ctl, index)) {
+				if (!_rtw_memcmp(get_my_bssid(&(pmlmeinfo->network)), &mac_addr[index][0], ETH_ALEN) 
+					&& !IS_MCAST(&mac_addr[index][0])) {
+					issue_action_SA_Query(padapter, &mac_addr[index][0], 0, 0, (u8)key_type);
+					DBG_871X("STA[%u]:"MAC_FMT"\n", index , MAC_ARG(&mac_addr[index][0]));
+				}
+			}
+		}
+	}
+	
+	return count;
+}
+
+int proc_get_tx_sa_query(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	
+	DBG_871X_SEL_NL(m, "%s\n", __func__);
+	return 0;
+}
+
+ssize_t proc_set_tx_deauth(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+	struct sta_info *psta;
+	_list	*plist, *phead;
+	_irqL	 irqL;
+	char tmp[16];
+	u8	mac_addr[NUM_STA][ETH_ALEN];
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u32 key_type;
+	u8 index;
+	
+
+	if (count > 2) {
+		DBG_871X("argument size is more than 2\n");
+		return -EFAULT;
+	}	
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {		
+
+		int num = sscanf(tmp, "%x", &key_type);
+
+		if (num !=  1) {
+			DBG_871X("invalid read_reg parameter!\n");
+			return count;
+		}
+		DBG_871X("key_type=%d\n", key_type);
+	}
+	if (key_type < 0 || key_type > 4)
+		return count;
+	
+	if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
+		&& (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) {
+		if (key_type == 3) /* key_type 3 only for AP mode */
+			return count;
+		/* TX unicast deauth to AP */
+		issue_deauth_11w(padapter, get_my_bssid(&(pmlmeinfo->network)), 0, (u8)key_type);
+	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
+		
+		if (key_type == 3)
+			issue_deauth_11w(padapter, bc_addr, 0, IEEE80211W_RIGHT_KEY);
+		
+		/* TX unicast deauth to every client STA */
+		_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+		for (index = 0; index < NUM_STA; index++) {
+			psta = NULL;
+			
+			phead = &(pstapriv->sta_hash[index]);
+			plist = get_next(phead);
+			
+			while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
+				psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+				plist = get_next(plist);
+				_rtw_memcpy(&mac_addr[psta->mac_id][0], psta->hwaddr, ETH_ALEN);
+			}
+		}
+		_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+		
+		for (index = 0; index < macid_ctl->num && index < NUM_STA; index++) {
+			if (rtw_macid_is_used(macid_ctl, index) && !rtw_macid_is_bmc(macid_ctl, index)) {
+				if (!_rtw_memcmp(get_my_bssid(&(pmlmeinfo->network)), &mac_addr[index][0], ETH_ALEN)) {
+					if (key_type != 3)
+						issue_deauth_11w(padapter, &mac_addr[index][0], 0, (u8)key_type);
+					
+					psta = rtw_get_stainfo(pstapriv, &mac_addr[index][0]);	
+					if (psta && key_type != IEEE80211W_WRONG_KEY && key_type != IEEE80211W_NO_KEY) {
+						u8 updated = _FALSE;
+					
+						_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+						if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) {			
+							rtw_list_delete(&psta->asoc_list);
+							pstapriv->asoc_list_cnt--;
+							updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_PREV_AUTH_NOT_VALID, _TRUE);
+			
+						}
+						_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			
+						associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+					}
+					
+					DBG_871X("STA[%u]:"MAC_FMT"\n", index , MAC_ARG(&mac_addr[index][0]));
+				}
+			}
+		}
+	}
+	
+	return count;
+}
+
+int proc_get_tx_deauth(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	
+	DBG_871X_SEL_NL(m, "%s\n", __func__);
+	return 0;
+}
+
+ssize_t proc_set_tx_auth(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+	struct net_device *dev = data;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+	struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+	struct sta_info *psta;
+	_list	*plist, *phead;
+	_irqL	 irqL;
+	char tmp[16];
+	u8	mac_addr[NUM_STA][ETH_ALEN];
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u32 tx_auth;
+	u8 index;
+	
+
+	if (count > 2) {
+		DBG_871X("argument size is more than 2\n");
+		return -EFAULT;
+	}	
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {		
+
+		int num = sscanf(tmp, "%x", &tx_auth);
+
+		if (num !=  1) {
+			DBG_871X("invalid read_reg parameter!\n");
+			return count;
+		}
+		DBG_871X("1: setnd auth, 2: send assoc request. tx_auth=%d\n", tx_auth);
+	}
+	
+	if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
+		&& (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) {
+		if (tx_auth == 1) {
+			/* TX unicast auth to AP */
+			issue_auth(padapter, NULL, 0);
+		} else if (tx_auth == 2) {
+			/* TX unicast auth to AP */
+			issue_assocreq(padapter);
+		}
+	} 
+	
+	return count;
+}
+
+int proc_get_tx_auth(struct seq_file *m, void *v)
+{
+	struct net_device *dev = m->private;
+	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+	
+	DBG_871X_SEL_NL(m, "%s\n", __func__);
+	return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+#endif /* CONFIG_PROC_DEBUG */
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_eeprom.c b/drivers/net/wireless/rtl8189es/core/rtw_eeprom.c
new file mode 100644
index 000000000000..e83c090ac746
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_eeprom.c
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_EEPROM_C_
+
+#include <drv_conf.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+
+void up_clk(_adapter*	padapter,	 u16 *x)
+{
+_func_enter_;
+	*x = *x | _EESK;
+	rtw_write8(padapter, EE_9346CR, (u8)*x);
+	rtw_udelay_os(CLOCK_RATE);
+
+_func_exit_;
+	
+}
+
+void down_clk(_adapter *	padapter, u16 *x	)
+{
+_func_enter_;
+	*x = *x & ~_EESK;
+	rtw_write8(padapter, EE_9346CR, (u8)*x);
+	rtw_udelay_os(CLOCK_RATE);
+_func_exit_;	
+}
+
+void shift_out_bits(_adapter * padapter, u16 data, u16 count)
+{
+	u16 x,mask;
+_func_enter_;
+
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	mask = 0x01 << (count - 1);
+	x = rtw_read8(padapter, EE_9346CR);
+
+	x &= ~(_EEDO | _EEDI);
+
+	do
+	{
+		x &= ~_EEDI;
+		if(data & mask)
+			x |= _EEDI;
+		if (rtw_is_surprise_removed(padapter)) {
+			RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+			goto out;
+		}
+		rtw_write8(padapter, EE_9346CR, (u8)x);
+		rtw_udelay_os(CLOCK_RATE);
+		up_clk(padapter, &x);
+		down_clk(padapter, &x);
+		mask = mask >> 1;
+	} while(mask);
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	x &= ~_EEDI;
+	rtw_write8(padapter, EE_9346CR, (u8)x);
+out:	
+_func_exit_;		
+}
+
+u16 shift_in_bits (_adapter * padapter)
+{
+	u16 x,d=0,i;
+_func_enter_;	
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	x = rtw_read8(padapter, EE_9346CR);
+
+	x &= ~( _EEDO | _EEDI);
+	d = 0;
+
+	for(i=0; i<16; i++)
+	{
+		d = d << 1;
+		up_clk(padapter, &x);
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+		x = rtw_read8(padapter, EE_9346CR);
+
+		x &= ~(_EEDI);
+		if(x & _EEDO)
+		d |= 1;
+
+		down_clk(padapter, &x);
+	}
+out:	
+_func_exit_;		
+
+	return d;
+}
+
+void standby(_adapter *	padapter	)
+{
+	u8   x;
+_func_enter_;	
+	x = rtw_read8(padapter, EE_9346CR);
+
+	x &= ~(_EECS | _EESK);
+	rtw_write8(padapter, EE_9346CR,x);
+
+	rtw_udelay_os(CLOCK_RATE);
+	x |= _EECS;
+	rtw_write8(padapter, EE_9346CR, x);
+	rtw_udelay_os(CLOCK_RATE);
+_func_exit_;		
+}
+
+u16 wait_eeprom_cmd_done(_adapter* padapter)
+{
+	u8 	x;
+	u16	i,res=_FALSE;
+_func_enter_;	
+	standby(padapter );
+	for (i=0; i<200; i++) 
+	{
+		x = rtw_read8(padapter, EE_9346CR);
+		if (x & _EEDO){
+			res=_TRUE;
+			goto exit;
+			}
+		rtw_udelay_os(CLOCK_RATE);
+	}
+exit:	
+_func_exit_;			
+	return res;
+}
+
+void eeprom_clean(_adapter * padapter)
+{
+	u16 x;
+_func_enter_;		
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	x = rtw_read8(padapter, EE_9346CR);
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	x &= ~(_EECS | _EEDI);
+	rtw_write8(padapter, EE_9346CR, (u8)x);
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	up_clk(padapter, &x);
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	down_clk(padapter, &x);
+out:	
+_func_exit_;			
+}
+
+void eeprom_write16(_adapter * padapter, u16 reg, u16 data)
+{
+	u8 x;
+#ifdef CONFIG_RTL8712
+	u8	tmp8_ori,tmp8_new,tmp8_clk_ori,tmp8_clk_new;
+	tmp8_ori=rtw_read8(padapter, 0x102502f1);
+	tmp8_new=tmp8_ori & 0xf7;
+	if(tmp8_ori != tmp8_new){	
+		rtw_write8(padapter, 0x102502f1, tmp8_new);
+		RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x102502f1=====\n"));
+	}
+	tmp8_clk_ori=rtw_read8(padapter,0x10250003);
+	tmp8_clk_new=tmp8_clk_ori|0x20;
+	if(tmp8_clk_new!=tmp8_clk_ori){
+		RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n"));
+		rtw_write8(padapter, 0x10250003, tmp8_clk_new);
+	}	
+#endif
+_func_enter_;		
+	
+	x = rtw_read8(padapter, EE_9346CR);
+
+	x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
+	x |= _EEM1 | _EECS;
+	rtw_write8(padapter, EE_9346CR, x);
+
+	shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5);
+	
+	if(padapter->EepromAddressSize==8)	//CF+ and SDIO
+		shift_out_bits(padapter, 0, 6);
+	else									//USB
+		shift_out_bits(padapter, 0, 4);
+	
+	standby( padapter);
+
+// Commented out by rcnjko, 2004.0
+//	// Erase this particular word.  Write the erase opcode and register
+//	// number in that order. The opcode is 3bits in length; reg is 6 bits long.
+//	shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3);
+//	shift_out_bits(Adapter, reg, Adapter->EepromAddressSize);
+//
+//	if (wait_eeprom_cmd_done(Adapter ) == FALSE) 
+//	{
+//		return;
+//	}
+
+
+	standby(padapter );
+
+	// write the new word to the EEPROM
+
+	// send the write opcode the EEPORM
+	shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3);
+
+	// select which word in the EEPROM that we are writing to.
+	shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+
+	// write the data to the selected EEPROM word.
+	shift_out_bits(padapter, data, 16);
+
+	if (wait_eeprom_cmd_done(padapter ) == _FALSE) 
+	{
+
+		goto exit;
+	}
+
+	standby(padapter );
+
+	shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5);
+	shift_out_bits(padapter, reg, 4);
+
+	eeprom_clean(padapter );
+exit:	
+#ifdef CONFIG_RTL8712
+	if(tmp8_clk_new!=tmp8_clk_ori)
+		rtw_write8(padapter, 0x10250003, tmp8_clk_ori);
+	if(tmp8_new!=tmp8_ori)
+		rtw_write8(padapter, 0x102502f1, tmp8_ori);
+
+#endif
+_func_exit_;	
+	return;
+}
+
+u16 eeprom_read16(_adapter * padapter, u16 reg) //ReadEEprom
+{
+
+	u16 x;
+	u16 data=0;
+#ifdef CONFIG_RTL8712
+	u8	tmp8_ori,tmp8_new,tmp8_clk_ori,tmp8_clk_new;
+	tmp8_ori= rtw_read8(padapter, 0x102502f1);
+	tmp8_new = tmp8_ori & 0xf7;
+	if(tmp8_ori != tmp8_new){	
+		rtw_write8(padapter, 0x102502f1, tmp8_new);
+		RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x102502f1=====\n"));
+	}
+	tmp8_clk_ori=rtw_read8(padapter,0x10250003);
+	tmp8_clk_new=tmp8_clk_ori|0x20;
+	if(tmp8_clk_new!=tmp8_clk_ori){
+		RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n"));
+		rtw_write8(padapter, 0x10250003, tmp8_clk_new);
+	}	
+#endif
+_func_enter_;		
+
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	// select EEPROM, reset bits, set _EECS
+	x = rtw_read8(padapter, EE_9346CR);
+
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+
+	x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
+	x |= _EEM1 | _EECS;
+	rtw_write8(padapter, EE_9346CR, (unsigned char)x);
+
+	// write the read opcode and register number in that order
+	// The opcode is 3bits in length, reg is 6 bits long
+	shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
+	shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+
+	// Now read the data (16 bits) in from the selected EEPROM word
+	data = shift_in_bits(padapter);
+
+	eeprom_clean(padapter);
+out:	
+#ifdef CONFIG_RTL8712
+	if(tmp8_clk_new!=tmp8_clk_ori)
+		rtw_write8(padapter, 0x10250003, tmp8_clk_ori);
+	if(tmp8_new!=tmp8_ori)
+		rtw_write8(padapter, 0x102502f1, tmp8_ori);
+
+#endif
+_func_exit_;		
+	return data;
+
+
+}
+
+
+
+
+//From even offset
+void eeprom_read_sz(_adapter * padapter, u16 reg, u8* data, u32 sz) 
+{
+
+	u16 x, data16;
+	u32 i;
+_func_enter_;		
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+	// select EEPROM, reset bits, set _EECS
+	x = rtw_read8(padapter, EE_9346CR);
+
+	if (rtw_is_surprise_removed(padapter)) {
+		RT_TRACE(_module_rtl871x_eeprom_c_, _drv_err_, ("padapter->bSurpriseRemoved==_TRUE"));
+		goto out;
+	}
+
+	x &= ~(_EEDI | _EEDO | _EESK | _EEM0);
+	x |= _EEM1 | _EECS;
+	rtw_write8(padapter, EE_9346CR, (unsigned char)x);
+
+	// write the read opcode and register number in that order
+	// The opcode is 3bits in length, reg is 6 bits long
+	shift_out_bits(padapter, EEPROM_READ_OPCODE, 3);
+	shift_out_bits(padapter, reg, padapter->EepromAddressSize);
+
+
+	for(i=0; i<sz; i+=2)
+	{
+		data16 = shift_in_bits(padapter);
+		data[i] = data16 & 0xff;
+		data[i+1] = data16 >>8;		
+	}
+
+	eeprom_clean(padapter);
+out:	
+_func_exit_;		
+
+
+
+}
+
+
+//addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg)
+u8 eeprom_read(_adapter * padapter, u32 addr_off, u8 sz, u8* rbuf)
+{
+	u8 quotient, remainder, addr_2align_odd;
+	u16 reg, stmp , i=0, idx = 0;
+_func_enter_;		
+	reg = (u16)(addr_off >> 1);
+	addr_2align_odd = (u8)(addr_off & 0x1);
+
+	if(addr_2align_odd) //read that start at high part: e.g  1,3,5,7,9,...
+	{
+		stmp = eeprom_read16(padapter, reg);
+		rbuf[idx++] = (u8) ((stmp>>8)&0xff); //return hogh-part of the short
+		reg++; sz--;
+	}
+	
+	quotient = sz >> 1;
+	remainder = sz & 0x1;
+
+	for( i=0 ; i < quotient; i++)
+	{
+		stmp = eeprom_read16(padapter, reg+i);
+		rbuf[idx++] = (u8) (stmp&0xff);
+		rbuf[idx++] = (u8) ((stmp>>8)&0xff);
+	}
+	
+	reg = reg+i;
+	if(remainder){ //end of read at lower part of short : 0,2,4,6,...
+		stmp = eeprom_read16(padapter, reg);
+		rbuf[idx] = (u8)(stmp & 0xff); 
+	}
+_func_exit_;		
+	return _TRUE;
+}
+
+
+
+VOID read_eeprom_content(_adapter *	padapter)
+{
+
+_func_enter_;		
+
+
+_func_exit_;		
+}
+
diff --git a/drivers/net/wireless/rtl8189es/core/rtw_ieee80211.c b/drivers/net/wireless/rtl8189es/core/rtw_ieee80211.c
new file mode 100644
index 000000000000..2ad3de506c8f
--- /dev/null
+++ b/drivers/net/wireless/rtl8189es/core/rtw_ieee80211.c
@@ -0,0 +1,2583 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *                                        
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _IEEE80211_C
+
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+#include <linux/fs.h>
+#endif 
+#include <drv_types.h>
+#include <linux/of.h>
+
+u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+u16 RTW_WPA_VERSION = 1;
+u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
+u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
+u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
+
+u16 RSN_VERSION_BSD = 1;
+u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
+u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
+u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
+u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
+//-----------------------------------------------------------
+// for adhoc-master to generate ie and provide supported-rate to fw 
+//-----------------------------------------------------------
+
+static u8 	WIFI_CCKRATES[] = 
+{(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)};
+
+static u8 	WIFI_OFDMRATES[] = 
+{(IEEE80211_OFDM_RATE_6MB),
+ (IEEE80211_OFDM_RATE_9MB),
+ (IEEE80211_OFDM_RATE_12MB),
+ (IEEE80211_OFDM_RATE_18MB),
+ (IEEE80211_OFDM_RATE_24MB),
+ IEEE80211_OFDM_RATE_36MB,
+ IEEE80211_OFDM_RATE_48MB,
+ IEEE80211_OFDM_RATE_54MB};
+
+
+int rtw_get_bit_value_from_ieee_value(u8 val)
+{
+	unsigned char dot11_rate_table[]={2,4,11,22,12,18,24,36,48,72,96,108,0}; // last element must be zero!!
+
+	int i=0;
+	while(dot11_rate_table[i] != 0) {
+		if (dot11_rate_table[i] == val)
+			return BIT(i);
+		i++;
+	}
+	return 0;
+}
+
+uint	rtw_is_cckrates_included(u8 *rate)
+{	
+		u32	i = 0;			
+
+		while(rate[i]!=0)
+		{		
+			if  (  (((rate[i]) & 0x7f) == 2)	|| (((rate[i]) & 0x7f) == 4) ||		
+			(((rate[i]) & 0x7f) == 11)  || (((rate[i]) & 0x7f) == 22) )		
+				return _TRUE;
+			i++;
+		}
+		
+		return _FALSE;
+}
+
+uint	rtw_is_cckratesonly_included(u8 *rate)
+{
+	u32 i = 0;
+
+
+	while(rate[i]!=0)
+	{
+			if  (  (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+				(((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22) )
+				return _FALSE;
+
+			i++;
+	}
+	
+	return _TRUE;
+
+}
+
+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
+{
+	if (channel > 14)
+	{
+		if ((rtw_is_cckrates_included(rate)) == _TRUE)
+			return WIRELESS_INVALID;
+		else
+			return WIRELESS_11A;
+	}	
+	else  // could be pure B, pure G, or B/G
+	{
+		if ((rtw_is_cckratesonly_included(rate)) == _TRUE)	
+			return WIRELESS_11B;
+		else if((rtw_is_cckrates_included(rate)) == _TRUE)
+			return 	WIRELESS_11BG;
+		else
+			return WIRELESS_11G;
+	}
+	
+}
+
+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source,
+				unsigned int *frlen)
+{
+	_rtw_memcpy((void *)pbuf, (void *)source, len);
+	*frlen = *frlen + len;
+	return (pbuf + len);
+}
+
+// rtw_set_ie will update frame length
+u8 *rtw_set_ie
+(
+	u8 *pbuf, 
+	sint index, 
+	uint len,
+	u8 *source, 
+	uint *frlen //frame length
+)
+{
+	*pbuf = (u8)index;
+
+	*(pbuf + 1) = (u8)len;
+
+	if (len > 0)
+		_rtw_memcpy((void *)(pbuf + 2), (void *)source, len);
+	
+	*frlen = *frlen + (len + 2);
+	
+	return (pbuf + len + 2);
+}
+
+inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+	u8 new_ch, u8 ch_switch_cnt)
+{
+	u8 ie_data[3];
+
+	ie_data[0] = ch_switch_mode;
+	ie_data[1] = new_ch;
+	ie_data[2] = ch_switch_cnt;
+	return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH,  3, ie_data, buf_len);
+}
+
+inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
+{
+	if (ch_offset == SCN)
+		return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	else if(ch_offset == SCA)
+		return HAL_PRIME_CHNL_OFFSET_UPPER;
+	else if(ch_offset == SCB)
+		return HAL_PRIME_CHNL_OFFSET_LOWER;
+
+	return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+}
+
+inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
+{
+	if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+		return SCN;
+	else if(ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+		return SCB;
+	else if(ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+		return SCA;
+
+	return SCN;
+}
+
+inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset)
+{
+	return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET,  1, &secondary_ch_offset, buf_len);
+}
+
+inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+	u8 flags, u16 reason, u16 precedence)
+{
+	u8 ie_data[6];
+
+	ie_data[0] = ttl;
+	ie_data[1] = flags;
+	RTW_PUT_LE16((u8*)&ie_data[2], reason);
+	RTW_PUT_LE16((u8*)&ie_data[4], precedence);
+
+	return rtw_set_ie(buf, 0x118,  6, ie_data, buf_len);
+}
+
+/*----------------------------------------------------------------------------
+index: the information element id index, limit is the limit for search
+-----------------------------------------------------------------------------*/
+u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
+{
+	sint tmp,i;
+	u8 *p;
+_func_enter_;
+	if (limit < 1){
+		_func_exit_;	
+		return NULL;
+	}
+
+	p = pbuf;
+	i = 0;
+	*len = 0;
+	while(1)
+	{
+		if (*p == index)
+		{
+			*len = *(p + 1);
+			return (p);
+		}
+		else
+		{
+			tmp = *(p + 1);
+			p += (tmp + 2);
+			i += (tmp + 2);
+		}
+		if (i >= limit)
+			break;
+	}
+_func_exit_;		
+	return NULL;
+}
+
+/**
+ * rtw_get_ie_ex - Search specific IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE
+ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE
+ *
+ * Returns: The address of the specific IE found, or NULL
+ */
+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
+{
+	uint cnt;
+	u8 *target_ie = NULL;
+
+
+	if(ielen)
+		*ielen = 0;
+
+	if(!in_ie || in_len<=0)
+		return target_ie;
+
+	cnt = 0;
+
+	while(cnt<in_len)
+	{
+		if(eid == in_ie[cnt]
+			&& ( !oui || _rtw_memcmp(&in_ie[cnt+2], oui, oui_len) == _TRUE))
+		{
+			target_ie = &in_ie[cnt];
+
+			if(ie)
+				_rtw_memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+			
+			if(ielen)
+				*ielen = in_ie[cnt+1]+2;
+
+			break;
+		}
+		else
+		{
+			cnt+=in_ie[cnt+1]+2; //goto next	
+		}		
+
+	}	
+
+	return target_ie;
+}
+
+/**
+ * rtw_ies_remove_ie - Find matching IEs and remove
+ * @ies: Address of IEs to search
+ * @ies_len: Pointer of length of ies, will update to new length
+ * @offset: The offset to start scarch
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ *
+ * Returns: _SUCCESS: ies is updated, _FAIL: not updated
+ */
+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len)
+{
+	int ret = _FAIL;
+	u8 *target_ie;
+	u32 target_ielen;
+	u8 *start;
+	uint search_len;
+	
+	if(!ies || !ies_len || *ies_len <= offset)
+		goto exit;
+
+	start = ies + offset;
+	search_len = *ies_len - offset;
+
+	while (1) {
+		target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
+		if (target_ie && target_ielen) {
+			u8 buf[MAX_IE_SZ] = {0};
+			u8 *remain_ies = target_ie + target_ielen;
+			uint remain_len = search_len - (remain_ies - start);
+			
+			_rtw_memcpy(buf, remain_ies, remain_len);
+			_rtw_memcpy(target_ie, buf, remain_len);
+			*ies_len = *ies_len - target_ielen;
+			ret = _SUCCESS;
+
+			start = target_ie;
+			search_len = remain_len;
+		} else {
+			break;
+		}
+	}
+exit:
+	return ret;
+}
+
+void rtw_set_supported_rate(u8* SupportedRates, uint mode) 
+{
+_func_enter_;
+
+	_rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+	
+	switch (mode)
+	{
+		case WIRELESS_11B:
+			_rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+			break;
+		
+		case WIRELESS_11G:
+		case WIRELESS_11A:
+		case WIRELESS_11_5N:
+		case WIRELESS_11A_5N://Todo: no basic rate for ofdm ?
+		case WIRELESS_11_5AC:
+			_rtw_memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+			break;
+		
+		case WIRELESS_11BG:
+		case WIRELESS_11G_24N:
+		case WIRELESS_11_24N:
+		case WIRELESS_11BG_24N:
+			_rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+			_rtw_memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+			break;
+	
+	}
+_func_exit_;	
+}
+
+uint	rtw_get_rateset_len(u8	*rateset)
+{
+	uint i = 0;
+_func_enter_;	
+	while(1)
+	{
+		if ((rateset[i]) == 0)
+			break;
+			
+		if (i > 12)
+			break;
+			
+		i++;			
+	}
+_func_exit_;		
+	return i;
+}
+
+int rtw_generate_ie(struct registry_priv *pregistrypriv)
+{
+	u8	wireless_mode;
+	int 	sz = 0, rateLen;
+	WLAN_BSSID_EX*	pdev_network = &pregistrypriv->dev_network;
+	u8*	ie = pdev_network->IEs;
+	
+_func_enter_;		
+
+	//timestamp will be inserted by hardware
+	sz += 8;	
+	ie += sz;
+	
+	//beacon interval : 2bytes
+	*(u16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);//BCN_INTERVAL;
+	sz += 2; 
+	ie += 2;
+	
+	//capability info
+	*(u16*)ie = 0;
+	
+	*(u16*)ie |= cpu_to_le16(cap_IBSS);
+
+	if(pregistrypriv->preamble == PREAMBLE_SHORT)
+		*(u16*)ie |= cpu_to_le16(cap_ShortPremble);
+	
+	if (pdev_network->Privacy)
+		*(u16*)ie |= cpu_to_le16(cap_Privacy);
+	
+	sz += 2;
+	ie += 2;
+	
+	//SSID
+	ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
+	
+	//supported rates
+	if(pregistrypriv->wireless_mode == WIRELESS_11ABGN)
+	{
+		if(pdev_network->Configuration.DSConfig > 14)
+			wireless_mode = WIRELESS_11A_5N;
+		else
+			wireless_mode = WIRELESS_11BG_24N;
+	}
+	else
+	{
+		wireless_mode = pregistrypriv->wireless_mode;
+	}
+	
+	rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode) ;
+	
+	rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
+
+	if (rateLen > 8)
+	{
+		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
+		//ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
+	}
+	else
+	{
+		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
+	}
+
+	//DS parameter set
+	ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
+
+
+	//IBSS Parameter Set
+	
+	ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
+
+	if (rateLen > 8)
+	{		
+		ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
+	}
+	
+#ifdef CONFIG_80211N_HT
+	//HT Cap.
+	if(((pregistrypriv->wireless_mode&WIRELESS_11_5N)||(pregistrypriv->wireless_mode&WIRELESS_11_24N)) 
+		&& (pregistrypriv->ht_enable==_TRUE))
+	{
+		//todo:
+	}
+#endif //CONFIG_80211N_HT
+
+	//pdev_network->IELength =  sz; //update IELength
+
+_func_exit_;
+
+	//return _SUCCESS;
+
+	return sz;
+
+}
+
+bool rtw_regsty_adjust_chbw(struct registry_priv *regsty, u8 req_ch, u8 *req_bw, u8 *req_offset)
+{
+	u8 regsty_allowed_bw;
+
+	if (req_ch <= 14)
+		regsty_allowed_bw = regsty->bw_mode & 0x0F;
+	else
+		regsty_allowed_bw = regsty->bw_mode >> 4;
+
+	if (regsty_allowed_bw == 2 && *req_bw > CHANNEL_WIDTH_80)
+		*req_bw = CHANNEL_WIDTH_80;
+	else if (regsty_allowed_bw == 1 && *req_bw > CHANNEL_WIDTH_40)
+		*req_bw = CHANNEL_WIDTH_40;
+	else if (regsty_allowed_bw == 0 && *req_bw > CHANNEL_WIDTH_20) {
+		*req_bw = CHANNEL_WIDTH_20;
+		*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	} else
+		return _FALSE;
+
+	return _TRUE;
+}
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
+{
+	int len;
+	u16 val16;
+	unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
+	u8 *pbuf = pie;
+	int limit_new = limit;
+
+	while(1) 
+	{
+		pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
+
+		if (pbuf) {
+
+			//check if oui matches...
+			if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == _FALSE) {
+
+				goto check_next_ie;
+			}
+
+			//check version...
+			_rtw_memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
+
+			val16 = le16_to_cpu(val16);
+			if (val16 != 0x0001)
+				goto check_next_ie;
+
+			*wpa_ie_len = *(pbuf + 1);
+
+			return pbuf;
+
+		}
+		else {
+
+			*wpa_ie_len = 0;
+			return NULL;
+		}
+
+check_next_ie:
+
+		limit_new = limit - (pbuf - pie) - 2 - len;
+
+		if (limit_new <= 0)
+			break;
+
+		pbuf += (2 + len);
+
+	}
+
+	*wpa_ie_len = 0;
+
+	return NULL;
+
+}
+
+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
+{	
+
+	return rtw_get_ie(pie, _WPA2_IE_ID_,rsn_ie_len, limit);
+
+}
+
+int rtw_get_wpa_cipher_suite(u8 *s)
+{
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP104;
+
+	return 0;
+}
+
+int rtw_get_wpa2_cipher_suite(u8 *s)
+{
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == _TRUE)
+		return WPA_CIPHER_WEP104;
+
+	return 0;
+}
+
+
+int rtw_parse_wpa_ie(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+	int i, ret=_SUCCESS;
+	int left, count;
+	u8 *pos;
+	u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
+
+	if (wpa_ie_len <= 0) {
+		/* No WPA IE - fail silently */
+		return _FAIL;
+	}
+
+	
+	if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
+	   (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != _TRUE) )
+	{		
+		return _FAIL;
+	}
+
+	pos = wpa_ie;
+
+	pos += 8;
+	left = wpa_ie_len - 8;	
+
+
+	//group_cipher
+	if (left >= WPA_SELECTOR_LEN) {
+
+		*group_cipher = rtw_get_wpa_cipher_suite(pos);
+		
+		pos += WPA_SELECTOR_LEN;
+		left -= WPA_SELECTOR_LEN;
+		
+	} 
+	else if (left > 0)
+	{
+		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left));
+		
+		return _FAIL;
+	}
+
+
+	//pairwise_cipher
+	if (left >= 2)
+	{		
+                //count = le16_to_cpu(*(u16*)pos);	
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), "
+				   		"count %u left %u", __FUNCTION__, count, left));
+			return _FAIL;
+		}
+		
+		for (i = 0; i < count; i++)
+		{
+			*pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
+			
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+		
+	} 
+	else if (left == 1)
+	{
+		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)",   __FUNCTION__));
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s : there has 802.1x auth\n", __FUNCTION__));
+				*is_8021x = 1;
+			}
+		}
+	}
+	
+	return ret;
+	
+}
+
+int rtw_parse_wpa2_ie(u8* rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+	int i, ret=_SUCCESS;
+	int left, count;
+	u8 *pos;
+	u8 SUITE_1X[4] = {0x00,0x0f, 0xac, 0x01};
+
+	if (rsn_ie_len <= 0) {
+		/* No RSN IE - fail silently */
+		return _FAIL;
+	}
+
+
+	if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2)))
+	{		
+		return _FAIL;
+	}
+	
+	pos = rsn_ie;
+	pos += 4;
+	left = rsn_ie_len - 4;	
+
+	//group_cipher
+	if (left >= RSN_SELECTOR_LEN) {
+
+		*group_cipher = rtw_get_wpa2_cipher_suite(pos);
+		
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+		
+	} else if (left > 0) {
+		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left));
+		return _FAIL;
+	}
+
+	//pairwise_cipher
+	if (left >= 2)
+	{		
+	        //count = le16_to_cpu(*(u16*)pos);
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), "
+				  		 "count %u left %u", __FUNCTION__, count, left));
+			return _FAIL;
+		}
+		
+		for (i = 0; i < count; i++)
+		{			
+			*pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
+			
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+
+	} 
+	else if (left == 1)
+	{
+		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)",  __FUNCTION__));
+		
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s (): there has 802.1x auth\n", __FUNCTION__));
+				*is_8021x = 1;
+			}
+		}
+	}
+
+	return ret;
+	
+}
+
+//#ifdef CONFIG_WAPI_SUPPORT
+int rtw_get_wapi_ie(u8 *in_ie,uint in_len,u8 *wapi_ie,u16 *wapi_len)
+{
+	int len = 0;
+	u8 authmode, i;
+	uint 	cnt;
+	u8 wapi_oui1[4]={0x0,0x14,0x72,0x01};
+	u8 wapi_oui2[4]={0x0,0x14,0x72,0x02};
+
+_func_enter_;
+
+	if(wapi_len)
+		*wapi_len = 0;
+
+	if(!in_ie || in_len<=0)
+		return len;
+
+	cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
+	
+	while(cnt<in_len)
+	{
+		authmode=in_ie[cnt];
+
+		//if(authmode==_WAPI_IE_)
+		if(authmode==_WAPI_IE_ && (_rtw_memcmp(&in_ie[cnt+6], wapi_oui1,4)==_TRUE ||
+				       	_rtw_memcmp(&in_ie[cnt+6], wapi_oui2,4)==_TRUE))
+		{
+			if (wapi_ie) {
+				_rtw_memcpy(wapi_ie, &in_ie[cnt],in_ie[cnt+1]+2);
+
+				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
+					RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+								wapi_ie[i],wapi_ie[i+1],wapi_ie[i+2],wapi_ie[i+3],wapi_ie[i+4],
+								wapi_ie[i+5],wapi_ie[i+6],wapi_ie[i+7]));
+				}
+			}
+
+			if(wapi_len)
+				*wapi_len=in_ie[cnt+1]+2;
+			
+			cnt+=in_ie[cnt+1]+2;  //get next
+		}
+		else
+		{
+			cnt+=in_ie[cnt+1]+2;   //get next
+		}
+	}
+
+	if(wapi_len)
+		len = *wapi_len;
+
+_func_exit_;
+
+	return len;
+
+}
+//#endif
+
+int rtw_get_sec_ie(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len)
+{
+	u8 authmode, sec_idx, i;
+	u8 wpa_oui[4]={0x0,0x50,0xf2,0x01};
+	uint 	cnt;
+	
+_func_enter_;
+
+	//Search required WPA or WPA2 IE and copy to sec_ie[ ]
+	
+	cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
+	
+	sec_idx=0;
+		
+	while(cnt<in_len)
+	{
+		authmode=in_ie[cnt];
+		
+		if((authmode==_WPA_IE_ID_)&&(_rtw_memcmp(&in_ie[cnt+2], &wpa_oui[0],4)==_TRUE))
+		{	
+				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw_get_wpa_ie: sec_idx=%d in_ie[cnt+1]+2=%d\n",sec_idx,in_ie[cnt+1]+2));		
+
+				if (wpa_ie) {
+				_rtw_memcpy(wpa_ie, &in_ie[cnt],in_ie[cnt+1]+2);
+
+				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
+						RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+									wpa_ie[i],wpa_ie[i+1],wpa_ie[i+2],wpa_ie[i+3],wpa_ie[i+4],
+									wpa_ie[i+5],wpa_ie[i+6],wpa_ie[i+7]));
+					}
+				}
+
+				*wpa_len=in_ie[cnt+1]+2;
+				cnt+=in_ie[cnt+1]+2;  //get next
+		}
+		else
+		{
+			if(authmode==_WPA2_IE_ID_)
+			{
+				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n get_rsn_ie: sec_idx=%d in_ie[cnt+1]+2=%d\n",sec_idx,in_ie[cnt+1]+2));		
+
+				if (rsn_ie) {
+				_rtw_memcpy(rsn_ie, &in_ie[cnt],in_ie[cnt+1]+2);
+
+				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
+						RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+									rsn_ie[i],rsn_ie[i+1],rsn_ie[i+2],rsn_ie[i+3],rsn_ie[i+4],
+									rsn_ie[i+5],rsn_ie[i+6],rsn_ie[i+7]));
+					}
+				}
+
+				*rsn_len=in_ie[cnt+1]+2;
+				cnt+=in_ie[cnt+1]+2;  //get next
+			}
+			else
+			{
+				cnt+=in_ie[cnt+1]+2;   //get next
+			}	
+		}
+		
+	}
+	
+_func_exit_;
+
+	return (*rsn_len+*wpa_len);
+	
+}
+
+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
+{	
+	u8 match = _FALSE;
+	u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04};
+	
+	if(ie_ptr == NULL) return match;
+	
+	eid = ie_ptr[0];
+	
+	if((eid==_WPA_IE_ID_)&&(_rtw_memcmp(&ie_ptr[2], wps_oui, 4)==_TRUE))
+	{			
+		//DBG_8192C("==> found WPS_IE.....\n");
+		*wps_ielen = ie_ptr[1]+2;			
+		match=_TRUE;
+	}	
+	return match;
+}
+
+u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type)
+{
+	u8*	wps = NULL;
+
+	DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type );
+	switch( frame_type )
+	{
+		case 1:
+		case 3:
+		{	//	Beacon or Probe Response
+			wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen);
+			break;
+		}
+		case 2:
+		{	//	Probe Request
+			wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen);
+			break;
+		}
+	}
+	return wps;
+}
+
+/**
+ * rtw_get_wps_ie - Search WPS IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
+ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
+ *
+ * Returns: The address of the WPS IE found, or NULL
+ */
+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *w