Merge branch imgsystems/4.1-imgsystems into aosp/master

Conflicts:
    arch/mips/boot/dts/pistachio/Makefile
    arch/mips/boot/dts/pistachio/pistachio_marduk.dts

Change-Id: Ibddb2db255830eb640d1df21b282b6a51369ea7c
diff --git a/Documentation/devicetree/bindings/misc/uboot-bootcount.txt b/Documentation/devicetree/bindings/misc/uboot-bootcount.txt
new file mode 100644
index 0000000..7ab1134
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/uboot-bootcount.txt
@@ -0,0 +1,34 @@
+U-Boot bootcount driver
+
+This driver implements the Linux kernel half of the boot count feature -
+the boot counter can only be reset after it is clear that the
+application has been started and is running correctly, which usually
+can only be determined by the application code itself. Thus the reset
+of the boot counter must be done by application code, which thus needs
+an appropriate driver.
+
+Required feature by the Carrier Grade Linux Requirements Definition;
+see for example document "Carrier Grade Linux Requirements Definition
+Overview V3.0" at
+
+http://www.linuxfoundation.org/collaborate/workgroups/cgl/requirements#SMM.6.0_Boot_Cycle_Detection
+
+        Description: OSDL CGL specifies that carrier grade Linux
+        shall provide support for detecting a repeating reboot cycle
+        due to recurring failures. This detection should happen in
+        user space before system services are started.
+
+This driver provides read/write access to the U-Boot bootcounter
+through sysfs file.
+
+Required properties:
+
+  - compatible : should be "uboot,bootcount"
+  - reg: the address of the bootcounter
+
+Example:
+
+bootcount@1c23000 {
+	compatible = "uboot,bootcount";
+	reg = <0x23060 0x1>;
+};
diff --git a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
index 3e1356b..338a015 100644
--- a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
+++ b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
@@ -15,11 +15,12 @@
 	- reset-gpio:		GPIO spec for the RESET pin
 Optional properties:
 	- amplified:		include if the CC2520 is connected to a CC2591 amplifier
+	- #clock-cells		from common clock binding; shall be set to 0
+				required if extclock-freq is specified
 	- extclock-freq:	frequency setting of external clock generator, should be
 				between 1000000-16000000 (check datasheet for supported values)
 				extclock is disabled if extclock-freq = <0>, if not specified
 				defaults to 1MHz (reset value)
-
 Example:
 	cc2520@0 {
 		compatible = "ti,cc2520";
@@ -34,5 +35,6 @@
 		cca-gpio = <&gpio1 16 0>;
 		vreg-gpio = <&gpio0 31 0>;
 		reset-gpio = <&gpio1 12 0>;
+		#clock-cells = <0>;
 		extclock-freq = <16000000>;
 	};
diff --git a/arch/mips/boot/dts/pistachio/pistachio.dtsi b/arch/mips/boot/dts/pistachio/pistachio.dtsi
index 05222e8..cb10b12 100644
--- a/arch/mips/boot/dts/pistachio/pistachio.dtsi
+++ b/arch/mips/boot/dts/pistachio/pistachio.dtsi
@@ -797,14 +797,14 @@
 		};
 
 		dac_clk_pin: dac-clk-pin {
-			dac-clk {
+			pin_dac_clk: dac-clk {
 				pins = "mfio45";
 				function = "i2s_dac_clk";
 			};
 		};
 
 		i2s_mclk_pin: i2s-mclk-pin {
-			i2s-mclk {
+			pin_i2s_mclk: i2s-mclk {
 				pins = "mfio36";
 				function = "i2s_out";
 			};
@@ -826,7 +826,7 @@
 		};
 
 		i2s_out_pins: i2s-out-pins {
-			i2s-out {
+			pins_i2s_out: i2s-out {
 				pins = "mfio37", "mfio38", "mfio39",
 				       "mfio40", "mfio41", "mfio42",
 				       "mfio43", "mfio44";
@@ -878,7 +878,7 @@
 
 	wdt: watchdog@18102100 {
 		compatible = "img,pdc-wdt";
-		reg = <0x18102100 0x100>;
+		reg = <0x18102100 0x20>;
 		interrupts = <GIC_SHARED 52 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&clk_periph PERIPH_CLK_WD>, <&cr_periph SYS_CLK_WD>;
 		clock-names = "wdt", "sys";
diff --git a/arch/mips/boot/dts/pistachio/pistachio_beetle.dtsi b/arch/mips/boot/dts/pistachio/pistachio_beetle.dtsi
index 6b7d4b9..11ae16e 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_beetle.dtsi
+++ b/arch/mips/boot/dts/pistachio/pistachio_beetle.dtsi
@@ -50,19 +50,32 @@
 	};
 };
 
+&uccpsystem {
+	status = "okay";
+};
+
+&uccphostport {
+	status = "okay";
+};
+
+&uccpbthp {
+	status = "okay";
+};
+
+&uccpdummyhp {
+	status = "okay";
+};
+
 &uart0 {
-	pinctrl-0 = <&uart0_pins>, <&uart0_rts_cts_pins>;
-	pinctrl-names = "default";
-
 	status = "okay";
+	assigned-clock-rates = <114278400>, <1843200>;
 };
 
-&uart1 {
+&sdhost {
 	status = "okay";
-};
 
-&usb {
-	status = "okay";
+	bus-width = <4>;
+	disable-wp;
 };
 
 &i2c3 {
@@ -85,7 +98,7 @@
 	status = "okay";
 	mac-address0 = [0123456789AC];
 	mac-address1 = [0123456789AD];
-	rf-params = [1E00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808];
+	rf-params = [1A1f24292e33383c4045484d5157595d6165686d7177263d3135393c41454a4d505356595c5f6164676c7023282c3135393d4145494d53565a5d616466686b6f20252b3134373c4144484d52555a5e62666a6f747923282c31363a3e4245494e51575b5f63666b71767a1a1f24292e33383c4045484d5055585b5e62666a7223272e32363a3e43474c4f53585b5f63666a6f7479252a2e32373b3f43474b4f55585c5f626467696c7223272a3134393d4044494e52565a5d6165696d727425292f33383c4043474c5054595d6165696d73787c0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B];
 	num_streams = [02];
 	io-channels = <&adc 4>;
 };
diff --git a/arch/mips/boot/dts/pistachio/pistachio_beetle_boardtest.dts b/arch/mips/boot/dts/pistachio/pistachio_beetle_boardtest.dts
index bd9bbd3..fea3fb8 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_beetle_boardtest.dts
+++ b/arch/mips/boot/dts/pistachio/pistachio_beetle_boardtest.dts
@@ -7,102 +7,41 @@
  * published by the Free Software Foundation.
  */
 
-/dts-v1/;
+#include "pistachio_beetle_mbub.dts"
 
-#include "pistachio_beetle.dtsi"
-#include <dt-bindings/sound/pistachio-audio.h>
-
-/ {
-	model = "IMG Pistachio Concerto mBuB with a Beetle module";
-	compatible = "img,pistachio-bub", "img,pistachio";
-
-	aliases {
-		serial0 = &uart0;
-		serial1 = &uart1;
-	};
-
-	chosen {
-		bootargs = "console=ttyS1,115200n8 earlycon=uart8250,mmio32,0x18101500,115200 root=/dev/sda1 rootwait ro";
-	};
-
-	reg_1v8: fixed-regulator {
-		compatible = "regulator-fixed";
-		regulator-name = "aux_adc_vref";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-		regulator-boot-on;
-	};
-
-	supply5v0: supply5v0@0 {
-		compatible = "regulator-fixed";
-		regulator-name = "5V-supply";
-		regulator-min-microvolt = <5000000>;
-		regulator-max-microvolt = <5000000>;
-	};
-
-	pistachio_audio_card {
-		compatible = "img,pistachio-audio";
-
-		clocks = <&clk_core CLK_AUDIO_PLL>,
-			 <&clk_core CLK_I2S>,
-			 <&clk_core CLK_AUDIO>;
-		clock-names = "audio_pll", "i2s_mclk", "dac_clk";
-
-		img,cr-periph = <&cr_periph>;
-		img,event-timer = <&event_timer>;
-
-		parallel-out {
-			cpu-dai = <&parallel_out>;
-			sound-dai = <&internal_dac>;
-		};
-
-	};
-
+&ir {
+	status = "disabled";
 };
 
-&uccpsystem {
-	status = "okay";
+&pwm {
+	status = "disabled";
 };
 
-&uccphostport {
-	status = "okay";
+&i2c0 {
+	status = "disabled";
 };
 
-&uccpbthp {
-	status = "okay";
+&i2c1 {
+	status = "disabled";
 };
 
-&uccpdummyhp {
-	status = "okay";
+&i2c2 {
+	status = "disabled";
 };
 
-&uart0 {
-	status = "okay";
-	assigned-clock-rates = <114278400>, <1843200>;
+&i2s_out {
+	status = "disabled";
 };
 
-&uart1 {
-	status = "okay";
+&i2s_in {
+	status = "disabled";
 };
 
-&usb {
-	status = "okay";
+&spdif_out {
+	status = "disabled";
 };
 
-&enet {
-	status = "okay";
-
-	mac-address = [0123456789AB];
-};
-
-&sdhost {
-	status = "okay";
-
-	bus-width = <4>;
-	disable-wp;
-};
-
-&parallel_out {
-	status = "okay";
+&spdif_in {
+	status = "disabled";
 };
 
diff --git a/arch/mips/boot/dts/pistachio/pistachio_beetle_mbub.dts b/arch/mips/boot/dts/pistachio/pistachio_beetle_mbub.dts
index 49be49c..ad152b5 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_beetle_mbub.dts
+++ b/arch/mips/boot/dts/pistachio/pistachio_beetle_mbub.dts
@@ -11,9 +11,10 @@
 
 #include "pistachio_beetle.dtsi"
 #include <dt-bindings/sound/pistachio-audio.h>
+#include "pistachio_board_uboot.dtsi"
 
 / {
-	model = "IMG Pistachio Concerto mBuB with a Beetle module";
+	model = "Beetle Bring-Up Board";
 	compatible = "img,pistachio-bub", "img,pistachio";
 
 	aliases {
@@ -95,25 +96,16 @@
 	};
 };
 
-&uccpsystem {
-	status = "okay";
+&pin_i2s_mclk {
+	drive-strength = <2>;
 };
 
-&uccphostport {
-	status = "okay";
+&pin_dac_clk {
+	drive-strength = <2>;
 };
 
-&uccpbthp {
-	status = "okay";
-};
-
-&uccpdummyhp {
-	status = "okay";
-};
-
-&uart0 {
-	status = "okay";
-	assigned-clock-rates = <114278400>, <1843200>;
+&pins_i2s_out {
+	drive-strength = <2>;
 };
 
 &uart1 {
@@ -136,13 +128,6 @@
 	mac-address = [0123456789AB];
 };
 
-&sdhost {
-	status = "okay";
-
-	bus-width = <4>;
-	disable-wp;
-};
-
 &ir {
 	status = "okay";
 };
diff --git a/arch/mips/boot/dts/pistachio/pistachio_board_uboot.dtsi b/arch/mips/boot/dts/pistachio/pistachio_board_uboot.dtsi
new file mode 100644
index 0000000..2fde543
--- /dev/null
+++ b/arch/mips/boot/dts/pistachio/pistachio_board_uboot.dtsi
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * This program 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.
+ */
+
+
+/ {
+	uboot-count {
+		compatible = "uboot,bootcount";
+		reg = <0x18102120 0x4>;
+	};
+};
diff --git a/arch/mips/boot/dts/pistachio/pistachio_bub.dts b/arch/mips/boot/dts/pistachio/pistachio_bub.dts
index 0750ca8..9e9aee4 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_bub.dts
+++ b/arch/mips/boot/dts/pistachio/pistachio_bub.dts
@@ -10,6 +10,7 @@
 /dts-v1/;
 
 #include "pistachio_bub_audio_no_daughterboard_example.dtsi"
+#include "pistachio_board_uboot.dtsi"
 
 / {
 	model = "IMG Pistachio BuB";
diff --git a/arch/mips/boot/dts/pistachio/pistachio_concerto.dtsi b/arch/mips/boot/dts/pistachio/pistachio_concerto.dtsi
index 5e35f4d..137afb0 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_concerto.dtsi
+++ b/arch/mips/boot/dts/pistachio/pistachio_concerto.dtsi
@@ -31,9 +31,10 @@
 	cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>;
 
 	flash@0 {
-		compatible = "spidev";
+		compatible = "jedec,spi-nor";
 		reg = <0>;
 		spi-max-frequency = <50000000>;
+		linux,mtd-name = "spi-nor";
 	};
 
 	flash@1 {
@@ -44,22 +45,29 @@
 		spi-rx-bus-width = <4>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+		linux,mtd-name = "spi-nand";
 	};
 };
 
+&uccpsystem {
+	status = "okay";
+};
+
+&uccphostport {
+	status = "okay";
+};
+
+&uccpbthp {
+	status = "okay";
+};
+
+&uccpdummyhp {
+	status = "okay";
+};
+
 &uart0 {
-	pinctrl-0 = <&uart0_pins>, <&uart0_rts_cts_pins>;
-	pinctrl-names = "default";
-
 	status = "okay";
-};
-
-&uart1 {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
+	assigned-clock-rates = <114278400>, <1843200>;
 };
 
 &i2c3 {
@@ -67,16 +75,20 @@
 	clock-frequency = <400000>;
 };
 
-//&i2s_out {
-//	status = "okay";
-//};
-
-//&i2s_in {
-//	status = "okay";
-//};
+&sdhost {
+	status = "okay";
+};
 
 &adc {
 	status = "okay";
 
 	vref-supply = <&adc_1v8>;
 };
+
+&wifi {
+       status = "okay";
+       mac-address0 = [0123456789AC];
+       mac-address1 = [0123456789AD];
+       rf-params = [1E00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808];
+       num_streams = [02];
+};
diff --git a/arch/mips/boot/dts/pistachio/pistachio_concerto_mbub.dts b/arch/mips/boot/dts/pistachio/pistachio_concerto_mbub.dts
index b0d8689..afddda8 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_concerto_mbub.dts
+++ b/arch/mips/boot/dts/pistachio/pistachio_concerto_mbub.dts
@@ -9,11 +9,12 @@
 
 /dts-v1/;
 
-#include "pistachio.dtsi"
+#include "pistachio_concerto.dtsi"
 #include <dt-bindings/sound/pistachio-audio.h>
+#include "pistachio_board_uboot.dtsi"
 
 / {
-	model = "IMG Pistachio Concerto mBuB";
+	model = "Concerto Bring-Up-Board";
 	compatible = "img,pistachio-bub", "img,pistachio";
 
 	aliases {
@@ -101,53 +102,6 @@
 	};
 };
 
-&spfi1 {
-	status = "okay";
-
-	pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>;
-	pinctrl-names = "default";
-	cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>;
-
-	flash@0 {
-		compatible = "jedec,spi-nor";
-		reg = <0>;
-		spi-max-frequency = <50000000>;
-		linux,mtd-name = "spi-nor";
-	};
-
-	flash@1 {
-		compatible = "gigadevice,gd5f";
-		reg = <1>;
-		spi-max-frequency = <50000000>;
-		nand-on-flash-bbt;
-		spi-rx-bus-width = <4>;
-		#address-cells = <1>;
-		#size-cells = <1>;
-		linux,mtd-name = "spi-nand";
-	};
-};
-
-&uccpsystem {
-	status = "okay";
-};
-
-&uccphostport {
-	status = "okay";
-};
-
-&uccpbthp {
-	status = "okay";
-};
-
-&uccpdummyhp {
-	status = "okay";
-};
-
-&uart0 {
-	status = "okay";
-	assigned-clock-rates = <114278400>, <1843200>;
-};
-
 &uart1 {
 	status = "okay";
 };
@@ -162,10 +116,6 @@
 	mac-address = [0123456789AB];
 };
 
-&sdhost {
-	status = "okay";
-};
-
 &ir {
 	status = "okay";
 };
@@ -198,19 +148,6 @@
 	clock-frequency = <400000>;
 };
 
-&i2c3 {
-	status = "okay";
-	clock-frequency = <400000>;
-};
-
-&wifi {
-       status = "okay";
-       mac-address0 = [0123456789AC];
-       mac-address1 = [0123456789AD];
-       rf-params = [1E00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808];
-       num_streams = [02];
-};
-
 &i2s_out {
 	status = "okay";
 };
diff --git a/arch/mips/boot/dts/pistachio/pistachio_marduk.dts b/arch/mips/boot/dts/pistachio/pistachio_marduk.dts
index d626837..003271a 100644
--- a/arch/mips/boot/dts/pistachio/pistachio_marduk.dts
+++ b/arch/mips/boot/dts/pistachio/pistachio_marduk.dts
@@ -10,6 +10,7 @@
 
 #include "pistachio.dtsi"
 #include <dt-bindings/sound/pistachio-audio.h>
+#include "pistachio_board_uboot.dtsi"
 
 / {
 	model = "IMG Marduk";
@@ -38,14 +39,6 @@
 		regulator-boot-on;
 	};
 
-	/* EXT clock from cc2520 is fed to sc16is752 */
-	cc2520_ext_clk: cc2520-ext-clk {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <16000000>;
-		clock-output-names = "cc2520_ext_clock";
-        };
-
 	pistachio_audio_card {
 		compatible = "img,pistachio-audio";
 
@@ -81,6 +74,13 @@
 		i2s-in {
 			cpu-dai = <&i2s_in>;
 			format = "i2s";
+
+			ak5720vt {
+				mclk = <PISTACHIO_MCLK_I2S>;
+				mclk-fs = <256>;
+				mclk-min-freq = <8192000>;
+				mclk-max-freq = <24576000>;
+			};
 		};
 	};
 
@@ -148,7 +148,7 @@
 	cs-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>, <&gpio0 2 GPIO_ACTIVE_HIGH>,
 			<&gpio1 12 GPIO_ACTIVE_HIGH>, <&gpio1 13 GPIO_ACTIVE_HIGH>;
 
-	cc2520@0 {
+	cc2520: cc2520@0 {
 		compatible = "ti,cc2520";
 		reg = <0>;
 		spi-max-frequency = <4000000>;
@@ -158,13 +158,14 @@
 		cca-gpio = <&gpio3 6 GPIO_ACTIVE_HIGH>;
 		vreg-gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>;
 		reset-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+		#clock-cells = <0>;
 		extclock-freq = <16000000>;
 	};
 
 	sc16is752: sc16is752@1 {
 		compatible = "nxp,sc16is752";
 		reg = <1>;
-		clocks = <&cc2520_ext_clk>;
+		clocks = <&cc2520 0>;
 		spi-max-frequency = <4000000>;
 		interrupt-parent = <&gpio0>;
 		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
@@ -265,6 +266,7 @@
 &adc {
 	status = "okay";
 	vref-supply = <&reg_1v8>;
+	adc-reserved-channels = <0x10>;
 };
 
 &i2c2 {
@@ -281,7 +283,7 @@
        status = "okay";
        mac-address0 = [0019f5ffff01];
        mac-address1 = [0019f5ffff02];
-       rf-params = [1E00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F00000000002426292A2C2E3237393F454A52576066000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F000000002B2C3033373A3D44474D51575A61656B6F0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808];
+       rf-params = [1A1c1f24292e33383c4045484d5157595d6165686d712023263d3135393c41454a4d505356595c5f6164672023282c3135393d4145494d53565a5e626567696c1c20252b3134373c4144484d52555a5e62666a6f742023282c31363a3e4245494e51575b5f63666b71761c1f24292e33383c4045494d5155585b5e62666a6f1e22262d3135393d42464b4e52575a5c6064676b702023282c3135393d4145494d5356595b5e606366692023272a31363b3f44484c5054575a5e6165696d711f2225292f33383c4043474c5054595d6165696d732828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828];
        num_streams = [02];
 };
 
diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig
index 2c602de..260f6c2 100644
--- a/arch/mips/configs/pistachio_defconfig
+++ b/arch/mips/configs/pistachio_defconfig
@@ -164,11 +164,13 @@
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SPI_NAND=y
 CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_WINBOND_OTP=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BLOCK=y
 CONFIG_ZRAM=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_SRAM=y
+CONFIG_UBOOT_BOOTCOUNT=y
 CONFIG_ATU=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -224,7 +226,7 @@
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
 CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_SERIAL_SC16IS7XX=m
+CONFIG_SERIAL_SC16IS7XX=y
 # CONFIG_SERIAL_SC16IS7XX_I2C is not set
 CONFIG_SERIAL_SC16IS7XX_SPI=y
 CONFIG_HW_RANDOM=y
@@ -335,7 +337,7 @@
 CONFIG_JOLIET=y
 CONFIG_ZISOFS=y
 CONFIG_UDF_FS=m
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_ECRYPT_FS=y
@@ -350,9 +352,9 @@
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_DEFAULT="utf8"
-CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_MAGIC_SYSRQ=y
@@ -385,3 +387,4 @@
 CONFIG_CRC7=m
 CONFIG_LIBCRC32C=m
 # CONFIG_XZ_DEC_X86 is not set
+CONFIG_MAC80211_RC_MINSTREL_VHT=y
diff --git a/arch/mips/configs/pistachio_prodtest_defconfig b/arch/mips/configs/pistachio_prodtest_defconfig
new file mode 100644
index 0000000..74bea90
--- /dev/null
+++ b/arch/mips/configs/pistachio_prodtest_defconfig
@@ -0,0 +1,390 @@
+CONFIG_MACH_PISTACHIO=y
+CONFIG_PISTACHIO_GPTIMER_CLKSRC=y
+CONFIG_MIPS_MT_SMP=y
+CONFIG_MIPS_CPS=y
+# CONFIG_COMPACTION is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_CMA=y
+CONFIG_ZSMALLOC=y
+CONFIG_NR_CPUS=4
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZO=y
+CONFIG_DEFAULT_HOSTNAME="localhost"
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPU_IDLE=y
+# CONFIG_MIPS_CPS_CPUIDLE is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_IPV6_SIT=m
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_DSCP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_NAT_IPV4=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_NAT_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_6LOWPAN=y
+CONFIG_IEEE802154=y
+CONFIG_IEEE802154_6LOWPAN=y
+CONFIG_MAC802154=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_PKTGEN=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIBTUSB=y
+CONFIG_BT_HCIBTSDIO=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIBFUSB=y
+CONFIG_BT_HCIVHCI=y
+CONFIG_BT_IMG=m
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+# CONFIG_CFG80211_DEFAULT_PS is not set
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_DEBUGFS=y
+CONFIG_MAC80211_DEBUG_MENU=y
+CONFIG_MAC80211_VERBOSE_DEBUG=y
+CONFIG_RFKILL=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DEBUG_DEVRES=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_WINBOND_OTP=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_ZRAM=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SRAM=y
+CONFIG_UBOOT_BOOTCOUNT=y
+CONFIG_ATU=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+CONFIG_VETH=m
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_NET_VENDOR_VIA is not set
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_MCS7830=m
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_RT2X00=m
+CONFIG_RT2800USB=m
+CONFIG_UCCP420WLAN=m
+CONFIG_IEEE802154_CC2520=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_SC16IS7XX=y
+# CONFIG_SERIAL_SC16IS7XX_I2C is not set
+CONFIG_SERIAL_SC16IS7XX_SPI=y
+CONFIG_HW_RANDOM=y
+CONFIG_TCG_TPM=y
+CONFIG_TCG_TIS_I2C_INFINEON=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_IMG=y
+CONFIG_I2C_STUB=m
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_IMG_SPFI=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_IMGPDC_WDT=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_RC_SUPPORT=y
+# CONFIG_RC_DECODERS is not set
+CONFIG_RC_DEVICES=y
+CONFIG_IR_IMG=y
+CONFIG_IR_IMG_NEC=y
+CONFIG_IR_IMG_JVC=y
+CONFIG_IR_IMG_SONY=y
+CONFIG_IR_IMG_SHARP=y
+CONFIG_IR_IMG_SANYO=y
+CONFIG_IR_IMG_RC5=y
+CONFIG_IR_IMG_RC6=y
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_IMG=y
+CONFIG_SND_SOC_IMG_PISTACHIO_BUB=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_OTG=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_PLATFORM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_TEST=m
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PISTACHIO=y
+CONFIG_DMADEVICES=y
+CONFIG_IMG_MDC_DMA=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+# CONFIG_ANDROID_TIMED_OUTPUT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_SOC_IMG=y
+CONFIG_MEMORY=y
+CONFIG_IIO=y
+CONFIG_CC10001_ADC=y
+CONFIG_PWM=y
+CONFIG_PWM_IMG=y
+CONFIG_PHY_PISTACHIO_USB=y
+CONFIG_ANDROID=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=m
+CONFIG_OVERLAY_FS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_HFSPLUS_FS=m
+CONFIG_UBIFS_FS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_CREDENTIALS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_LKDTM=y
+CONFIG_TEST_UDELAY=m
+CONFIG_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_YAMA=y
+CONFIG_SECURITY_YAMA_STACKED=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_IMGTEC_HASH=y
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=m
+# CONFIG_XZ_DEC_X86 is not set
+CONFIG_MAC80211_RC_MINSTREL_VHT=y
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 6499d93..47bc45a 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -101,10 +101,8 @@
 	/* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
 	if ((config_enabled(CONFIG_32BIT) ||
 	    test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
-	    (regs->regs[2] == __NR_syscall)) {
+	    (regs->regs[2] == __NR_syscall))
 		i++;
-		n++;
-	}
 
 	while (n--)
 		ret |= mips_get_syscall_arg(args++, task, regs, i++);
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 4cc1350..aa2df3e8 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -36,16 +36,8 @@
 	lw	t1, PT_EPC(sp)		# skip syscall on return
 
 	subu	v0, v0, __NR_O32_Linux	# check syscall number
-	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
 	addiu	t1, 4			# skip to next instruction
 	sw	t1, PT_EPC(sp)
-	beqz	t0, illegal_syscall
-
-	sll	t0, v0, 2
-	la	t1, sys_call_table
-	addu	t1, t0
-	lw	t2, (t1)		# syscall routine
-	beqz	t2, illegal_syscall
 
 	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
 
@@ -96,6 +88,16 @@
 	li	t1, _TIF_WORK_SYSCALL_ENTRY
 	and	t0, t1
 	bnez	t0, syscall_trace_entry # -> yes
+syscall_common:
+	sltiu	t0, v0, __NR_O32_Linux_syscalls + 1
+	beqz	t0, illegal_syscall
+
+	sll	t0, v0, 2
+	la	t1, sys_call_table
+	addu	t1, t0
+	lw	t2, (t1)		# syscall routine
+
+	beqz	t2, illegal_syscall
 
 	jalr	t2			# Do The Real Thing (TM)
 
@@ -116,7 +118,7 @@
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
+	move	s0, v0
 	move	a0, sp
 
 	/*
@@ -129,27 +131,18 @@
 
 1:	jal	syscall_trace_enter
 
-	bltz	v0, 2f			# seccomp failed? Skip syscall
+	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t0, s0
+	move	v0, s0			# restore syscall
+
 	RESTORE_STATIC
 	lw	a0, PT_R4(sp)		# Restore argument registers
 	lw	a1, PT_R5(sp)
 	lw	a2, PT_R6(sp)
 	lw	a3, PT_R7(sp)
-	jalr	t0
+	j	syscall_common
 
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sw	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	lw	t1, PT_R2(sp)		# syscall number
-	negu	v0			# error
-	sw	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sw	v0, PT_R2(sp)		# result
-
-2:	j	syscall_exit
+1:	j	syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index ad4d4463..676fda7 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -39,18 +39,11 @@
 	.set	at
 #endif
 
-	dsubu	t0, v0, __NR_64_Linux	# check syscall number
-	sltiu	t0, t0, __NR_64_Linux_syscalls + 1
 #if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
 	ld	t1, PT_EPC(sp)		# skip syscall on return
 	daddiu	t1, 4			# skip to next instruction
 	sd	t1, PT_EPC(sp)
 #endif
-	beqz	t0, illegal_syscall
-
-	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sys_call_table - (__NR_64_Linux * 8))(t0)
-					# syscall routine
 
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
 
@@ -59,6 +52,17 @@
 	and	t0, t1, t0
 	bnez	t0, syscall_trace_entry
 
+syscall_common:
+	dsubu	t2, v0, __NR_64_Linux
+	sltiu   t0, t2, __NR_64_Linux_syscalls + 1
+	beqz	t0, illegal_syscall
+
+	dsll	t0, t2, 3		# offset into table
+	dla	t2, sys_call_table
+	daddu	t0, t2, t0
+	ld	t2, (t0)		# syscall routine
+	beqz	t2, illegal_syscall
+
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -78,14 +82,14 @@
 
 syscall_trace_entry:
 	SAVE_STATIC
-	move	s0, t2
+	move	s0, v0
 	move	a0, sp
 	daddiu	a1, v0, __NR_64_Linux
 	jal	syscall_trace_enter
 
-	bltz	v0, 2f			# seccomp failed? Skip syscall
+	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t0, s0
+	move	v0, s0
 	RESTORE_STATIC
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
@@ -93,19 +97,9 @@
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
-	jalr	t0
+	j	syscall_common
 
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
-
-2:	j	syscall_exit
+1:	j	syscall_exit
 
 illegal_syscall:
 	/* This also isn't a 64-bit syscall, throw an error.  */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 446cc65..611ba3b 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -52,6 +52,7 @@
 	and	t0, t1, t0
 	bnez	t0, n32_syscall_trace_entry
 
+syscall_common:
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -75,9 +76,9 @@
 	daddiu	a1, v0, __NR_N32_Linux
 	jal	syscall_trace_enter
 
-	bltz	v0, 2f			# seccomp failed? Skip syscall
+	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t0, s0
+	move	t2, s0
 	RESTORE_STATIC
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
@@ -85,19 +86,9 @@
 	ld	a3, PT_R7(sp)
 	ld	a4, PT_R8(sp)
 	ld	a5, PT_R9(sp)
-	jalr	t0
+	j	syscall_common
 
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
-
-2:	j	syscall_exit
+1:	j	syscall_exit
 
 not_n32_scall:
 	/* This is not an n32 compatibility syscall, pass it on to
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 66d618b..64397d2 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -87,6 +87,7 @@
 	and	t0, t1, t0
 	bnez	t0, trace_a_syscall
 
+syscall_common:
 	jalr	t2			# Do The Real Thing (TM)
 
 	li	t0, -EMAXERRNO - 1	# error?
@@ -130,9 +131,9 @@
 
 1:	jal	syscall_trace_enter
 
-	bltz	v0, 2f			# seccomp failed? Skip syscall
+	bltz	v0, 1f			# seccomp failed? Skip syscall
 
-	move	t0, s0
+	move	t2, s0
 	RESTORE_STATIC
 	ld	a0, PT_R4(sp)		# Restore argument registers
 	ld	a1, PT_R5(sp)
@@ -142,19 +143,9 @@
 	ld	a5, PT_R9(sp)
 	ld	a6, PT_R10(sp)
 	ld	a7, PT_R11(sp)		# For indirect syscalls
-	jalr	t0
+	j	syscall_common
 
-	li	t0, -EMAXERRNO - 1	# error?
-	sltu	t0, t0, v0
-	sd	t0, PT_R7(sp)		# set error flag
-	beqz	t0, 1f
-
-	ld	t1, PT_R2(sp)		# syscall number
-	dnegu	v0			# error
-	sd	t1, PT_R0(sp)		# save it for syscall restarting
-1:	sd	v0, PT_R2(sp)		# result
-
-2:	j	syscall_exit
+1:	j	syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
diff --git a/arch/mips/pistachio/init.c b/arch/mips/pistachio/init.c
index 890ac8a..1f90fd9 100644
--- a/arch/mips/pistachio/init.c
+++ b/arch/mips/pistachio/init.c
@@ -2,6 +2,7 @@
  * Pistachio platform setup
  *
  * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2016 Imagination Technologies
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -9,6 +10,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/of_fdt.h>
@@ -26,9 +28,28 @@
 #include <asm/traps.h>
 #include <asm/reboot.h>
 
+/*
+ * Core revision register decoding
+ * Bits 23 to 20: Major rev
+ * Bits 15 to 8: Minor rev
+ * Bits 7 to 0: Maintenance rev
+ */
+#define PISTACHIO_CORE_REV_REG	0xB81483D0
+#define PISTACHIO_CORE_REV_A1	0x00100006
+#define PISTACHIO_CORE_REV_B0	0x00100106
+
 const char *get_system_type(void)
 {
-	return "IMG Pistachio SoC";
+	u32 core_rev;
+
+	core_rev = __raw_readl((const void *)PISTACHIO_CORE_REV_REG);
+
+	if (core_rev == PISTACHIO_CORE_REV_B0)
+		return "IMG Pistachio SoC (B0)";
+	else if (core_rev == PISTACHIO_CORE_REV_A1)
+		return "IMG_Pistachio SoC (A1)";
+	else
+		return "IMG_Pistachio SoC";
 }
 
 static void __init plat_setup_iocoherency(void)
@@ -130,6 +151,8 @@
 	mips_cm_probe();
 	mips_cpc_probe();
 	register_cps_smp_ops();
+
+	pr_info("SoC Type: %s\n", get_system_type());
 }
 
 void __init prom_free_prom_memory(void)
diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
index fd64bd9..7271c4e 100644
--- a/drivers/clk/pistachio/clk-pistachio.c
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -44,7 +44,7 @@
 	GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div",
 	     0x104, 22),
 	GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23),
-	GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24),
+	GATE(CLK_SD_HOST, "sd_host", "sd_host_div4", 0x104, 24),
 	GATE(CLK_BT, "bt", "bt_div", 0x104, 25),
 	GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26),
 	GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27),
@@ -54,6 +54,7 @@
 static struct pistachio_fixed_factor pistachio_ffs[] __initdata = {
 	FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4),
 	FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8),
+	FIXED_FACTOR(CLK_SDHOST_DIV4, "sd_host_div4", "sd_host_div", 4),
 };
 
 static struct pistachio_div pistachio_divs[] __initdata = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2c2719a..a2f25b8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -538,6 +538,13 @@
 	  To compile this driver as a module, choose M here: the module will
 	  be called img-pdm.
 
+config UBOOT_BOOTCOUNT
+	tristate "U-Boot Bootcount driver"
+	depends on OF
+	help
+	  The U-Boot Bootcount driver allows to access the
+	  bootcounter through sysfs file.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f6e02a3..4b26b2e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -47,6 +47,7 @@
 obj-y				+= lis3lv02d/
 obj-y				+= carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
+obj-$(CONFIG_UBOOT_BOOTCOUNT)	+= uboot_bootcount.o
 obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)		+= mei/
 obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
diff --git a/drivers/misc/atu/atu_clk_maintainer.c b/drivers/misc/atu/atu_clk_maintainer.c
index 2589fff..297dff8 100644
--- a/drivers/misc/atu/atu_clk_maintainer.c
+++ b/drivers/misc/atu/atu_clk_maintainer.c
@@ -639,7 +639,6 @@
 			int dir;
 
 			freq = txc->freq;
-			freq = (freq * NSEC_PER_USEC) >> 16;
 
 			if (freq < 0) {
 				dir = -1;
diff --git a/drivers/misc/uboot_bootcount.c b/drivers/misc/uboot_bootcount.c
new file mode 100644
index 0000000..684993a
--- /dev/null
+++ b/drivers/misc/uboot_bootcount.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies Ltd.
+ *
+ * This driver gives access(read/write) to the bootcounter used by u-boot.
+ * Access is supported via sysfs.
+ *
+ * Based on work from: Steffen Rumler  <Steffen.Rumler@siemens.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+*/
+
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#define UBOOT_BOOTCOUNT_MAGIC		0xB001C041 /* magic number value */
+#define UBOOT_BOOTCOUNT_MAGIC_MASK	0xFFFF0000 /* magic, when combined */
+#define UBOOT_BOOTCOUNT_COUNT_MASK	0x0000FFFF /* value, when combined */
+
+
+struct bootcount_device {
+	void __iomem *reg;
+};
+
+static int bootcount_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	unsigned long bootcount;
+	struct bootcount_device *priv = dev_get_drvdata(dev);
+
+	bootcount = readl(priv->reg);
+	if ((bootcount & UBOOT_BOOTCOUNT_MAGIC_MASK) !=
+		(UBOOT_BOOTCOUNT_MAGIC & UBOOT_BOOTCOUNT_MAGIC_MASK)) {
+		return -EINVAL;
+	}
+	bootcount &= UBOOT_BOOTCOUNT_COUNT_MASK;
+	return sprintf(buf, "%lu\n", bootcount);
+}
+
+static int bootcount_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	int ret;
+	u32 value;
+	struct bootcount_device *priv = dev_get_drvdata(dev);
+
+	ret = kstrtou32(buf, 0, &value);
+	if (ret < 0)
+		return ret;
+
+	value = (UBOOT_BOOTCOUNT_MAGIC & UBOOT_BOOTCOUNT_MAGIC_MASK) |
+		(value & UBOOT_BOOTCOUNT_COUNT_MASK);
+	writel(value, priv->reg);
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(bootcount);
+
+static int bootcount_probe(struct platform_device *ofdev)
+{
+	unsigned long magic;
+	struct bootcount_device *priv;
+	struct resource *res;
+	int status;
+
+	priv = devm_kzalloc(&ofdev->dev, sizeof(struct bootcount_device), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&ofdev->dev, "Unable to allocate device private data\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+	priv->reg = devm_ioremap_resource(&ofdev->dev, res);
+	 if (IS_ERR(priv->reg)) {
+		dev_err(&ofdev->dev, "unable to map register\n");
+		return PTR_ERR(priv->reg);
+	}
+
+	magic = readl(priv->reg);
+	if ((magic & UBOOT_BOOTCOUNT_MAGIC_MASK) !=
+	    (UBOOT_BOOTCOUNT_MAGIC & UBOOT_BOOTCOUNT_MAGIC_MASK)) {
+		dev_err(&ofdev->dev, "bad magic\n");
+		return -EINVAL;
+	}
+
+	status = device_create_file(&ofdev->dev, &dev_attr_bootcount);
+	if (status) {
+		dev_err(&ofdev->dev, "unable to register sysfs entry\n");
+		return status;
+	}
+	dev_set_drvdata(&ofdev->dev, priv);
+	return 0;
+}
+
+static int bootcount_remove(struct platform_device *ofdev)
+{
+	device_remove_file(&ofdev->dev, &dev_attr_bootcount);
+	return 0;
+}
+
+static const struct of_device_id bootcount_match[] = {
+	{ .compatible = "uboot,bootcount", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, bootcount_match);
+
+static struct platform_driver bootcount_driver = {
+	.driver = {
+		.name = "bootcount",
+		.of_match_table = bootcount_match,
+	},
+	.probe = bootcount_probe,
+	.remove = bootcount_remove,
+};
+
+module_platform_driver(bootcount_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Avinash Tahakik <avinash.tahakik@imgtec.com>");
+MODULE_DESCRIPTION("Provide (read/write) access to the U-Boot bootcounter via sysfs");
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 3af137f..9000241 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -48,13 +48,15 @@
 	return ret;
 }
 
-static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
+static void m25p_addr2cmd(unsigned int addr, unsigned int addr_width, u8 *cmd)
 {
-	/* opcode is in cmd[0] */
-	cmd[1] = addr >> (nor->addr_width * 8 -  8);
-	cmd[2] = addr >> (nor->addr_width * 8 - 16);
-	cmd[3] = addr >> (nor->addr_width * 8 - 24);
-	cmd[4] = addr >> (nor->addr_width * 8 - 32);
+	if (addr_width) {
+		/* opcode is in cmd[0] */
+		cmd[1] = addr >> (addr_width * 8 -  8);
+		cmd[2] = addr >> (addr_width * 8 - 16);
+		cmd[3] = addr >> (addr_width * 8 - 24);
+		cmd[4] = addr >> (addr_width * 8 - 32);
+	}
 }
 
 static int m25p_cmdsz(struct spi_nor *nor)
@@ -90,7 +92,7 @@
 		cmd_sz = 1;
 
 	flash->command[0] = nor->program_opcode;
-	m25p_addr2cmd(nor, to, flash->command);
+	m25p_addr2cmd(to, nor->addr_width, flash->command);
 
 	t[0].tx_buf = flash->command;
 	t[0].len = cmd_sz;
@@ -105,9 +107,9 @@
 	*retlen += m.actual_length - cmd_sz;
 }
 
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+static inline unsigned int m25p80_rx_nbits(enum read_mode mode)
 {
-	switch (nor->flash_read) {
+	switch (mode) {
 	case SPI_NOR_DUAL:
 		return 2;
 	case SPI_NOR_QUAD:
@@ -137,14 +139,14 @@
 	memset(t, 0, (sizeof t));
 
 	flash->command[0] = nor->read_opcode;
-	m25p_addr2cmd(nor, from, flash->command);
+	m25p_addr2cmd(from, nor->addr_width, flash->command);
 
 	t[0].tx_buf = flash->command;
 	t[0].len = m25p_cmdsz(nor) + dummy;
 	spi_message_add_tail(&t[0], &m);
 
 	t[1].rx_buf = buf;
-	t[1].rx_nbits = m25p80_rx_nbits(nor);
+	t[1].rx_nbits = m25p80_rx_nbits(nor->flash_read);
 	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
@@ -163,13 +165,97 @@
 
 	/* Set up command buffer. */
 	flash->command[0] = nor->erase_opcode;
-	m25p_addr2cmd(nor, offset, flash->command);
+	m25p_addr2cmd(offset, nor->addr_width, flash->command);
 
 	spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
 
 	return 0;
 }
 
+/* From spi_nor_xfer_cfg, this call ignores cmd_pins, addr_pins, so single I/O
+ * line is used for cmd and addr
+ * mode_pins, mode_cycles are ignored, decides nbits based on mode
+ */
+static int m25p80_read_xfer(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+				u8 *buf, size_t len, size_t *retlen)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u32 dummy = cfg->dummy_cycles/8; /* convert dummy cycles into bytes */
+	u32 cmd_sz = (1 + cfg->addr_width + dummy);
+	int ret;
+
+	if (cfg->addr_width > 4 || cmd_sz > MAX_CMD_SIZE)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof (t));
+
+	memset(flash->command, 0, MAX_CMD_SIZE);
+	flash->command[0] = cfg->cmd;
+	m25p_addr2cmd(cfg->addr, cfg->addr_width, flash->command);
+
+	t[0].tx_buf = flash->command;
+	t[0].len = cmd_sz;
+	spi_message_add_tail(&t[0], &m);
+
+	if (len) {
+		t[1].rx_buf = buf;
+		t[1].rx_nbits = m25p80_rx_nbits(cfg->mode);
+		t[1].len = len;
+		spi_message_add_tail(&t[1], &m);
+	}
+
+	ret = spi_sync(spi, &m);
+
+	if (!ret)
+		*retlen += (m.actual_length - cmd_sz);
+	return ret;
+}
+
+/* From spi_nor_xfer_cfg, this call ignores cmd_pins, addr_pins, mode, mode_pins,
+ * mode_cycles, so single I/O line is used for cmd, addr and data
+ */
+static int m25p80_write_xfer(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+				u8 *buf, size_t len, size_t *retlen)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
+	struct spi_transfer t[2];
+	struct spi_message m;
+	u32 dummy = cfg->dummy_cycles/8; /* convert dummy cycles into bytes */
+	u32 cmd_sz = (1 + cfg->addr_width + dummy);
+	int ret;
+
+	if (cfg->addr_width > 4 || cmd_sz > MAX_CMD_SIZE)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	memset(flash->command, 0, MAX_CMD_SIZE);
+	flash->command[0] = cfg->cmd;
+	m25p_addr2cmd(cfg->addr, cfg->addr_width, flash->command);
+
+	t[0].tx_buf = flash->command;
+	t[0].len = cmd_sz;
+	spi_message_add_tail(&t[0], &m);
+
+	if (len) {
+		t[1].tx_buf = buf;
+		t[1].len = len;
+		spi_message_add_tail(&t[1], &m);
+	}
+
+	ret = spi_sync(spi, &m);
+
+	if (!ret)
+		*retlen += (m.actual_length - cmd_sz);
+	return ret;
+}
+
 /*
  * board specific setup should have ensured the SPI clock used here
  * matches what the READ command supports, at least until this driver
@@ -199,6 +285,8 @@
 	nor->erase = m25p80_erase;
 	nor->write_reg = m25p80_write_reg;
 	nor->read_reg = m25p80_read_reg;
+	nor->read_xfer = m25p80_read_xfer;
+	nor->write_xfer = m25p80_write_xfer;
 
 	nor->dev = &spi->dev;
 	nor->mtd = &flash->mtd;
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 64a4f0e..e157c33 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -28,4 +28,12 @@
 	  This enables support for the Quad SPI controller in master mode.
 	  We only connect the NOR to this controller now.
 
+config MTD_SPI_NOR_WINBOND_OTP
+	bool "Support for winbond security register and unique ID"
+	depends on MTD_SPI_NOR
+	default n
+	help
+	  This enables support for read/write of winbond security registers
+	  as user OTP and also reading of NOR unique ID as factory OTP.
+
 endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 6a7ce14..6aba941 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor.o
+obj-$(CONFIG_MTD_SPI_NOR_WINBOND_OTP)	+= winbond-otp.o
 obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
diff --git a/drivers/mtd/spi-nor/spi-nor-common.h b/drivers/mtd/spi-nor/spi-nor-common.h
new file mode 100644
index 0000000..ff15d42
--- /dev/null
+++ b/drivers/mtd/spi-nor/spi-nor-common.h
@@ -0,0 +1,8 @@
+#ifndef SPI_NOR_COMMON_H
+#define SPI_NOR_COMMON_H
+
+int spi_nor_wait_till_ready(struct spi_nor *nor);
+int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops);
+void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops);
+
+#endif
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 1194f33..46d2f06 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -22,6 +22,8 @@
 #include <linux/of_platform.h>
 #include <linux/spi/flash.h>
 #include <linux/mtd/spi-nor.h>
+#include "winbond-otp.h"
+#include "spi-nor-common.h"
 
 /* Define max times to check status register before we give up. */
 #define	MAX_READY_WAIT_JIFFIES	(40 * HZ) /* M25P16 specs 40s max chip erase */
@@ -55,6 +57,7 @@
 #define	SPI_NOR_DUAL_READ	0x20    /* Flash supports Dual Read */
 #define	SPI_NOR_QUAD_READ	0x40    /* Flash supports Quad Read */
 #define	USE_FSR			0x80	/* use flag status register */
+#define WINBOND_OTP		0x100	/* use winbond security reg as OTP */
 };
 
 #define JEDEC_MFR(info)	((info)->id[0])
@@ -231,7 +234,7 @@
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
  */
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+int spi_nor_wait_till_ready(struct spi_nor *nor)
 {
 	unsigned long deadline;
 	int timeout = 0, ret;
@@ -268,7 +271,7 @@
 	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0, 0);
 }
 
-static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 {
 	int ret = 0;
 
@@ -285,7 +288,7 @@
 	return ret;
 }
 
-static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
 {
 	if (nor->unprepare)
 		nor->unprepare(nor, ops);
@@ -611,7 +614,7 @@
 	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
 	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
 	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
+	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K | WINBOND_OTP) },
 	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
 	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, 0) },
 
@@ -1078,6 +1081,9 @@
 		mtd->_unlock = spi_nor_unlock;
 	}
 
+	if (info->flags & WINBOND_OTP)
+		winbond_otp_register(mtd);
+
 	/* sst nor chips use AAI word program */
 	if (info->flags & SST_WRITE)
 		mtd->_write = sst_write;
diff --git a/drivers/mtd/spi-nor/winbond-otp.c b/drivers/mtd/spi-nor/winbond-otp.c
new file mode 100644
index 0000000..a9db770
--- /dev/null
+++ b/drivers/mtd/spi-nor/winbond-otp.c
@@ -0,0 +1,482 @@
+/*
+ * Imagination Technologies
+ *
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * This program 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 driver provides read/write access to the 3 x 256 bytes security
+ * registers as user OTP and unique ID of the NOR can be read as factory OTP
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include "spi-nor-common.h"
+
+#define SECURITY_REG_START_ADDR		0x1000 /*first security register addr*/
+#define SECURITY_REG_ADDR_OFFSET	0x1000 /*diff between consecutive reg*/
+#define SECURITY_REG_NUM		3 /* number of security registers */
+#define SECURITY_REG_SIZE		256 /* bytes per security register */
+#define SECURITY_REG_TOTAL_SIZE		(SECURITY_REG_NUM * SECURITY_REG_SIZE)
+#define SPI_NOR_UNIQUE_ID_LEN		8 /*number of bytes of unique ID */
+
+/* SPI FLASH opcodes */
+#define SPINOR_OP_RD_SR2		0x35 /* Read status register 2 */
+#define SPINOR_OP_PR_SECURITY_REG	0x42 /* Program security register */
+#define SPINOR_OP_ER_SECURITY_REG	0x44 /* Erase security register */
+#define SPINOR_OP_RD_SECURITY_REG	0x48 /* Read security register */
+#define SPINOR_OP_RD_UNIQUE_ID		0x4B /* Read unique id */
+
+/* Status register 2 */
+#define SR2_LB1_BIT			3 /* security register lock bit 1 */
+
+/* Get start addr of the security reg*/
+#define SEC_REG_START_ADDR(addr) (addr & 0x3000)
+
+static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+{
+	return mtd->priv;
+}
+
+static inline int write_enable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
+}
+
+static inline int write_disable(struct spi_nor *nor)
+{
+	return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0, 0);
+}
+
+static int read_sr(struct spi_nor *nor, u8 opcode, u8 *val)
+{
+	int ret;
+
+	ret = nor->read_reg(nor, opcode, val, 1);
+	if (ret < 0)
+		pr_err("error %d reading SR\n", ret);
+	return ret;
+}
+
+/*
+ * Converts address range
+ *	0 - 0xFF	-> 0x1000 - 0x10FF
+ *	0x100 - 0x1FF	-> 0x2000 - 0x20FF
+ *	0x200 - 0x2FF	-> 0x3000 - 0x30FF
+ *
+ * This func assumes that sanity checks on addr are done and is in valid range
+ */
+static loff_t translate_addr(loff_t addr)
+{
+	int i;
+	loff_t new_addr = SECURITY_REG_START_ADDR;
+
+	for (i = 0; i < SECURITY_REG_NUM; i++) {
+		if (addr < ((i+1)*SECURITY_REG_SIZE)) {
+			new_addr |= addr & (SECURITY_REG_SIZE-1);
+			break;
+		}
+		new_addr += SECURITY_REG_ADDR_OFFSET;
+	}
+
+	return new_addr;
+}
+
+/*
+ * Return 3 blocks of 256 bytes security register as user OTP,
+ * address of these blocks will be 0, 0x100, 0x200
+ * driver will convert these address to actual address while doing
+ * read/write
+ */
+static int winbond_get_user_otp_info(struct mtd_info *mtd, size_t len,
+					size_t *retlen,
+					struct otp_info *otpinfo)
+{
+	u8 val;
+	int i, ret;
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	mutex_lock(&nor->lock);
+	ret = read_sr(nor, SPINOR_OP_RD_SR2, &val);
+	mutex_unlock(&nor->lock);
+
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < SECURITY_REG_NUM; i++) {
+		otpinfo[i].start = i * SECURITY_REG_SIZE;
+		otpinfo[i].length = SECURITY_REG_SIZE;
+		otpinfo[i].locked = !!(val & BIT(SR2_LB1_BIT + i));
+	}
+
+	*retlen = SECURITY_REG_NUM * sizeof(*otpinfo);
+
+	return 0;
+}
+
+static int spi_otp_read(struct spi_nor *nor, loff_t from,
+					size_t len, size_t *retlen, u_char *buf)
+{
+	struct spi_nor_xfer_cfg cfg = {
+		.cmd = SPINOR_OP_RD_SECURITY_REG,
+		.addr = from,
+		.addr_width = nor->addr_width,
+		.mode = SPI_NOR_NORMAL,
+		.dummy_cycles = 8,
+	};
+
+	return nor->read_xfer(nor, &cfg, buf, len, retlen);
+}
+
+static int spi_otp_write(struct spi_nor *nor, loff_t to,
+					size_t len, size_t *retlen, u_char *buf)
+{
+	struct spi_nor_xfer_cfg cfg = {
+		.cmd = SPINOR_OP_PR_SECURITY_REG,
+		.addr = to,
+		.addr_width = nor->addr_width,
+		.mode = SPI_NOR_NORMAL,
+	};
+
+	return nor->write_xfer(nor, &cfg, buf, len, retlen);
+}
+
+static int spi_otp_erase(struct spi_nor *nor, loff_t offs)
+{
+	size_t temp_retlen;
+	struct spi_nor_xfer_cfg cfg = {
+		.cmd = SPINOR_OP_ER_SECURITY_REG,
+		.addr = offs,
+		.addr_width = nor->addr_width,
+		.mode = SPI_NOR_NORMAL,
+	};
+
+	return nor->write_xfer(nor, &cfg, NULL, 0, &temp_retlen);
+}
+
+static int spi_read_uniqueid(struct spi_nor *nor, u8 *buf)
+{
+	size_t temp_retlen;
+	struct spi_nor_xfer_cfg cfg = {
+		.cmd = SPINOR_OP_RD_UNIQUE_ID,
+		.addr_width = 0,
+		.mode = SPI_NOR_NORMAL,
+		.dummy_cycles = 32,
+	};
+
+	return nor->read_xfer(nor, &cfg, buf, SPI_NOR_UNIQUE_ID_LEN,
+				&temp_retlen);
+}
+
+
+static int winbond_read_user_otp(struct mtd_info *mtd, loff_t from,
+					size_t len, size_t *retlen, u_char *buf)
+{
+	int ret;
+	u32 i, read_len, end_addr, sreg_offset;
+	loff_t temp_addr;
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	*retlen = 0;
+
+	if (from < 0 || from >= SECURITY_REG_TOTAL_SIZE
+		     || (from + len) > SECURITY_REG_TOTAL_SIZE)
+		return -EINVAL;
+
+	if (!len)
+		return 0;
+
+	end_addr = from + len;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	for (i = from; i < end_addr; i += read_len) {
+		sreg_offset = i & (SECURITY_REG_SIZE-1);
+		/* if offset not on boundary, read first few bytes */
+		if (sreg_offset) {
+			/* check if everything has to be read from 1 reg */
+			if ((sreg_offset + len) <= SECURITY_REG_SIZE)
+				read_len = len;
+			else
+				read_len = SECURITY_REG_SIZE - sreg_offset;
+		}
+		/* if it is last chunk, read the remaining bytes */
+		else if ((end_addr - i) < SECURITY_REG_SIZE)
+			read_len = end_addr - i;
+		else
+			read_len = SECURITY_REG_SIZE;
+
+		temp_addr = translate_addr(i);
+		ret = spi_otp_read(nor, temp_addr, read_len, retlen,
+					buf + (i-from));
+		if (ret < 0)
+			goto error;
+	}
+error:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+	return ret;
+}
+
+/*
+ * This func assumes that offset is within valid range of security registers,
+ * valid offset are 0x1000, 0x2000 or 0x3000
+ */
+static int winbond_erase_security_reg(struct spi_nor *nor, loff_t offset)
+{
+	int ret;
+
+	ret = write_enable(nor);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	ret = spi_otp_erase(nor, offset);
+	if (ret < 0)
+		return ret;
+
+	ret = spi_nor_wait_till_ready(nor);
+
+	return ret;
+}
+
+/*
+ * This function does read, modify locally, erase and write to the register to
+ * be written
+ * It doesn't do any range checks on reg_addr, sreg_offset, len
+ */
+static int winbond_write_security_reg(struct spi_nor *nor, loff_t reg_addr,
+					u32 sreg_offset, size_t len,
+					size_t *retlen, u_char *buf)
+{
+	int ret;
+	size_t temp_retlen = 0;
+	u8 *reg_buffer;
+
+	if (unlikely(sreg_offset + len > SECURITY_REG_SIZE))
+		return -EINVAL;
+
+	reg_buffer = kmalloc(SECURITY_REG_SIZE, GFP_KERNEL);
+	if (!reg_buffer)
+		return -ENOMEM;
+
+	/* read the security register */
+	ret = spi_otp_read(nor, reg_addr, SECURITY_REG_SIZE, &temp_retlen,
+				reg_buffer);
+	if (ret < 0 || temp_retlen != SECURITY_REG_SIZE)
+		goto error;
+
+	/* modify the part to be written */
+	memcpy(reg_buffer + sreg_offset, buf, len);
+
+	/* erase the security register */
+	ret = winbond_erase_security_reg(nor, reg_addr);
+	if (ret < 0)
+		goto error;
+
+	/* write the security reg*/
+	ret = write_enable(nor);
+	if (ret < 0)
+		goto error;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		goto error;
+
+	temp_retlen = 0;
+
+	ret = spi_otp_write(nor, reg_addr, SECURITY_REG_SIZE, &temp_retlen,
+				reg_buffer);
+	if (ret < 0 || temp_retlen != SECURITY_REG_SIZE)
+		goto error;
+
+	ret = spi_nor_wait_till_ready(nor);
+
+	*retlen += len;
+
+error:
+	kfree(reg_buffer);
+	return ret;
+}
+
+static int winbond_write_user_otp(struct mtd_info *mtd, loff_t to,
+					size_t len, size_t *retlen, u_char *buf)
+{
+	int ret;
+	u32 i, write_len, end_addr, sreg_offset;
+	loff_t temp_addr;
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	*retlen = 0;
+
+	if (to < 0 || to >= SECURITY_REG_TOTAL_SIZE
+		   || (to + len) > SECURITY_REG_TOTAL_SIZE)
+		return -EINVAL;
+
+	if (!len)
+		return 0;
+
+	end_addr = to + len;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE);
+	if (ret)
+		return ret;
+
+	for (i = to; i < end_addr; i += write_len) {
+		sreg_offset = i & (SECURITY_REG_SIZE-1);
+		/* if offset not on boundary, write first few bytes */
+		if (sreg_offset) {
+			/* check if everything has to be written in 1 reg */
+			if ((sreg_offset + len) <= SECURITY_REG_SIZE)
+				write_len = len;
+			else
+				write_len = SECURITY_REG_SIZE - sreg_offset;
+		}
+		/* if it is last chunk, write the remaining bytes */
+		else if ((end_addr - i) < SECURITY_REG_SIZE)
+			write_len = end_addr - i;
+		else
+			write_len = SECURITY_REG_SIZE;
+
+		temp_addr = translate_addr(i);
+		ret = winbond_write_security_reg(nor,
+					SEC_REG_START_ADDR(temp_addr),
+					sreg_offset, write_len,
+					retlen,	buf + (i-to));
+		if (ret < 0)
+			goto error;
+	}
+
+error:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+	return ret;
+}
+
+static int winbond_lock_user_otp(struct mtd_info *mtd, loff_t from, size_t len)
+{
+	int ret;
+	u8 sr1, sr2, security_reg_num;
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	/* allow locking 1 register at a time,
+	 * so ensure that len is 256
+	 * also check if address is on security register boundary
+	 */
+	if (len != SECURITY_REG_SIZE || from < 0
+		|| from >= SECURITY_REG_TOTAL_SIZE
+		|| from & (SECURITY_REG_SIZE - 1))
+		return -EINVAL;
+
+	/* find out the security reg to set */
+	security_reg_num = from / SECURITY_REG_SIZE;
+
+	if (unlikely(security_reg_num > (SECURITY_REG_NUM-1)))
+		return -EINVAL;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
+	if (ret)
+		return ret;
+
+	/* read status registers */
+	ret = read_sr(nor, SPINOR_OP_RDSR, &sr1);
+	if (ret < 0)
+		goto error;
+
+	ret = read_sr(nor, SPINOR_OP_RD_SR2, &sr2);
+	if (ret < 0)
+		goto error;
+
+	ret = write_enable(nor);
+	if (ret < 0)
+		goto error;
+
+	/* set the corresponding LB bit in security register 2 */
+	sr2 |= BIT(SR2_LB1_BIT + security_reg_num);
+
+	/* write status registers */
+	nor->cmd_buf[0] = sr1;
+	nor->cmd_buf[1] = sr2;
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2, 0);
+
+	write_disable(nor);
+
+error:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+	return ret;
+}
+
+/*
+ * Unique ID of NOR device will be reported as factory OTP
+ */
+static int winbond_get_fact_otp_info(struct mtd_info *mtd, size_t len,
+					size_t *retlen,
+					struct otp_info *otpinfo)
+{
+	otpinfo->start = 0;
+	otpinfo->length = SPI_NOR_UNIQUE_ID_LEN;
+	otpinfo->locked = 1;
+
+	*retlen = sizeof(*otpinfo);
+
+	return 0;
+}
+
+static int winbond_read_fact_otp(struct mtd_info *mtd, loff_t from, size_t len,
+					size_t *retlen, u_char *buf)
+{
+	int ret;
+
+	char unique_id[SPI_NOR_UNIQUE_ID_LEN] = {0};
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	*retlen = 0;
+
+	if (from < 0 || from >= SPI_NOR_UNIQUE_ID_LEN
+		     || (from + len) > SPI_NOR_UNIQUE_ID_LEN)
+		return -EINVAL;
+
+	if (!len)
+		return 0;
+
+	ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
+	if (ret)
+		return ret;
+
+	ret = spi_read_uniqueid(nor, unique_id);
+	if (ret < 0)
+		goto error;
+
+	/* Read complete unique ID,but just copy whatever is requested */
+	memcpy(buf, unique_id + from, len);
+	*retlen = len;
+error:
+	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+	return ret;
+}
+
+void winbond_otp_register(struct mtd_info *mtd)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	if (nor->read_xfer && nor->write_xfer) {
+		mtd->_get_user_prot_info = winbond_get_user_otp_info;
+		mtd->_read_user_prot_reg = winbond_read_user_otp;
+		mtd->_write_user_prot_reg = winbond_write_user_otp;
+		mtd->_lock_user_prot_reg = winbond_lock_user_otp;
+		mtd->_get_fact_prot_info = winbond_get_fact_otp_info;
+		mtd->_read_fact_prot_reg = winbond_read_fact_otp;
+	} else
+		dev_err(nor->dev, "Required nor interfaces "
+				"(read_xfer, write_xfer) not defined\n");
+}
diff --git a/drivers/mtd/spi-nor/winbond-otp.h b/drivers/mtd/spi-nor/winbond-otp.h
new file mode 100644
index 0000000..29cbbcc
--- /dev/null
+++ b/drivers/mtd/spi-nor/winbond-otp.h
@@ -0,0 +1,20 @@
+/*
+ * Imagination Technologies
+ *
+ * Copyright (c) 2015 Imagination Technologies Ltd.
+ *
+ * This program 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.
+ */
+
+#ifndef WINBOND_OTP_H
+#define WINBOND_OTP_H
+
+#ifdef CONFIG_MTD_SPI_NOR_WINBOND_OTP
+void winbond_otp_register(struct mtd_info *mtd);
+#else
+static inline void winbond_otp_register(struct mtd_info *mtd) { return; }
+#endif
+
+#endif
diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index d25eb39..2759fb3 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -21,6 +21,7 @@
 #include <linux/skbuff.h>
 #include <linux/of_gpio.h>
 #include <linux/ieee802154.h>
+#include <linux/clk-provider.h>
 
 #include <net/mac802154.h>
 #include <net/cfg802154.h>
@@ -212,6 +213,7 @@
 	bool disable_tx;		/* don't send any packets */
 	bool disable_rx;		/* disable rx */
 	bool started;			/* Flag to know if device is up */
+	struct clk *clk;		/* external clock */
 };
 
 /* Generic Functions */
@@ -789,11 +791,45 @@
 		 * default to 1MHz(reset value)
 		 */
 		pdata->extclockfreq = CC2520_EXTCLOCK_DEFAULT_FREQ;
-	}
+	} else
+		pdata->registerclk = true;
 
 	return 0;
 }
 
+static int cc2520_register_clk(struct spi_device *spi,
+			       struct cc2520_platform_data *pdata)
+{
+	struct device_node *np = spi->dev.of_node;
+	struct cc2520_private *priv = spi_get_drvdata(spi);
+	int ret = 0;
+
+	if (pdata->registerclk) {
+		if (np) {
+			priv->clk = clk_register_fixed_rate(&spi->dev, np->name,
+					NULL, CLK_IS_ROOT, pdata->extclockfreq);
+
+			if (!IS_ERR(priv->clk)) {
+				ret = of_clk_add_provider(np,
+							  of_clk_src_simple_get,
+							  priv->clk);
+				if (ret) {
+					clk_unregister(priv->clk);
+					dev_err(&spi->dev,
+						"Failed to add clk provider\n");
+				}
+			} else {
+				dev_err(&spi->dev, "Failed to register clk\n");
+				ret = PTR_ERR(priv->clk);
+			}
+		} else
+			dev_err(&spi->dev, "No device node found, ext-clk won't"
+						" be registered\n");
+	}
+
+	return ret;
+}
+
 static int cc2520_hw_init(struct cc2520_private *priv)
 {
 	u8 status = 0, state = 0xff;
@@ -1153,10 +1189,21 @@
 
 	ret = sysfs_create_group(&spi->dev.kobj, &dev_attr_group);
 	if (ret)
-		goto err_hw_init;
+		goto err_free_device;
+
+	ret = cc2520_register_clk(spi, &pdata);
+	if (ret)
+		goto err_free_sysfs;
 
 	return 0;
 
+err_free_sysfs:
+	sysfs_remove_group(&spi->dev.kobj, &dev_attr_group);
+
+err_free_device:
+	ieee802154_unregister_hw(priv->hw);
+	ieee802154_free_hw(priv->hw);
+
 err_hw_init:
 	mutex_destroy(&priv->buffer_mutex);
 	flush_work(&priv->fifop_irqwork);
@@ -1167,6 +1214,11 @@
 {
 	struct cc2520_private *priv = spi_get_drvdata(spi);
 
+	if (priv->clk) {
+		of_clk_del_provider(spi->dev.of_node);
+		clk_unregister(priv->clk);
+	}
+
 	sysfs_remove_group(&spi->dev.kobj, &dev_attr_group);
 	mutex_destroy(&priv->buffer_mutex);
 	flush_work(&priv->fifop_irqwork);
diff --git a/drivers/net/wireless/uccp420wlan/inc/core.h b/drivers/net/wireless/uccp420wlan/inc/core.h
index abb9fa3..1adf5cf 100644
--- a/drivers/net/wireless/uccp420wlan/inc/core.h
+++ b/drivers/net/wireless/uccp420wlan/inc/core.h
@@ -88,7 +88,8 @@
 #define TX_COMPLETE_TIMEOUT_TICKS msecs_to_jiffies(TX_COMPLETE_TIMEOUT)
 #define SCAN_ABORT_TIMEOUT 1000
 #define SCAN_ABORT_TIMEOUT_TICKS msecs_to_jiffies(SCAN_ABORT_TIMEOUT)
-
+#define CANCEL_HW_ROC_TIMEOUT 1000
+#define CANCEL_HW_ROC_TIMEOUT_TICKS msecs_to_jiffies(CANCEL_HW_ROC_TIMEOUT)
 
 #define DEFAULT_TX_ANT_SELECT 3 /* bitmap of antennas for tx, 3=> both first and
 				 * second antenna to be used
@@ -202,6 +203,8 @@
 	int payload_length;
 	int start_prod_mode;
 	int init_prod;
+	unsigned char bypass_vpd;
+	unsigned int cont_tx;
 };
 
 struct cmd_send_recv_cnt {
@@ -334,6 +337,10 @@
 	unsigned int cts_received_mcp_cnt;
 
 	/*MAC Stats*/
+	unsigned int roc_start;
+	unsigned int roc_stop;
+	unsigned int roc_complete;
+	unsigned int roc_stop_complete;
 	/* TX related */
 	unsigned int tx_cmd_cnt; /* Num of TX commands received from host */
 	unsigned int tx_done_cnt; /* Num of Tx done events sent to host */
@@ -388,10 +395,12 @@
 	struct sk_buff_head pkt;
 	unsigned int hdr_len;
 	unsigned int queue;
+	unsigned int vif_index;
 	unsigned int rate[4];
 	unsigned int retries[4];
 	unsigned int curr_retries;
 	unsigned int max_retries;
+	int roc_peer_id;
 	bool adjusted_rates;
 };
 
@@ -410,11 +419,13 @@
 	unsigned int next_spare_token_ac;
 
 	/* Used to store the address of pending skbs per ac */
-	struct sk_buff_head pending_pkt[MAX_PEND_Q_PER_AC][NUM_ACS];
+	struct sk_buff_head pending_pkt[MAX_UMAC_VIF_CHANCTX_TYPES]
+				       [MAX_PEND_Q_PER_AC]
+				       [NUM_ACS];
 
 #ifdef MULTI_CHAN_SUPPORT
 	/* Peer which has the opportunity to xmit next on a queue */
-	unsigned int curr_peer_opp[MAX_CHANCTX][NUM_ACS];
+	unsigned int curr_peer_opp[MAX_CHANCTX + MAX_OFF_CHANCTX][NUM_ACS];
 #else
 	unsigned int curr_peer_opp[NUM_ACS];
 #endif
@@ -423,8 +434,9 @@
 	 * it will be used in tx complete.
 	 */
 #ifdef MULTI_CHAN_SUPPORT
-	unsigned char desc_chan_map[NUM_TX_DESCS];
-	struct tx_pkt_info pkt_info[MAX_CHANCTX][NUM_TX_DESCS];
+	int desc_chan_map[NUM_TX_DESCS];
+	struct tx_pkt_info pkt_info[MAX_CHANCTX + MAX_OFF_CHANCTX]
+				   [NUM_TX_DESCS];
 #else
 	struct tx_pkt_info pkt_info[NUM_TX_DESCS];
 #endif
@@ -462,17 +474,17 @@
 #endif
 
 struct current_channel {
+	unsigned int pri_chnl_num;
 	unsigned int center_freq1;
 	unsigned int center_freq2;
 	unsigned int freq_band;
 	unsigned int ch_width;
-	unsigned int pri_chnl_num;
 };
 
 struct roc_params {
 	unsigned char roc_in_progress;
-	unsigned char roc_ps_changed;
-	unsigned char roc_chan_changed;
+	unsigned int roc_type;
+	bool need_offchan;
 	atomic_t roc_mgmt_tx_count;
 };
 
@@ -480,11 +492,12 @@
 	struct proc_dir_entry *umac_proc_dir_entry;
 	struct device *dev;
 	struct mac_address if_mac_addresses[MAX_VIFS];
+	unsigned int current_vif_count;
 	unsigned int active_vifs;
 	struct mutex mutex;
 	int state;
 	int txpower;
-	unsigned char	mc_filters[MCST_ADDR_LIMIT][6];
+	unsigned char mc_filters[MCST_ADDR_LIMIT][6];
 	int mc_filter_count;
 
 	struct tasklet_struct proc_tx_tasklet;
@@ -504,6 +517,8 @@
 	struct wifi_stats  *stats;
 	char name[20];
 	char scan_abort_done;
+	char cancel_hw_roc_done;
+	char cancel_roc;
 	char chan_prog_done;
 	char reset_complete;
 	int power_save; /* Will be set only when a single VIF in
@@ -517,12 +532,15 @@
 				* when transmitting bcast frames in AP in IBSS
 				* modes
 				*/
+	spinlock_t roc_lock;
 	unsigned char tx_antenna;
 	unsigned char tx_last_beacon;
 	unsigned int rts_threshold;
 #ifdef MULTI_CHAN_SUPPORT
 	spinlock_t chanctx_lock;
 	struct ieee80211_chanctx_conf *chanctx[MAX_CHANCTX];
+	struct umac_chanctx *off_chanctx[MAX_OFF_CHANCTX];
+	int roc_off_chanctx_idx;
 	int curr_chanctx_idx;
 	int num_active_chanctx;
 #endif
@@ -564,6 +582,7 @@
 #ifdef MULTI_CHAN_SUPPORT
 	struct list_head list;
 	struct umac_chanctx *chanctx;
+	struct umac_chanctx *off_chanctx;
 #endif
 };
 
@@ -585,15 +604,23 @@
 
 #endif
 
+struct curr_peer_info {
+	int id;
+	int op_chan_idx;
+};
 
-extern int wait_for_scan_abort(struct mac80211_dev *dev);
-extern int wait_for_channel_prog_complete(struct mac80211_dev *dev);
-extern int uccp420wlan_prog_nw_selection(unsigned int nw_select_enabled,
-					 unsigned char *mac_addr);
+
 #ifdef MULTI_CHAN_SUPPORT
 void uccp420wlan_proc_ch_sw_event(struct umac_event_ch_switch *ch_sw_info,
 				  void *context);
 #endif
+extern int wait_for_cancel_hw_roc(struct mac80211_dev *dev);
+extern int wait_for_scan_abort(struct mac80211_dev *dev);
+extern int wait_for_channel_prog_complete(struct mac80211_dev *dev);
+extern int wait_for_tx_queue_flush_complete(struct mac80211_dev *dev,
+					    unsigned int token);
+extern int uccp420wlan_prog_nw_selection(unsigned int nw_select_enabled,
+					 unsigned char *mac_addr);
 extern int  uccp420wlan_core_init(struct mac80211_dev *dev, unsigned int ftm);
 extern void uccp420wlan_core_deinit(struct mac80211_dev *dev, unsigned int ftm);
 extern void uccp420wlan_vif_add(struct umac_vif  *uvif);
@@ -622,30 +649,43 @@
 				  bool retry);
 extern void uccp420wlan_tx_init(struct mac80211_dev *dev);
 extern void uccp420wlan_tx_deinit(struct mac80211_dev *dev);
-
+void uccp420wlan_tx_proc_send_pend_frms_all(struct mac80211_dev *dev,
+					   int chan_id);
 extern void proc_bss_info_changed(unsigned char *mac_addr, int value);
 extern void packet_generation(unsigned long data);
 extern int wait_for_reset_complete(struct mac80211_dev *dev);
 
-extern void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev,
+extern int uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev,
 				   int queue,
 #ifdef MULTI_CHAN_SUPPORT
 				   int curr_chanctx_idx,
 #endif
-				   int peer_id,
 				   int token_id);
-int get_curr_peer_opp(struct mac80211_dev *dev,
+void free_token(struct mac80211_dev *dev,
+		int token_id,
+		int queue);
+
+struct curr_peer_info get_curr_peer_opp(struct mac80211_dev *dev,
 #ifdef MULTI_CHAN_SUPPORT
 		      int curr_chanctx_idx,
 #endif
 		      int queue);
 
+int uccp420_flush_vif_queues(struct mac80211_dev *dev,
+			     struct umac_vif *uvif,
+			     int chanctx_idx,
+			     unsigned int hw_queue_map,
+			     enum UMAC_VIF_CHANCTX_TYPE vif_chanctx_type);
+
 /* Beacon TimeStamp */
 __s32 __attribute__((weak)) frc_to_atu(__u32 frccnt, __u64 *patu, s32 dir);
 int __attribute__((weak)) get_evt_timer_freq(unsigned int *mask,
 						unsigned int *num,
 						unsigned int *denom);
 
+int tx_queue_map(int queue);
+int tx_queue_unmap(int queue);
+
 extern unsigned char *rf_params_vpd;
 extern int num_streams_vpd;
 
diff --git a/drivers/net/wireless/uccp420wlan/inc/host_umac_if.h b/drivers/net/wireless/uccp420wlan/inc/host_umac_if.h
index 5d41ad9..bb3034a 100644
--- a/drivers/net/wireless/uccp420wlan/inc/host_umac_if.h
+++ b/drivers/net/wireless/uccp420wlan/inc/host_umac_if.h
@@ -40,7 +40,9 @@
 #define MAX_PEND_Q_PER_AC (MAX_PEERS + MAX_VIFS)
 
 #ifdef MULTI_CHAN_SUPPORT
-#define MAX_CHANCTX 2
+#define MAX_CHANCTX MAX_VIFS
+#define MAX_OFF_CHANCTX MAX_VIFS
+#define OFF_CHANCTX_IDX_BASE MAX_CHANCTX
 #endif
 
 #define WEP40_KEYLEN 5
@@ -246,6 +248,10 @@
 
 struct umac_event_mac_stats {
 	struct host_mac_msg_hdr hdr;
+	unsigned int roc_start;
+	unsigned int roc_stop;
+	unsigned int roc_complete;
+	unsigned int roc_stop_complete;
 	/* TX related */
 	unsigned int tx_cmd_cnt; /* Num of TX commands received from host */
 	unsigned int tx_done_cnt; /* Num of Tx done events sent to host */
@@ -342,12 +348,6 @@
 	TRIG_DISCONNECT
 };
 
-struct umac_event_roc_status {
-	struct host_mac_msg_hdr hdr;
-	unsigned int roc_status;
-} __packed;
-
-
 struct umac_event_ps_econ_wake {
 	struct host_mac_msg_hdr hdr;
 	enum UMAC_PS_ECON_WAKE_TRIG trigger;
@@ -402,6 +402,7 @@
 #ifdef MULTI_CHAN_SUPPORT
 	UMAC_CMD_CHANCTX_TIME_INFO,
 #endif
+	UMAC_CMD_CONT_TX,
 };
 
 enum UMAC_EVENT_TAG {
@@ -709,7 +710,9 @@
 	unsigned int roc_ctrl;
 	unsigned int roc_channel;
 	unsigned int roc_duration;
-
+#define ROC_TYPE_NORMAL 0
+#define ROC_TYPE_OFFCHANNEL_TX 1
+	unsigned int roc_type;
 } __packed;
 
 enum POWER_SAVE_TAG {
@@ -932,6 +935,12 @@
 	unsigned int chain_id;
 } __packed;
 
+struct cmd_cont_tx {
+	struct host_mac_msg_hdr hdr;
+	unsigned int op;
+} __packed;
+
+
 
 /* DFS SUPPORT */
 /* Command to start/stop Radar detection operation */
@@ -1127,4 +1136,9 @@
 	unsigned int bt_state;
 } __packed;
 
+struct umac_event_roc_status {
+	struct host_mac_msg_hdr hdr;
+	unsigned int roc_status;
+} __packed;
+
 #endif /*_UCCP420HOST_UMAC_IF_H_*/
diff --git a/drivers/net/wireless/uccp420wlan/inc/umac_if.h b/drivers/net/wireless/uccp420wlan/inc/umac_if.h
index cd6ba74..63c1584 100644
--- a/drivers/net/wireless/uccp420wlan/inc/umac_if.h
+++ b/drivers/net/wireless/uccp420wlan/inc/umac_if.h
@@ -33,6 +33,8 @@
 #include "hal.h"
 #include "host_umac_if.h"
 
+#define UMAC_ROC_AC WLAN_AC_VO
+
 struct umac_key {
 	unsigned char *peer_mac;
 	unsigned char *tx_mic;
@@ -184,6 +186,7 @@
 
 extern int uccp420wlan_prog_rcv_bcn_mode(unsigned int  bcn_rcv_mode);
 extern int uccp420wlan_prog_aux_adc_chain(unsigned int chain_id);
+extern int uccp420wlan_cont_tx(int val);
 extern int uccp420wlan_prog_txq_params(int index,
 				       unsigned char *vif_addr,
 				       unsigned int queue,
@@ -235,7 +238,8 @@
 
 extern int uccp420wlan_prog_roc(unsigned int roc_status,
 				unsigned int roc_channel,
-				unsigned int roc_duration);
+				unsigned int roc_duration,
+				unsigned int roc_type);
 
 #ifdef CONFIG_PM
 extern int uccp420wlan_prog_econ_ps_state(int if_index,
diff --git a/drivers/net/wireless/uccp420wlan/inc/version.h b/drivers/net/wireless/uccp420wlan/inc/version.h
index c2a476c..99f0685 100644
--- a/drivers/net/wireless/uccp420wlan/inc/version.h
+++ b/drivers/net/wireless/uccp420wlan/inc/version.h
@@ -23,7 +23,7 @@
  */
 #ifndef _UCCP420WLAN_VERSION_H
 #define _UCCP420WLAN_VERSION_H
-#define UCCP_DRIVER_VERSION "4_5_8"
+#define UCCP_DRIVER_VERSION "6_0_2"
 #define UCCP_DRIVER_NAME "UCCP420WIFI"
 #endif /* _UCCP420WLAN_VERSION_H */
 
diff --git a/drivers/net/wireless/uccp420wlan/src/80211_if.c b/drivers/net/wireless/uccp420wlan/src/80211_if.c
index b6f13ff..774d9c0 100644
--- a/drivers/net/wireless/uccp420wlan/src/80211_if.c
+++ b/drivers/net/wireless/uccp420wlan/src/80211_if.c
@@ -178,7 +178,7 @@
 };
 
 
-/* Interface combinations for Virtual interfaces*/
+/* Interface combinations for Virtual interfaces */
 static const struct ieee80211_iface_limit if_limit1[] = {
 		{ .max = 2, .types = BIT(NL80211_IFTYPE_STATION)}
 };
@@ -203,7 +203,8 @@
 #ifdef MULTI_CHAN_SUPPORT
 static const struct ieee80211_iface_limit if_limit5[] = {
 		{ .max = 1, .types = BIT(NL80211_IFTYPE_STATION)},
-		{ .max = 1, .types = BIT(NL80211_IFTYPE_AP)}
+		{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
+				     BIT(NL80211_IFTYPE_P2P_GO)}
 };
 #endif
 
@@ -274,6 +275,111 @@
 }
 
 
+static void uccp420_roc_complete_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = NULL;
+	struct mac80211_dev *dev = NULL;
+	unsigned long flags;
+	struct umac_chanctx *off_chanctx = NULL;
+	struct umac_vif *uvif = NULL, *tmp = NULL;
+	struct tx_config *tx = NULL;
+	u32 roc_queue = 0;
+	bool need_offchan;
+	int roc_off_chanctx_idx = -1;
+	int chan_id = 0;
+
+	dwork = container_of(work, struct delayed_work, work);
+	dev = container_of(dwork, struct mac80211_dev, roc_complete_work);
+	tx = &dev->tx;
+
+	mutex_lock(&dev->mutex);
+	need_offchan = dev->roc_params.need_offchan;
+
+	roc_queue = tx_queue_unmap(UMAC_ROC_AC);
+	roc_off_chanctx_idx = dev->roc_off_chanctx_idx;
+
+	/* Stop the ROC queue */
+	ieee80211_stop_queue(dev->hw, roc_queue);
+	/* Unlock RCU immediately as we are freeing off_chanctx in this funciton
+	 * only and because flush_vif_queues sleep
+	 */
+	rcu_read_lock();
+	off_chanctx = rcu_dereference(dev->off_chanctx[roc_off_chanctx_idx]);
+	rcu_read_unlock();
+
+	list_for_each_entry_safe(uvif, tmp, &off_chanctx->vifs, list) {
+		if (uvif == NULL || uvif->off_chanctx  == NULL)
+			continue;
+		/* Flush the TX queues */
+		uccp420_flush_vif_queues(dev,
+					 uvif,
+					 uvif->off_chanctx->index,
+					 BIT(UMAC_ROC_AC),
+					 UMAC_VIF_CHANCTX_TYPE_OFF);
+
+
+		spin_lock_irqsave(&tx->lock, flags);
+		spin_lock(&dev->chanctx_lock);
+
+		/* ROC DONE: Move the channel context */
+		if (uvif->chanctx)
+			dev->curr_chanctx_idx = uvif->chanctx->index;
+		else
+			dev->curr_chanctx_idx = -1;
+
+		spin_unlock(&dev->chanctx_lock);
+		spin_unlock_irqrestore(&tx->lock, flags);
+
+		if (need_offchan) {
+			/* DEL from OFF chan list */
+			list_del_init(&uvif->list);
+			if (uvif->chanctx) {
+				/* Add it back to OP chan list */
+				list_add_tail(&uvif->list,
+					      &uvif->chanctx->vifs);
+
+				/* !need_offchan: In this case, the frames are
+				 * transmitted, so trigger is not needed.
+				 *
+				 * need_offchan: In this case, frames are
+				 * buffered so we need trigger in case no frames
+				 * come from mac80211.
+				 */
+				/* Process OPER pending frames only.
+				 * TXQ is flushed before start of ROC
+				 */
+				chan_id = uvif->chanctx->index;
+				uccp420wlan_tx_proc_send_pend_frms_all(dev,
+								       chan_id);
+			}
+			off_chanctx->nvifs--;
+		}
+		uvif->off_chanctx = NULL;
+	}
+
+	if (need_offchan)
+		kfree(off_chanctx);
+
+
+	rcu_assign_pointer(dev->off_chanctx[roc_off_chanctx_idx], NULL);
+	dev->roc_off_chanctx_idx = -1;
+	dev->roc_params.roc_in_progress = 0;
+
+	if (dev->cancel_roc == 0) {
+		ieee80211_remain_on_channel_expired(dev->hw);
+		DEBUG_LOG("%s-80211IF: ROC STOPPED..\n", dev->name);
+	} else {
+		dev->cancel_hw_roc_done = 1;
+		dev->cancel_roc = 0;
+		DEBUG_LOG("%s-80211IF: ROC CANCELLED..\n", dev->name);
+	}
+
+	/* Start the ROC queue */
+	ieee80211_wake_queue(dev->hw, roc_queue);
+	mutex_unlock(&dev->mutex);
+}
+
+
 static void tx(struct ieee80211_hw *hw,
 	       struct ieee80211_tx_control *txctl,
 	       struct sk_buff *skb)
@@ -377,10 +483,13 @@
 		mutex_unlock(&dev->mutex);
 		return -ENODEV;
 	}
+
 	INIT_DELAYED_WORK(&dev->roc_complete_work, uccp420_roc_complete_work);
+
 	dev->state = STARTED;
 	memset(dev->params->pdout_voltage, 0,
 	       sizeof(char) * MAX_AUX_ADC_SAMPLES);
+	dev->roc_off_chanctx_idx = -1;
 	mutex_unlock(&dev->mutex);
 
 	return 0;
@@ -408,19 +517,28 @@
 	struct umac_vif   *uvif;
 	int vif_index, iftype;
 
+	mutex_lock(&dev->mutex);
 	iftype = vif->type;
 	v = vif;
 	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
 	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
 
-	if (!(iftype == NL80211_IFTYPE_STATION ||
-				iftype == NL80211_IFTYPE_ADHOC ||
-				iftype == NL80211_IFTYPE_AP)) {
-		pr_err("Invalid Interface type\n");
+	if (dev->current_vif_count == wifi->params.num_vifs) {
+		pr_err("%s: Exceeded Maximum supported VIF's cur:%d max: %d.\n",
+		       __func__,
+		       dev->current_vif_count,
+		       wifi->params.num_vifs);
+
+		mutex_unlock(&dev->mutex);
 		return -ENOTSUPP;
 	}
 
-	mutex_lock(&dev->mutex);
+	if (!(iftype == NL80211_IFTYPE_STATION ||
+	      iftype == NL80211_IFTYPE_ADHOC ||
+	      iftype == NL80211_IFTYPE_AP)) {
+		pr_err("Invalid Interface type\n");
+		return -ENOTSUPP;
+	}
 
 	if (wifi->params.production_test) {
 		if (dev->active_vifs || iftype != NL80211_IFTYPE_ADHOC) {
@@ -448,6 +566,7 @@
 	uvif->seq_no = 0;
 	uccp420wlan_vif_add(uvif);
 	dev->active_vifs |= (1 << vif_index);
+	dev->current_vif_count++;
 
 	if (iftype == NL80211_IFTYPE_ADHOC)
 		dev->tx_last_beacon = 0;
@@ -467,16 +586,16 @@
 	struct ieee80211_vif *v;
 	int vif_index;
 
+	mutex_lock(&dev->mutex);
 	v = vif;
 	vif_index = ((struct umac_vif *)&v->drv_priv)->vif_index;
 
-	mutex_lock(&dev->mutex);
-
 	uccp420wlan_vif_remove((struct umac_vif *)&v->drv_priv);
 	dev->active_vifs &= ~(1 << vif_index);
 	rcu_assign_pointer(dev->vifs[vif_index], NULL);
 	synchronize_rcu();
 
+	dev->current_vif_count--;
 	mutex_unlock(&dev->mutex);
 
 }
@@ -587,9 +706,9 @@
 	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
 
 		DEBUG_LOG("%s-80211IF:Retry Limits changed to %d and %d\n",
-			       dev->name,
-			       conf->short_frame_max_tx_count,
-			       conf->long_frame_max_tx_count);
+			  dev->name,
+			  conf->short_frame_max_tx_count,
+			  conf->long_frame_max_tx_count);
 	}
 
 	for (i = 0; i < MAX_VIFS; i++) {
@@ -1136,6 +1255,7 @@
 	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
 	hw->max_listen_interval = 10;
 	hw->wiphy->max_remain_on_channel_duration = 5000; /*ROC*/
+	hw->offchannel_tx_hw_queue = WLAN_AC_VO;
 	hw->max_rates = 4;
 	hw->max_rate_tries = 5;
 	hw->queues = 4;
@@ -1271,193 +1391,160 @@
 }
 
 
-static void uccp420_roc_complete_work(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	int i;
-	struct mac80211_dev *dev;
-
-	dwork = container_of(work, struct delayed_work, work);
-	dev = container_of(dwork, struct mac80211_dev, roc_complete_work);
-
-	if (atomic_read(&dev->roc_params.roc_mgmt_tx_count) != 0) {
-		DEBUG_LOG("%s:%d but %d off channel tx frames pending\n",
-			  __func__,
-			  __LINE__,
-			  atomic_read(&dev->roc_params.roc_mgmt_tx_count));
-		return;
-	}
-
-	/* ROC Completed */
-	mutex_lock(&dev->mutex);
-
-	/* Put the chip back to its original state */
-	for (i = 0; i < MAX_VIFS; i++) {
-
-		if (!dev->roc_params.roc_ps_changed)
-			break;
-
-		if (!(dev->active_vifs & (1 << i)))
-			continue;
-
-		uccp420wlan_prog_ps_state(i,
-					  dev->if_mac_addresses[i].addr,
-					  dev->power_save);
-	}
-
-	dev->roc_params.roc_ps_changed = 0;
-
-	if (dev->roc_params.roc_chan_changed) {
-		dev->chan_prog_done = 0;
-
-		uccp420wlan_prog_channel(dev->cur_chan.pri_chnl_num,
-					 dev->cur_chan.center_freq1,
-					 dev->cur_chan.center_freq2,
-					 dev->cur_chan.ch_width,
-#ifdef MULTI_CHAN_SUPPORT
-					 0,
-#endif
-					 dev->cur_chan.freq_band);
-
-		if (wait_for_channel_prog_complete(dev)) {
-			pr_err("%s:%d ROC Complete: Programming the Channel %d Timed-out (500ms)\n",
-			       __func__, __LINE__, dev->cur_chan.pri_chnl_num);
-			dev->roc_params.roc_in_progress = 0;
-			dev->roc_params.roc_chan_changed = 0;
-			ieee80211_remain_on_channel_expired(dev->hw);
-			mutex_unlock(&dev->mutex);
-
-			/* Unable to go back to Home channel, what next?? */
-			return;
-		}
-
-		dev->roc_params.roc_chan_changed = 0;
-	}
-
-	/* Inform FW that ROC is started */
-	uccp420wlan_prog_roc(ROC_START, dev->cur_chan.pri_chnl_num, 0);
-
-	ieee80211_remain_on_channel_expired(dev->hw);
-	dev->roc_params.roc_in_progress = 0;
-
-	DEBUG_LOG("%s:%d Coming back to Orig: %d\n",
-		  __func__,
-		  __LINE__,
-		  dev->power_save);
-
-	mutex_unlock(&dev->mutex);
-}
-
-
 static int remain_on_channel(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_channel *channel,
 			     int duration,
 			     enum ieee80211_roc_type type)
-
 {
-	int i;
 	struct mac80211_dev *dev = (struct mac80211_dev *)hw->priv;
-	unsigned int pri_chnl_num = 0;
-	unsigned int chnl_num1 = 0;
-	unsigned int freq_band = channel->band;
-	unsigned int ch_width = 0; /* 20MHz */
-#ifdef MULTI_CHAN_SUPPORT
+	unsigned int pri_chnl_num =
+		ieee80211_frequency_to_channel(channel->center_freq);
 	struct umac_vif *uvif = (struct umac_vif *)vif->drv_priv;
-#endif
-
-	pri_chnl_num = ieee80211_frequency_to_channel(channel->center_freq);
-	chnl_num1 = ieee80211_frequency_to_channel(channel->center_freq);
+	struct umac_chanctx *off_chanctx = NULL;
+	int off_chanctx_id = 0, i = 0;
+	unsigned long flags;
+	struct tx_config *tx = &dev->tx;
+	u32 hw_queue_map = 0;
+	struct ieee80211_chanctx_conf *vif_chanctx;
+	bool need_offchan = true;
 
 	mutex_lock(&dev->mutex);
 
-	DEBUG_LOG("%s:%d orig_ps: %d The Params are: channel:%d\n",
-		  __func__, __LINE__,
-		  dev->power_save,
-		  pri_chnl_num);
-	DEBUG_LOG("	duration:%d type: %d c1:%d band:%d\n",
+	DEBUG_LOG("%s-80211IF: Params are Chan:%d Dur:%d Type: %d\n",
+		  dev->name,
+		  ieee80211_frequency_to_channel(channel->center_freq),
 		  duration,
-		  type,
-		  chnl_num1,
-		  freq_band);
+		  type);
 
-	/* Put the chip in powersave */
-	for (i = 0; i < MAX_VIFS; i++) {
-		if (dev->power_save == PWRSAVE_STATE_AWAKE)
-			break;
-
-		dev->roc_params.roc_ps_changed = 1;
-
-		if (!(dev->active_vifs & (1 << i)))
-			continue;
-
-		uccp420wlan_prog_ps_state(i,
-					  dev->if_mac_addresses[i].addr,
-					  PWRSAVE_STATE_AWAKE);
+	if (dev->roc_params.roc_in_progress) {
+		DEBUG_LOG("%s-80211IF: Dropping roc...Busy\n", dev->name);
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
 	}
 
-	do {
-		if (dev->cur_chan.pri_chnl_num == pri_chnl_num)
-			break;
+	if (dev->num_active_chanctx == 2) {
+		DEBUG_LOG("%s-80211IF: ROC is not supported in TSMC Mode\n",
+			  dev->name);
 
-		DEBUG_LOG("%s:%d Programming the Channel\n",
-			  __func__, __LINE__);
-
-		dev->chan_prog_done = 0;
-
-		uccp420wlan_prog_channel(dev->cur_chan.pri_chnl_num,
-					channel->center_freq,
-					 0,
-					 ch_width,
-#ifdef MULTI_CHAN_SUPPORT
-					 uvif->vif_index,
-#endif
-					 freq_band);
-
-		if (!wait_for_channel_prog_complete(dev)) {
-			dev->roc_params.roc_chan_changed = 1;
-			break;
-		}
-
-		pr_err("%s:%d ROC Start: Programming the Channel %d Timed-out (500ms)\n",
-			__func__, __LINE__, pri_chnl_num);
-
-		/* Put the chip back to its orig state*/
-		for (i = 0; i < MAX_VIFS; i++) {
-			if (!dev->roc_params.roc_ps_changed)
-				break;
-
-			if (!(dev->active_vifs & (1 << i)))
-				continue;
-
-			uccp420wlan_prog_ps_state(i,
-						  dev->if_mac_addresses[i].addr,
-						  dev->power_save);
-		}
-
-		dev->roc_params.roc_ps_changed = 0;
-
-		ieee80211_remain_on_channel_expired(dev->hw);
 		mutex_unlock(&dev->mutex);
+		return -ENOTSUPP;
+	}
 
-		return 0;
+	/* Inform FW that ROC is started:
+	 * For pure TX we send OFFCHANNEL_TX so that driver can terminate ROC
+	 * For Tx + Rx we use NORMAL, FW will terminate ROC based on duration.
+	 */
+	if (duration != 10 && type == ROC_TYPE_OFFCHANNEL_TX)
+		type = ROC_TYPE_NORMAL;
 
-	} while (0);
+	/* uvif is in connected state
+	 */
+	if (uvif->chanctx) {
+		rcu_read_lock();
 
-	DEBUG_LOG("%s:%d Programming the Channel Success:%d\n",
-		  __func__, __LINE__,
-		  dev->chan_prog_done);
+		vif_chanctx =
+			rcu_dereference(dev->chanctx[uvif->chanctx->index]);
 
-	/* Inform FW that ROC is started */
-	uccp420wlan_prog_roc(ROC_START, pri_chnl_num, duration);
+		/* AS ROC frames are MGMT frames, checking only for Primary
+		 * Channel.
+		 */
+		if (vif_chanctx->def.chan->center_freq == channel->center_freq)
+			need_offchan = false;
 
-	ieee80211_queue_delayed_work(hw,
-				     &dev->roc_complete_work,
-				     msecs_to_jiffies(duration));
+		rcu_read_unlock();
+	}
 
-	dev->roc_params.roc_in_progress = 1;
+	DEBUG_LOG("%s-80211IF: need_offchan: %d\n", dev->name, need_offchan);
+	dev->roc_params.need_offchan = need_offchan;
 
-	ieee80211_ready_on_channel(dev->hw);
+	if (need_offchan) {
+		/* Different chan context than the uvif */
+		off_chanctx = kmalloc(sizeof(struct umac_chanctx),
+				      GFP_KERNEL);
+
+		if (!off_chanctx) {
+			pr_err("%s: Unable to alloc mem for channel context\n",
+			       __func__);
+			mutex_unlock(&dev->mutex);
+			return -ENOMEM;
+		}
+
+		/** Currently OFFCHAN is limited to handling ROC case
+		 *  but it is meant for a generic case.
+		 *  ideally we should look for existing offchan context
+		 *  and re-use/create.
+		 */
+		for (i = 0; i < MAX_OFF_CHANCTX; i++) {
+			if (!dev->off_chanctx[i]) {
+				off_chanctx_id = i;
+				break;
+			}
+		}
+
+		if (uvif->chanctx) {
+			ieee80211_stop_queues(hw);
+
+			hw_queue_map = BIT(WLAN_AC_BK) |
+				BIT(WLAN_AC_BE) |
+				BIT(WLAN_AC_VI) |
+				BIT(WLAN_AC_VO) |
+				BIT(WLAN_AC_BCN);
+
+			uccp420_flush_vif_queues(dev,
+					uvif,
+					uvif->chanctx->index,
+					hw_queue_map,
+					UMAC_VIF_CHANCTX_TYPE_OPER);
+		}
+
+
+		off_chanctx->index = OFF_CHANCTX_IDX_BASE + off_chanctx_id;
+		dev->roc_off_chanctx_idx = off_chanctx_id;
+		INIT_LIST_HEAD(&off_chanctx->vifs);
+		off_chanctx->nvifs = 0;
+
+		if (uvif->chanctx) {
+			/* Delete the uvif from OP channel list */
+			list_del_init(&uvif->list);
+		}
+		/* Add the vif to the off_chanctx */
+		list_add_tail(&uvif->list, &off_chanctx->vifs);
+		off_chanctx->nvifs++;
+		rcu_assign_pointer(dev->off_chanctx[off_chanctx_id],
+				   off_chanctx);
+		synchronize_rcu();
+
+
+		/* Move the channel context */
+		spin_lock_bh(&dev->chanctx_lock);
+		dev->curr_chanctx_idx = off_chanctx->index;
+		spin_unlock_bh(&dev->chanctx_lock);
+	} else {
+		/* Same channel context, just update off_chanctx
+		 * to chanctx
+		 */
+		off_chanctx = uvif->chanctx;
+
+		for (i = 0; i < MAX_OFF_CHANCTX; i++) {
+			if (!dev->off_chanctx[i]) {
+				off_chanctx_id = i;
+				break;
+			}
+		}
+		dev->roc_off_chanctx_idx = off_chanctx->index;
+		rcu_assign_pointer(dev->off_chanctx[off_chanctx_id],
+				   off_chanctx);
+		synchronize_rcu();
+	}
+	spin_lock_irqsave(&tx->lock, flags);
+	uvif->off_chanctx = off_chanctx;
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	uccp420wlan_prog_roc(ROC_START, pri_chnl_num, duration, type);
+
+	if (uvif->chanctx)
+		ieee80211_wake_queues(hw);
 
 	mutex_unlock(&dev->mutex);
 
@@ -1467,34 +1554,34 @@
 
 static int cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
-	int i = 0;
 	struct mac80211_dev *dev = (struct mac80211_dev *)hw->priv;
+	int ret = 0;
 
 	mutex_lock(&dev->mutex);
 
 	if (dev->roc_params.roc_in_progress) {
-		cancel_delayed_work_sync(&dev->roc_complete_work);
+		dev->cancel_hw_roc_done = 0;
+		dev->cancel_roc = 1;
+		DEBUG_LOG("%s-80211IF: Cancelling HW ROC....\n", dev->name);
 
-		/* Put the chip back to its original state */
-		for (i = 0; i < MAX_VIFS; i++) {
-			if (!(dev->active_vifs & (1 << i)))
-				continue;
+		uccp420wlan_prog_roc(ROC_STOP, 0, 0, 0);
 
-			uccp420wlan_prog_ps_state(i,
-						  dev->if_mac_addresses[i].addr,
-						  dev->power_save);
+		mutex_unlock(&dev->mutex);
+
+		if (!wait_for_cancel_hw_roc(dev)) {
+			DEBUG_LOG("%s-80211IF: Cancel HW ROC....done\n",
+				  dev->name);
+			ret = 0;
+		} else {
+			DEBUG_LOG("%s-80211IF: Cancel HW ROC..timedout\n",
+				  dev->name);
+			ret = -1;
 		}
-
-		DEBUG_LOG("%s:%d Coming back to Orig:%d\n",
-			  __func__, __LINE__,
-			  dev->power_save);
-
-		dev->roc_params.roc_in_progress = 0;
+	} else {
+		mutex_unlock(&dev->mutex);
 	}
 
-	mutex_unlock(&dev->mutex);
-
-	return 0;
+	return ret;
 }
 
 
@@ -1563,7 +1650,7 @@
 
 	if (uccp420wlan_prog_econ_ps_state(active_vif_index,
 					   PWRSAVE_STATE_AWAKE)) {
-		pr_err(" %s : Error Occured\n",
+		pr_err("%s : Error Occured\n",
 		       __func__);
 		mutex_unlock(&dev->mutex);
 		return -1;
@@ -1617,7 +1704,7 @@
 	}
 
 	if (count != 1) {
-		pr_err("%s: Economy mode supported only for single VIF in STA mode\n",
+		pr_err("%s: Economy mode supp only for single VIF(STA mode)\n",
 		       __func__);
 		mutex_unlock(&dev->mutex);
 		return -1;
@@ -1731,6 +1818,9 @@
 			       unsigned int len)
 {
 	struct mac80211_dev *dev = (struct mac80211_dev *)context;
+	int i = 0;
+	struct ieee80211_vif *vif = NULL;
+	const char ra[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 	/* DO NOT update the scan results through cfg80211 API's we just pass
 	 * the beacons and probe responses up and mac80211 will inform cfg80211
@@ -1750,6 +1840,25 @@
 			dev->stats->umac_scan_complete++;
 			ieee80211_scan_completed(dev->hw, false);
 
+			/* WAR for TT_PRB0164. To be removed after patch
+			 *  submitted to kernel
+			 */
+			for (i = 0; i < MAX_VIFS; i++) {
+
+				if (!(dev->active_vifs & (1 << i)))
+					continue;
+
+				rcu_read_lock();
+				vif = rcu_dereference(dev->vifs[i]);
+				rcu_read_unlock();
+
+				if (vif->type != NL80211_IFTYPE_AP)
+					continue;
+
+				ieee80211_stop_tx_ba_cb_irqsafe(vif,
+						ra, IEEE80211_NUM_TIDS);
+			}
+
 			/* Keep track of HW Scan requests and compeltes */
 			wifi->params.hw_scan_status = HW_SCAN_STATUS_NONE;
 		}
@@ -1987,8 +2096,8 @@
 	}
 
 	DEBUG_LOG("%s: %d MHz\n",
-			 __func__,
-			 conf->def.chan->center_freq);
+		  __func__,
+		  conf->def.chan->center_freq);
 
 	mutex_lock(&dev->mutex);
 
@@ -2117,20 +2226,37 @@
 	struct mac80211_dev *dev = NULL;
 	struct umac_vif *uvif = NULL;
 	struct umac_chanctx *ctx = NULL;
+	u32 hw_queue_map = 0;
+	int i = 0;
 
 	dev = hw->priv;
 	uvif = (struct umac_vif *)vif->drv_priv;
 	ctx = (struct umac_chanctx *)conf->drv_priv;
 
 	DEBUG_LOG("%s: addr: %pM, type: %d, p2p: %d chan: %d MHz\n",
-			 __func__,
-			 vif->addr,
-			 vif->type,
-			 vif->p2p,
-			 conf->def.chan->center_freq);
+		  __func__,
+		  vif->addr,
+		  vif->type,
+		  vif->p2p,
+		  conf->def.chan->center_freq);
 
 	mutex_lock(&dev->mutex);
 
+	/* We need to specifically handle flushing tx queues for the AP VIF
+	 * here (for STA VIF, mac80211 handles this via flush_queues)
+	 */
+	if (vif->type == NL80211_IFTYPE_AP) {
+		/* Flush all queues for this VIF */
+		for (i = 0; i < NUM_ACS; i++)
+			hw_queue_map |= BIT(i);
+
+		uccp420_flush_vif_queues(dev,
+					 uvif,
+					 uvif->chanctx->index,
+					 hw_queue_map,
+					 UMAC_VIF_CHANCTX_TYPE_OPER);
+	}
+
 	uvif->chanctx = NULL;
 
 	list_del(&uvif->list);
@@ -2154,25 +2280,13 @@
 {
 	struct mac80211_dev *dev = NULL;
 	struct umac_vif *uvif = NULL;
-	struct umac_chanctx *ctx = NULL;
-	unsigned int chan_ctx_id = 0;
-	unsigned int queue = 0;
-	unsigned int pending = 0;
-	int count = 0;
-	int peer_id = -1;
+	u32 hw_queue_map = 0;
 	int i = 0;
-	unsigned long flags = 0;
-	struct sk_buff_head *pend_pkt_q = NULL;
-	struct tx_config *tx = NULL;
-	struct ieee80211_sta *sta = NULL;
-	struct umac_sta *usta = NULL;
 
 	dev = hw->priv;
 
 	mutex_lock(&dev->mutex);
 
-	tx = &dev->tx;
-
 	if (!vif)
 		goto out;
 
@@ -2181,75 +2295,21 @@
 	if (!uvif->chanctx)
 		goto out;
 
-	if (dev->num_active_chanctx != 2) {
-		DEBUG_LOG("%s-80211IF: Flush is only supported for TSMC case\n",
-			  __func__);
-		goto out;
+	/* Convert the mac80211 queue map to our hw queue map */
+	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+		if (queues & BIT(i))
+			hw_queue_map |= BIT(tx_queue_map(i));
 	}
-
-	ctx = uvif->chanctx;
-	chan_ctx_id = ctx->index;
-
-	for (queue = 0; queue < WLAN_AC_MAX_CNT; queue++) {
-		if (!((1 << queue) & queues))
-			continue;
-
-check_tokens_flush_complete:
-	pending = 0;
-
-	spin_lock_irqsave(&tx->lock, flags);
-	rcu_read_lock();
-
-	for (i = 0; i < MAX_PEND_Q_PER_AC; i++) {
-		if (i < MAX_PEERS) {
-			sta = rcu_dereference(dev->peers[i]);
-
-			if (!sta)
-				continue;
-
-			usta = (struct umac_sta *)(sta->drv_priv);
-
-			if (usta->vif_index == uvif->vif_index)
-				peer_id = i;
-			else
-				continue;
-		} else if (i == uvif->vif_index) {
-			peer_id = uvif->vif_index;
-		} else
-			continue;
-
-		pend_pkt_q = &tx->pending_pkt[peer_id][queue];
-
-		/* Assuming all packets for the peer have same channel
-		 * context
-		 */
-		pending = skb_queue_len(pend_pkt_q);
-	}
-
-	rcu_read_unlock();
-	spin_unlock_irqrestore(&tx->lock, flags);
-
-	if (pending && (count < QUEUE_FLUSH_TIMEOUT_TICKS)) {
-		current->state = TASK_INTERRUPTIBLE;
-
-		if (0 == schedule_timeout(1))
-			count++;
-
-		goto check_tokens_flush_complete;
-	}
-
-	if (pending)
-		DEBUG_LOG("%s: failed for VIF: %d and Queue: %d, pending: %d\n",
-				__func__,
-				uvif->vif_index,
-				queue,
-				pending);
-	else
-		DEBUG_LOG("%s: Flush for VIF: %d and Queue: %d success\n",
-				__func__,
-				uvif->vif_index,
-				queue);
-	}
+	/* This op should not get called during ROC operation, so we can assume
+	 * that the vif_chanctx_type will be UMAC_VIF_CHANCTX_TYPE_OPER. As for
+	 * TSMC operation the VIF can only be associated to one channel context,
+	 * so we pass uvif->chanctx->index as the parameter for chanctx_idx
+	 */
+	uccp420_flush_vif_queues(dev,
+				 uvif,
+				 uvif->chanctx->index,
+				 hw_queue_map,
+				 UMAC_VIF_CHANCTX_TYPE_OPER);
 
 out:
 	mutex_unlock(&dev->mutex);
@@ -2331,6 +2391,7 @@
 	}
 
 	dev = (struct mac80211_dev *)hw->priv;
+	memset(dev, 0, sizeof(struct mac80211_dev));
 
 	hwsim_class = class_create(THIS_MODULE, "uccp420");
 
@@ -2374,6 +2435,7 @@
 	spin_lock_init(&dev->chanctx_lock);
 #endif
 
+	spin_lock_init(&dev->roc_lock);
 	dev->state = STOPPED;
 	dev->active_vifs = 0;
 	dev->txpower = DEFAULT_TX_POWER;
@@ -2391,6 +2453,7 @@
 	dev->params = &wifi->params;
 	dev->stats = &wifi->stats;
 	dev->umac_proc_dir_entry = wifi->umac_proc_dir_entry;
+	dev->current_vif_count = 0;
 	dev->stats->system_rev = system_rev;
 #ifdef MULTI_CHAN_SUPPORT
 	dev->num_active_chanctx = 0;
@@ -2462,6 +2525,7 @@
 	seq_puts(m, "\n");
 
 	seq_printf(m, "production_test = %d\n", wifi->params.production_test);
+	seq_printf(m, "bypass_vpd = %d\n", wifi->params.bypass_vpd);
 	seq_printf(m, "tx_fixed_mcs_indx = %d (%s)\n",
 		   wifi->params.tx_fixed_mcs_indx,
 		   (wifi->params.prod_mode_rate_flag &
@@ -2616,6 +2680,8 @@
 		   wifi->params.payload_length);
 	seq_printf(m, "start_prod_mode = channel: %d\n",
 		   wifi->params.start_prod_mode);
+	seq_printf(m, "continuous_tx = %d\n",
+		   wifi->params.cont_tx);
 
 	if (ftm || wifi->params.production_test)
 		seq_printf(m, "set_tx_power = %d dB\n",
@@ -2915,6 +2981,14 @@
 			   total_rssi_samples);
 
 	seq_puts(m, "************* LMAC STATS ***********\n");
+	seq_printf(m, "roc_start =%d\n",
+		   wifi->stats.roc_start);
+	seq_printf(m, "roc_stop =%d\n",
+		   wifi->stats.roc_stop);
+	seq_printf(m, "roc_complete =%d\n",
+		   wifi->stats.roc_complete);
+	seq_printf(m, "roc_stop_complete =%d\n",
+		   wifi->stats.roc_stop_complete);
 	/* TX related */
 	seq_printf(m, "tx_cmd_cnt =%d\n",
 		   wifi->stats.tx_cmd_cnt);
@@ -3117,6 +3191,12 @@
 			}
 		} else
 			pr_err("Invalid parameter value\n");
+	} else if (param_get_val(buf, "bypass_vpd=", &val)) {
+		if ((val == 0) || (val == 1)) {
+			if (wifi->params.bypass_vpd != val)
+				wifi->params.bypass_vpd = val;
+		} else
+			pr_err("Invalid parameter value\n");
 	} else if (param_get_val(buf, "num_vifs=", &val)) {
 		if (val > 0 && val <= MAX_VIFS) {
 			if (wifi->params.num_vifs != val) {
@@ -3709,6 +3789,13 @@
 			       AUX_ADC_CHAIN1,
 			       AUX_ADC_CHAIN2);
 	} else if ((wifi->params.production_test) &&
+		param_get_val(buf, "continuous_tx=", &val)) {
+		if (val == 0 || val == 1) {
+			wifi->params.cont_tx = val;
+			uccp420wlan_cont_tx(val);
+		   } else
+			pr_err("Invalid tx_continuous parameter\n");
+	} else if ((wifi->params.production_test) &&
 		    param_get_val(buf, "start_prod_mode=", &val)) {
 			unsigned int pri_chnl_num = 0;
 			unsigned int freq_band = IEEE80211_BAND_5GHZ;
diff --git a/drivers/net/wireless/uccp420wlan/src/core.c b/drivers/net/wireless/uccp420wlan/src/core.c
index 9df0fda..45e754a 100644
--- a/drivers/net/wireless/uccp420wlan/src/core.c
+++ b/drivers/net/wireless/uccp420wlan/src/core.c
@@ -117,6 +117,31 @@
 
 }
 
+int wait_for_cancel_hw_roc(struct mac80211_dev *dev)
+{
+	int count = 0;
+
+check_cancel_hw_roc_complete:
+	if (!dev->cancel_hw_roc_done && (count < CANCEL_HW_ROC_TIMEOUT_TICKS)) {
+		current->state = TASK_INTERRUPTIBLE;
+		if (0 == schedule_timeout(1))
+			count++;
+		goto check_cancel_hw_roc_complete;
+	}
+
+	if (!dev->cancel_hw_roc_done) {
+		pr_err("%s-UMAC: Warning: Didn't get CANCEL_HW_ROC_DONE after %ld timer ticks\n",
+		       dev->name,
+		       CANCEL_HW_ROC_TIMEOUT_TICKS);
+		return -1;
+	}
+
+	DEBUG_LOG("%s-UMAC: Cancel HW RoC complete after %d timer ticks\n",
+		   dev->name, count);
+
+	return 0;
+
+}
 
 int wait_for_channel_prog_complete(struct mac80211_dev *dev)
 {
@@ -147,6 +172,38 @@
 
 }
 
+int wait_for_tx_queue_flush_complete(struct mac80211_dev *dev,
+				     unsigned int queue)
+{
+	int count = 0;
+
+check_tx_queue_flush_complete:
+	if (dev->tx.outstanding_tokens[queue] &&
+	    (count < QUEUE_FLUSH_TIMEOUT_TICKS)) {
+		current->state = TASK_INTERRUPTIBLE;
+		if (0 == schedule_timeout(1))
+			count++;
+		goto check_tx_queue_flush_complete;
+	}
+
+	if (dev->tx.outstanding_tokens[queue]) {
+		pr_err("%s-UMAC: Warning: Tx Queue %d flush failed pending: %d after %ld timer ticks\n",
+		       dev->name,
+		       queue,
+		       dev->tx.outstanding_tokens[queue],
+		       QUEUE_FLUSH_TIMEOUT_TICKS);
+		return -1;
+	}
+
+	DEBUG_LOG("%s-UMAC: Flushed Tx queue %d in %d timer ticks\n",
+		  dev->name,
+		  queue,
+		  count);
+
+	return 0;
+
+}
+
 
 int wait_for_reset_complete(struct mac80211_dev *dev)
 {
@@ -880,6 +937,10 @@
 	struct mac80211_dev *dev = (struct mac80211_dev *)context;
 
 	/* TX related */
+	dev->stats->roc_start = mac_stats->roc_start;
+	dev->stats->roc_stop = mac_stats->roc_stop;
+	dev->stats->roc_complete = mac_stats->roc_complete;
+	dev->stats->roc_stop_complete = mac_stats->roc_stop_complete;
 	dev->stats->tx_cmd_cnt = mac_stats->tx_cmd_cnt;
 	dev->stats->tx_done_cnt = mac_stats->tx_done_cnt;
 	dev->stats->tx_edca_trigger_cnt = mac_stats->tx_edca_trigger_cnt;
@@ -1045,168 +1106,6 @@
 #endif
 
 
-#ifdef MULTI_CHAN_SUPPORT
-void uccp420wlan_proc_ch_sw_event(struct umac_event_ch_switch *ch_sw_info,
-				  void *context)
-{
-	struct mac80211_dev *dev = NULL;
-	int chan = 0;
-	int curr_freq = 0;
-	int chan_id = 0;
-	struct sk_buff_head *txq = NULL;
-	int txq_len = 0;
-	int i = 0;
-	int queue = 0;
-	unsigned long flags = 0;
-	int curr_bit = 0;
-	int pool_id = 0;
-	int ret = 0;
-	int peer_id = -1;
-	int ac = 0;
-	struct ieee80211_chanctx_conf *curr_chanctx = NULL;
-	struct tx_config *tx = NULL;
-
-	if (!ch_sw_info || !context) {
-		pr_err("%s: Invalid Parameters\n", __func__);
-		return;
-	}
-
-	dev = (struct mac80211_dev *)context;
-	chan = ch_sw_info->chan;
-	tx = &dev->tx;
-
-	rcu_read_lock();
-
-	for (i = 0; i < MAX_CHANCTX; i++) {
-		curr_chanctx = rcu_dereference(dev->chanctx[i]);
-
-		if (curr_chanctx) {
-			curr_freq = curr_chanctx->def.chan->center_freq;
-
-			if (ieee80211_frequency_to_channel(curr_freq) == chan) {
-				chan_id = i;
-				break;
-			}
-		}
-	}
-
-	rcu_read_unlock();
-
-	if (i == MAX_CHANCTX) {
-		pr_err("%s: Invalid Channel Context: chan: %d\n",
-		       __func__,
-		       chan);
-		return;
-	}
-
-
-	/* Switch to the new channel context */
-	spin_lock(&dev->chanctx_lock);
-	dev->curr_chanctx_idx = chan_id;
-	spin_unlock(&dev->chanctx_lock);
-
-	/* We now try to xmit any frames whose xmission got cancelled due to a
-	 * previous channel switch
-	 */
-	for (i = 0; i < NUM_TX_DESCS; i++) {
-		spin_lock_irqsave(&tx->lock, flags);
-
-		curr_bit = (i % TX_DESC_BUCKET_BOUND);
-		pool_id = (i / TX_DESC_BUCKET_BOUND);
-
-		if (test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) {
-			spin_unlock_irqrestore(&tx->lock, flags);
-			continue;
-		}
-
-		txq = &tx->pkt_info[chan_id][i].pkt;
-		txq_len = skb_queue_len(txq);
-		queue = tx->pkt_info[chan_id][i].queue;
-
-		if (!txq_len) {
-			/* Reserved token */
-			if (i < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
-				queue = (i % NUM_ACS);
-				peer_id = get_curr_peer_opp(dev,
-							    chan_id,
-							    queue);
-
-				if (peer_id == -1) {
-					/* Mark the token as available */
-					__clear_bit(curr_bit,
-						    &tx->buf_pool_bmp[pool_id]);
-
-					spin_unlock_irqrestore(&tx->lock,
-							       flags);
-					continue;
-				}
-
-			/* Spare token */
-			} else {
-				for (ac = WLAN_AC_VO; ac >= 0; ac--) {
-					peer_id = get_curr_peer_opp(dev,
-								    chan_id,
-								    ac);
-
-					if (peer_id != -1) {
-						queue = ac;
-						break;
-					}
-				}
-
-				if (ac < 0) {
-					/* Mark the token as available */
-					__clear_bit(curr_bit,
-						    &tx->buf_pool_bmp[pool_id]);
-
-					spin_unlock_irqrestore(&tx->lock,
-							       flags);
-					continue;
-				}
-			}
-
-			uccp420wlan_tx_proc_pend_frms(dev,
-						      queue,
-						      chan_id,
-						      peer_id,
-						      i);
-
-			tx->outstanding_tokens[queue]++;
-
-		}
-
-		spin_unlock_irqrestore(&tx->lock, flags);
-
-		ret = __uccp420wlan_tx_frame(dev,
-					     queue,
-					     i,
-					     chan_id,
-					     0,
-					     0); /* TODO: Currently sending 0
-						    since this param is not used
-						    as expected in the orig
-						    code for multiple frames etc
-						    Need to set this
-						    properly when the orig code
-						    logic is corrected
-						  */
-		if (ret < 0) {
-			/* SDK: Check if we need to clear the TX bitmap and
-			 * desc_chan_map here
-			 */
-			pr_err("%s: Queueing of TX frame to FW failed\n",
-			       __func__);
-		} else {
-			spin_lock_irqsave(&tx->lock, flags);
-			tx->desc_chan_map[i] = chan_id;
-			spin_unlock_irqrestore(&tx->lock, flags);
-		}
-
-	}
-}
-#endif
-
-
 void uccp420wlan_rx_frame(struct sk_buff *skb, void *context)
 {
 	struct mac80211_dev *dev = (struct mac80211_dev *)context;
diff --git a/drivers/net/wireless/uccp420wlan/src/tx.c b/drivers/net/wireless/uccp420wlan/src/tx.c
index 1d43578..465d87d 100644
--- a/drivers/net/wireless/uccp420wlan/src/tx.c
+++ b/drivers/net/wireless/uccp420wlan/src/tx.c
@@ -61,8 +61,7 @@
 	}
 }
 
-
-static inline int tx_queue_map(int queue)
+int tx_queue_map(int queue)
 {
 	unsigned int ac[4] = {WLAN_AC_VO, WLAN_AC_VI, WLAN_AC_BE, WLAN_AC_BK};
 
@@ -72,8 +71,7 @@
 	return WLAN_AC_VO;
 }
 
-
-static inline int tx_queue_unmap(int queue)
+int tx_queue_unmap(int queue)
 {
 	unsigned int ac[4] = {3, 2, 1, 0};
 
@@ -105,6 +103,9 @@
 	int tx_fixed_mcs_idx = 0;
 	int tx_fixed_rate = 0;
 	struct ieee80211_supported_band *band = NULL;
+	struct umac_vif *uvif = NULL;
+
+	uvif = (struct umac_vif *)(tx_info->control.vif->drv_priv);
 
 	/* Rate info will be retained, except the count*/
 	ieee80211_tx_info_clear_status(tx_info);
@@ -207,13 +208,18 @@
 		index++;
 	}
 
-	if ((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) &&
+	if (((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
+	     (uvif->chanctx &&
+	      (uvif->chanctx->index == dev->roc_off_chanctx_idx))) &&
 	    (atomic_dec_return(&dev->roc_params.roc_mgmt_tx_count) == 0)) {
-		if (dev->roc_params.roc_in_progress) {
-			/* Reuse the delayed workqueue with 1ms delay */
-			ieee80211_queue_delayed_work(dev->hw,
-						     &dev->roc_complete_work,
-						     msecs_to_jiffies(1));
+		DEBUG_LOG("%s-UMACTX: TXDONE Frame: %d\n",
+			  dev->name,
+			  atomic_read(&dev->roc_params.roc_mgmt_tx_count));
+		if (dev->roc_params.roc_in_progress &&
+		    dev->roc_params.roc_type == ROC_TYPE_OFFCHANNEL_TX) {
+			uccp420wlan_prog_roc(ROC_STOP, 0, 0, 0);
+			DEBUG_LOG("%s-UMACTX: all offchan pend frames clear\n",
+				  dev->name);
 		}
 	}
 
@@ -242,6 +248,7 @@
 
 		if (!test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) {
 			token_id = queue + (NUM_ACS * cnt);
+			tx->outstanding_tokens[queue]++;
 			break;
 		}
 	}
@@ -258,29 +265,40 @@
 			/* Do not set, we will queue to the same token */
 			if (!test_and_set_bit(curr_bit,
 					      &tx->buf_pool_bmp[pool_id])) {
+				tx->outstanding_tokens[queue]++;
 				break;
 			}
 		}
 	}
 
-	if (token_id != NUM_TX_DESCS) {
-		tx->outstanding_tokens[queue]++;
-#ifdef MULTI_CHAN_SUPPORT
-		tx->desc_chan_map[token_id] = curr_chanctx_idx;
-#endif
-	}
-
 	return token_id;
 }
 
-
-int get_curr_peer_opp(struct mac80211_dev *dev,
-#ifdef MULTI_CHAN_SUPPORT
-		      int curr_chanctx_idx,
-#endif
-		      int queue)
+void free_token(struct mac80211_dev *dev,
+		int token_id,
+		int queue)
 {
+	struct tx_config *tx = &dev->tx;
+	int bit = -1;
+	int pool_id = -1;
+
+	bit = (token_id % TX_DESC_BUCKET_BOUND);
+	pool_id = (token_id / TX_DESC_BUCKET_BOUND);
+
+	__clear_bit(bit, &tx->buf_pool_bmp[pool_id]);
+
+	tx->outstanding_tokens[queue]--;
+}
+
+
+struct curr_peer_info get_curr_peer_opp(struct mac80211_dev *dev,
+#ifdef MULTI_CHAN_SUPPORT
+					int curr_chanctx_idx,
+#endif
+					int ac)
+	{
 	unsigned int curr_peer_opp = 0;
+	unsigned int curr_vif_op_chan = UMAC_VIF_CHANCTX_TYPE_OPER;
 	unsigned int i = 0;
 	struct tx_config *tx = NULL;
 #ifdef MULTI_CHAN_SUPPORT
@@ -291,21 +309,28 @@
 	int vif_index = -1;
 #endif
 	unsigned int init_peer_opp = 0;
+	struct curr_peer_info peer_info;
+	unsigned int pend_q_len;
+	struct sk_buff_head *pend_q = NULL;
 
 	tx = &dev->tx;
 
 #ifdef MULTI_CHAN_SUPPORT
-	init_peer_opp = tx->curr_peer_opp[curr_chanctx_idx][queue];
+	init_peer_opp = tx->curr_peer_opp[curr_chanctx_idx][ac];
 #else
-	init_peer_opp = tx->curr_peer_opp[queue];
+	init_peer_opp = tx->curr_peer_opp[ac];
 #endif
-
+	/*TODO: Optimize this loop for BCN_Q
+	 */
 	for (i = 0; i < MAX_PEND_Q_PER_AC; i++) {
 		curr_peer_opp = (init_peer_opp + i) % MAX_PEND_Q_PER_AC;
 
 #ifdef MULTI_CHAN_SUPPORT
 		rcu_read_lock();
 
+		/* RoC Frame do not have a "sta" entry.
+		 * so we need not handle RoC stuff here
+		 */
 		if (curr_peer_opp < MAX_PEERS) {
 			sta = rcu_dereference(dev->peers[curr_peer_opp]);
 
@@ -316,16 +341,43 @@
 
 			usta = (struct umac_sta *)(sta->drv_priv);
 
-			if (!usta->chanctx) {
+			vif = rcu_dereference(dev->vifs[usta->vif_index]);
+
+			if (!vif) {
 				rcu_read_unlock();
 				continue;
 			}
 
-			if (usta->chanctx->index != curr_chanctx_idx) {
+
+			uvif = (struct umac_vif *)(vif->drv_priv);
+
+			if (!uvif->chanctx && !uvif->off_chanctx) {
 				rcu_read_unlock();
 				continue;
 			}
 
+			if ((uvif->chanctx &&
+			     (uvif->chanctx->index != curr_chanctx_idx)) ||
+			    !uvif->chanctx) {
+				if ((uvif->off_chanctx &&
+				     (uvif->off_chanctx->index !=
+				      curr_chanctx_idx)) ||
+				    !uvif->off_chanctx) {
+					rcu_read_unlock();
+					continue;
+				} else {
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OFF;
+				}
+			} else {
+				if (dev->roc_params.roc_in_progress &&
+				    !dev->roc_params.need_offchan)
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OFF;
+				else
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OPER;
+			}
 		} else {
 			vif_index = (curr_peer_opp - MAX_PEERS);
 
@@ -338,46 +390,177 @@
 
 			uvif = (struct umac_vif *)(vif->drv_priv);
 
-			if (!uvif->chanctx) {
+			if (!uvif->chanctx && !uvif->off_chanctx) {
 				rcu_read_unlock();
 				continue;
 			}
 
-			if (uvif->chanctx->index != curr_chanctx_idx) {
-				rcu_read_unlock();
-				continue;
+			/* For a beacon queue we will process the frames
+			 * irrespective of the current channel context.
+			 * The FW will take care of transmitting them in the
+			 * appropriate channel.
+			 */
+
+			if (ac != WLAN_AC_BCN &&
+			    ((uvif->chanctx &&
+			      (uvif->chanctx->index != curr_chanctx_idx)) ||
+			     !uvif->chanctx)) {
+				if ((uvif->off_chanctx &&
+				     (uvif->off_chanctx->index !=
+				      curr_chanctx_idx)) ||
+				    !uvif->off_chanctx) {
+					rcu_read_unlock();
+					continue;
+				} else {
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OFF;
+				}
+			} else {
+				if (dev->roc_params.roc_in_progress &&
+				    !dev->roc_params.need_offchan)
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OFF;
+				else
+					curr_vif_op_chan =
+						UMAC_VIF_CHANCTX_TYPE_OPER;
 			}
 		}
 
 		rcu_read_unlock();
 #endif
+		pend_q = &tx->pending_pkt[curr_vif_op_chan][curr_peer_opp][ac];
+		pend_q_len = skb_queue_len(pend_q);
 
-		if (skb_queue_len(&tx->pending_pkt[curr_peer_opp][queue])) {
+		if (pend_q_len) {
 #ifdef MULTI_CHAN_SUPPORT
-			tx->curr_peer_opp[curr_chanctx_idx][queue] =
+			tx->curr_peer_opp[curr_chanctx_idx][ac] =
 				(curr_peer_opp + 1) % MAX_PEND_Q_PER_AC;
 #else
-			tx->curr_peer_opp[queue] =
+			tx->curr_peer_opp[ac] =
 				(curr_peer_opp + 1) % MAX_PEND_Q_PER_AC;
 #endif
 			break;
 		}
 	}
 
-	if (i == MAX_PEND_Q_PER_AC)
-		return -1;
+	if (i == MAX_PEND_Q_PER_AC) {
+		peer_info.id = -1;
+		peer_info.op_chan_idx = -1;
+	} else {
+		peer_info.id = curr_peer_opp;
+		peer_info.op_chan_idx = curr_vif_op_chan;
+		DEBUG_LOG("%s-UMACTX: Queue: %d Peer: %d op_chan: %d ",
+			  dev->name,
+			  ac,
+			  curr_peer_opp,
+			  curr_vif_op_chan);
+		DEBUG_LOG("chanctx: %d got opportunity, pending: %d\n",
+			  curr_chanctx_idx,
+			  pend_q_len);
+	}
 
-	return curr_peer_opp;
+	return peer_info;
 }
 
 
-void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev,
-				   int queue,
 #ifdef MULTI_CHAN_SUPPORT
-				   int curr_chanctx_idx,
+void uccp420wlan_tx_proc_send_pend_frms_all(struct mac80211_dev *dev,
+					    int ch_id)
+{
+	int txq_len = 0;
+	int i = 0, cnt = 0;
+	int queue = 0;
+	unsigned long flags = 0;
+	int curr_bit = 0;
+	int pool_id = 0;
+	int ret = 0;
+	int start_ac, end_ac;
+	unsigned int pkts_pend = 0;
+	struct tx_config *tx = NULL;
+	struct sk_buff_head *txq = NULL;
+
+	tx = &dev->tx;
+
+	for (i = 0; i < NUM_TX_DESCS; i++) {
+		spin_lock_irqsave(&tx->lock, flags);
+
+		curr_bit = (i % TX_DESC_BUCKET_BOUND);
+		pool_id = (i / TX_DESC_BUCKET_BOUND);
+
+		if (test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) {
+			spin_unlock_irqrestore(&tx->lock, flags);
+			continue;
+		}
+
+		txq = &tx->pkt_info[ch_id][i].pkt;
+		txq_len = skb_queue_len(txq);
+
+		/* Not valid when txq len is 0 */
+		queue = tx->pkt_info[ch_id][i].queue;
+
+		if (!txq_len) {
+			/* Reserved token */
+			if (i < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
+				queue = (i % NUM_ACS);
+				start_ac = end_ac = queue;
+			} else {
+				/* Spare token:
+				 * Loop through all AC's
+				 */
+				start_ac = WLAN_AC_VO;
+				end_ac = WLAN_AC_BK;
+			}
+
+			for (cnt = start_ac; cnt >= end_ac; cnt--) {
+				pkts_pend = uccp420wlan_tx_proc_pend_frms(dev,
+									  cnt,
+									  ch_id,
+									  i);
+				if (pkts_pend) {
+					queue = cnt;
+					break;
+				}
+			}
+
+			if (pkts_pend == 0) {
+				__clear_bit(curr_bit,
+					    &tx->buf_pool_bmp[pool_id]);
+				spin_unlock_irqrestore(&tx->lock, flags);
+				continue;
+			}
+		}
+
+		tx->outstanding_tokens[queue]++;
+		spin_unlock_irqrestore(&tx->lock, flags);
+
+		ret = __uccp420wlan_tx_frame(dev,
+					     queue,
+					     i,
+					     ch_id,
+					     0,
+					     0); /* TODO: Currently sending 0
+						    since this param is not used
+						    as expected in the orig
+						    code for multiple frames etc
+						    Need to set this
+						    properly when the orig code
+						    logic is corrected
+						  */
+		if (ret < 0) {
+			pr_err("%s: Queueing of TX frame to FW failed\n",
+			       __func__);
+		}
+	}
+}
 #endif
-				   int peer_id,
-				   int token_id)
+
+
+int uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev,
+				  int ac,
+#ifdef MULTI_CHAN_SUPPORT
+				  int curr_chanctx_idx,
+#endif
+				  int token_id)
 {
 	struct tx_config *tx = &dev->tx;
 	unsigned long ampdu_len = 0;
@@ -394,8 +577,22 @@
 	unsigned int max_tx_cmds = dev->params->max_tx_cmds;
 	struct sk_buff_head *txq = NULL;
 	struct sk_buff_head *pend_pkt_q = NULL;
+	unsigned int total_pending_processed = 0;
+	int pend_pkt_q_len = 0;
+	struct curr_peer_info peer_info;
 
-	pend_pkt_q = &tx->pending_pkt[peer_id][queue];
+	peer_info = get_curr_peer_opp(dev,
+#ifdef MULTI_CHAN_SUPPORT
+				       curr_chanctx_idx,
+#endif
+				       ac);
+
+	/* No pending frames for any peer in that AC.
+	 */
+	if (peer_info.id == -1)
+		return 0;
+
+	pend_pkt_q = &tx->pending_pkt[peer_info.op_chan_idx][peer_info.id][ac];
 
 #ifdef MULTI_CHAN_SUPPORT
 	txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt;
@@ -405,6 +602,12 @@
 
 	skb_first = skb_peek(pend_pkt_q);
 
+	if (skb_first == NULL)
+		pr_err("%s:%d Null SKB: peer: %d\n",
+		       __func__,
+		       __LINE__,
+		       peer_info.id);
+
 	mac_hdr_first = (struct ieee80211_hdr *)skb_first->data;
 
 	tx_info_first = IEEE80211_SKB_CB(skb_first);
@@ -443,8 +646,18 @@
 			    IEEE80211_TX_MAX_RATES) != 0) ||
 		    (tx_info_first->flags != tx_info->flags) ||
 #endif
+		    /* RPU has a limitation, it expects A1-A2-A3 to be same
+		     * for all MPDU's within an AMPDU. This is a temporary
+		     * solution, remove it when RPU has fix for this.
+		     */
 		    (memcmp(mac_hdr->addr1,
 			    mac_hdr_first->addr1,
+			    ETH_ALEN) != 0) ||
+		    (memcmp(mac_hdr->addr2,
+			    mac_hdr_first->addr2,
+			    ETH_ALEN) != 0) ||
+		    (memcmp(mac_hdr->addr3,
+			    mac_hdr_first->addr3,
 			    ETH_ALEN) != 0))
 			break;
 
@@ -457,115 +670,120 @@
 	if (!skb_queue_len(txq))
 		skb_queue_tail(txq, skb_dequeue(pend_pkt_q));
 
-	DEBUG_LOG("%s-UMACTX:Max_pkt_thresh: send spare: %d with %d\n",
+	total_pending_processed = skb_queue_len(txq);
+
+	pend_pkt_q_len = skb_queue_len(pend_pkt_q);
+	if ((ac != WLAN_AC_BCN) &&
+	    (tx->queue_stopped_bmp & (1 << ac)) &&
+	    pend_pkt_q_len < (MAX_TX_QUEUE_LEN / 2)) {
+		ieee80211_wake_queue(dev->hw, tx_queue_unmap(ac));
+		tx->queue_stopped_bmp &= ~(1 << (ac));
+	}
+
+	DEBUG_LOG("%s-UMACTX: token_id: %d total_pending_packets_process: %d\n",
 		  dev->name,
 		  token_id,
 		  skb_queue_len(txq));
+
+	return total_pending_processed;
 }
 
 
-int uccp420wlan_tx_alloc_buff_req(struct mac80211_dev *dev,
-				  int queue,
+int uccp420wlan_tx_alloc_token(struct mac80211_dev *dev,
+			       int ac,
 #ifdef MULTI_CHAN_SUPPORT
-				  struct umac_vif *uvif,
-				  int curr_chanctx_idx,
+			       int off_chanctx_idx,
+			       int curr_chanctx_idx,
 #endif
-				  int peer_id,
-				  struct sk_buff *skb)
+			       int peer_id,
+			       struct sk_buff *skb)
 {
 	int token_id = NUM_TX_DESCS;
 	struct tx_config *tx = &dev->tx;
-	struct sk_buff_head *txq = NULL;
-	unsigned long flags = 0;
+	unsigned long flags;
 	struct sk_buff_head *pend_pkt_q = NULL;
-	int tx_peer_id = 0;
-	struct ieee80211_hdr *mac_hdr = NULL;
+	unsigned int pkts_pend = 0;
 
 	spin_lock_irqsave(&tx->lock, flags);
 
-	pend_pkt_q = &tx->pending_pkt[peer_id][queue];
+	pend_pkt_q = &tx->pending_pkt[off_chanctx_idx][peer_id][ac];
 
-	DEBUG_LOG("%s-UMACTX:Alloc buf Req q = %d,\n", dev->name, queue);
+	DEBUG_LOG("%s-UMACTX:Alloc buf Req q = %d off_chan: %d peerid: %d,\n",
+		  dev->name,
+		  ac,
+		  off_chanctx_idx,
+		  peer_id);
 
-#ifdef MULTI_CHAN_SUPPORT
-	if (uvif->chanctx->index == curr_chanctx_idx)
-		token_id = get_token(dev,
-				     curr_chanctx_idx,
-				     queue);
-#else
-	token_id = get_token(dev,
-			     queue);
-#endif
+	/* Queue the frame to the pending frames queue */
+	skb_queue_tail(pend_pkt_q, skb);
 
+	/* If the number of outstanding Tx tokens is greater than
+	 * NUM_TX_DESCS_PER_AC we try and encourage aggregation to the max size
+	 * supported (dev->params->max_tx_cmds)
+	 */
+	if (tx->outstanding_tokens[ac] >= NUM_TX_DESCS_PER_AC) {
+		if ((skb_queue_len(pend_pkt_q) < dev->params->max_tx_cmds) ||
+		   ac == WLAN_AC_BCN)
+			goto out;
+	}
 
-	/* If we got a reserved token, then queue frame to the Xmit queue */
-	if (token_id < NUM_TX_DESCS_PER_AC * NUM_ACS) {
-		DEBUG_LOG("%s-UMACTX:Reserved Token, Sending single\n",
-			  dev->name);
-#ifdef MULTI_CHAN_SUPPORT
-		txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt;
-#else
-		txq = &dev->tx.pkt_info[token_id].pkt;
-#endif
-		skb_queue_tail(txq, skb);
-	} else {
-		/* A frame for a beacon queue should never get a reserved
-		 * token
-		 */
-		mac_hdr = (struct ieee80211_hdr *)(skb->data);
-
-		if ((queue == WLAN_AC_BCN) &&
-		    (ieee80211_is_beacon(mac_hdr->frame_control))) {
-			if (net_ratelimit())
-				pr_warn("Did not get rsvd token for beacon\n");
-		}
-
-		/* Queue the frame to the pending frames queue */
-		skb_queue_tail(pend_pkt_q, skb);
-
-		if (queue != WLAN_AC_BCN) {
-			/* Take steps to stop the TX traffic if we have reached
-			 * the queueing limit
-			 */
-			if (skb_queue_len(pend_pkt_q) >= MAX_TX_QUEUE_LEN) {
-				ieee80211_stop_queue(dev->hw,
-						     skb->queue_mapping);
-				tx->queue_stopped_bmp |= (1 << queue);
-			}
-
-			/* If we got a spare token, try sending out pending
-			 * frames
-			 */
-			if (token_id < NUM_TX_DESCS) {
-				tx_peer_id = get_curr_peer_opp(dev,
-#ifdef MULTI_CHAN_SUPPORT
-							       curr_chanctx_idx,
-#endif
-							       queue);
-
-				uccp420wlan_tx_proc_pend_frms(dev,
-							      queue,
-#ifdef MULTI_CHAN_SUPPORT
-							      curr_chanctx_idx,
-#endif
-							      tx_peer_id,
-							      token_id);
-			}
+	/* Take steps to stop the TX traffic if we have reached
+	 * the queueing limit.
+	 * We dont this for the ROC queue to avoid the case where we are in the
+	 * OFF channel but there is lot of traffic for the operating channel on
+	 * the shared ROC queue (which is VO right now), since this would block
+	 * ROC traffic too.
+	 */
+	if (skb_queue_len(pend_pkt_q) >= MAX_TX_QUEUE_LEN) {
+		if ((!dev->roc_params.roc_in_progress) ||
+		    (dev->roc_params.roc_in_progress &&
+		     (ac != UMAC_ROC_AC))) {
+			ieee80211_stop_queue(dev->hw,
+					     skb->queue_mapping);
+			tx->queue_stopped_bmp |= (1 << ac);
 		}
 	}
 
-	DEBUG_LOG("%s-UMACTX:Alloc buf Result *id = %d q = %d peer_id = %d\n",
+	token_id = get_token(dev,
+#ifdef MULTI_CHAN_SUPPORT
+			     curr_chanctx_idx,
+#endif
+			     ac);
+
+	DEBUG_LOG("%s-UMACTX:Alloc buf Result *id= %d q = %d peerid: %d,\n",
 		  dev->name,
-		  token_id
-		  queue,
+		  token_id,
+		  ac,
 		  peer_id);
 
+	if (token_id == NUM_TX_DESCS)
+		goto out;
+
+	pkts_pend = uccp420wlan_tx_proc_pend_frms(dev,
+						  ac,
+#ifdef MULTI_CHAN_SUPPORT
+						  curr_chanctx_idx,
+#endif
+						  token_id);
+
+	/* We have just added a frame to pending_q but channel context is
+	 * mismatch.
+	 */
+
+	if (!pkts_pend) {
+		free_token(dev, token_id, ac);
+		token_id = NUM_TX_DESCS;
+	}
+
+out:
 	spin_unlock_irqrestore(&tx->lock, flags);
 
+	DEBUG_LOG("%s-UMACTX:Alloc buf Result *id= %d\n", dev->name, token_id);
 	/* If token is available, just return tokenid, list will be sent*/
 	return token_id;
 }
 
+
 int get_band_chanctx(struct mac80211_dev *dev, struct umac_vif *uvif)
 {
 	struct ieee80211_chanctx_conf *chanctx = NULL;
@@ -586,9 +804,10 @@
 	return band;
 }
 
+
 int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev,
 				 struct umac_event_tx_done *tx_done,
-				 unsigned char *queue,
+				 unsigned char *ac,
 #ifdef MULTI_CHAN_SUPPORT
 				 int curr_chanctx_idx,
 #endif
@@ -606,18 +825,15 @@
 	int vif_index = -1;
 	unsigned int pkt = 0;
 	int cnt = 0;
-	int bit = 0;
-	int pool_id = 0;
 	unsigned int desc_id = tx_done->descriptor_id;
-	unsigned int max_tx_cmds = dev->params->max_tx_cmds;
 	struct umac_vif *uvif = NULL;
 	struct ieee80211_vif *ivif = NULL;
 	unsigned long bcn_int = 0;
-	int pend_pkt_q_len = 0;
-	int peer_id = 0;
 #ifdef MULTI_CHAN_SUPPORT
 	int chanctx_idx = 0;
+	struct tx_pkt_info *pkt_info = NULL;
 #endif
+	int start_ac, end_ac;
 
 	skb_queue_head_init(&tx_done_list);
 
@@ -628,67 +844,17 @@
 
 	spin_lock_irqsave(&tx->lock, flags);
 
-	tx->outstanding_tokens[tx_done->queue]--;
-
 #ifdef MULTI_CHAN_SUPPORT
 	chanctx_idx = tx->desc_chan_map[desc_id];
-#endif
-
-	bit = (desc_id % TX_DESC_BUCKET_BOUND);
-	pool_id = (desc_id / TX_DESC_BUCKET_BOUND);
-
-	/* Reserved token */
-	if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
-		*queue = tx_done->queue;
-
-		peer_id = get_curr_peer_opp(dev,
-#ifdef MULTI_CHAN_SUPPORT
-					    curr_chanctx_idx,
-#endif
-					    *queue);
-
-		if (peer_id == -1) {
-			__clear_bit(bit, &tx->buf_pool_bmp[pool_id]);
-#ifdef MULTI_CHAN_SUPPORT
-			tx->desc_chan_map[desc_id] = -1;
-#endif
-		}
-	/* Spare token */
-	} else {
-		for (cnt = WLAN_AC_VO; cnt >= 0; cnt--) {
-			peer_id = get_curr_peer_opp(dev,
-#ifdef MULTI_CHAN_SUPPORT
-						    curr_chanctx_idx,
-#endif
-						    cnt);
-
-			if (peer_id != -1) {
-				*queue = cnt;
-				break;
-			}
-		}
-
-		/* If beacon queue has pending and no other AC
-		 *  has pending
-		 */
-		if (peer_id == -1) {
-			__clear_bit(bit, &tx->buf_pool_bmp[pool_id]);
-#ifdef MULTI_CHAN_SUPPORT
-			tx->desc_chan_map[desc_id] = -1;
-#endif
-		}
+	if (chanctx_idx == -1) {
+		spin_unlock_irqrestore(&tx->lock, flags);
+		pr_err("%s: Unexpected channel context\n", __func__);
+		goto out;
 	}
+	pkt_info = &dev->tx.pkt_info[chanctx_idx][desc_id];
+#endif
 
-	if (peer_id != -1)
-		pkts_pend = skb_queue_len(&tx->pending_pkt[peer_id][*queue]);
 
-	DEBUG_LOG("%s-UMACTX:%s pend_q = %d, sta_id = %d desc_id: %d pend:%d\n",
-		  dev->name,
-		  __func__,
-		  *queue,
-		  peer_id,
-		  desc_id,
-		  pkts_pend);
 
 	/* Defer Tx Done Processsing */
 #ifdef MULTI_CHAN_SUPPORT
@@ -705,48 +871,28 @@
 			  dev->name, skb_list);
 	}
 
-	if (pkts_pend > 0) {
-		/* For a beacon queue we will process the frames irrespective
-		 * of the current channel context. The FW will take care of
-		 * transmitting them in the appropriate channel. Hence pass the
-		 * interfaces channel context instead of the actual current
-		 * channel context.
+	/* Reserved token */
+	if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
+		start_ac = end_ac = tx_done->queue;
+	} else {
+		/* Spare token:
+		 * Loop through all AC's
 		 */
-		if (*queue == WLAN_AC_BCN) {
-			rcu_read_lock();
-
-			vif_index = (peer_id - MAX_PEERS);
-			ivif = rcu_dereference(dev->vifs[vif_index]);
-			uvif = (struct umac_vif *)(ivif->drv_priv);
-			curr_chanctx_idx = uvif->chanctx->index;
-			rcu_read_unlock();
-		}
-
-		uccp420wlan_tx_proc_pend_frms(dev,
-					      *queue,
+		start_ac = WLAN_AC_VO;
+		end_ac = WLAN_AC_BK;
+	}
+	for (cnt = start_ac; cnt >= end_ac; cnt--) {
+		pkts_pend = uccp420wlan_tx_proc_pend_frms(dev,
+					      cnt,
 #ifdef MULTI_CHAN_SUPPORT
 					      curr_chanctx_idx,
 #endif
-					      peer_id,
 					      desc_id);
 
-		tx->outstanding_tokens[*queue]++;
-
-		DEBUG_LOG("%s-UMACTX:Pending packets: %d, Total: %d\n",
-			  dev->name,
-			  pkts_pend,
-			  skb_queue_len(skb_list));
-	} else {
-		DEBUG_LOG("%s-UMACTX:No Pending Packets\n", dev->name);
-	}
-
-	pend_pkt_q_len = skb_queue_len(&tx->pending_pkt[peer_id][*queue]);
-
-	if ((*queue != WLAN_AC_BCN) &&
-	    (tx->queue_stopped_bmp & (1 << *queue)) &&
-	    pend_pkt_q_len < (MAX_TX_QUEUE_LEN / 2)) {
-		ieee80211_wake_queue(dev->hw, tx_queue_unmap(*queue));
-		tx->queue_stopped_bmp &= ~(1 << (*queue));
+		if (pkts_pend) {
+			*ac = cnt;
+			break;
+		}
 	}
 
 	/* Unmap here before release lock to avoid race */
@@ -879,35 +1025,81 @@
 		pkt++;
 	}
 out:
-	return min(pkts_pend, max_tx_cmds);
+	return pkts_pend;
 }
 
 
 #ifdef MULTI_CHAN_SUPPORT
-void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev,
-				      int curr_chanctx_idx,
-				      struct umac_event_tx_done *tx_done)
+void uccp420wlan_proc_ch_sw_event(struct umac_event_ch_switch *ch_sw_info,
+				  void *context)
+{
+	struct mac80211_dev *dev = NULL;
+	int chan = 0;
+	int curr_freq = 0;
+	int chan_id = 0;
+	struct ieee80211_chanctx_conf *curr_chanctx = NULL;
+	int i = 0;
+
+	if (!ch_sw_info || !context) {
+		pr_err("%s: Invalid Parameters:\n", __func__);
+		return;
+	}
+
+	dev = (struct mac80211_dev *)context;
+	chan = ch_sw_info->chan;
+
+	rcu_read_lock();
+
+	for (i = 0; i < MAX_CHANCTX; i++) {
+		curr_chanctx = rcu_dereference(dev->chanctx[i]);
+
+		if (curr_chanctx) {
+			curr_freq = curr_chanctx->def.chan->center_freq;
+
+			if (ieee80211_frequency_to_channel(curr_freq) == chan) {
+				chan_id = i;
+				break;
+			}
+		}
+	}
+
+	rcu_read_unlock();
+
+	if (i == MAX_CHANCTX) {
+		pr_err("%s: Invalid Channel Context: chan: %d\n",
+		       __func__,
+		       chan);
+		return;
+	}
+
+	/* Switch to the new channel context */
+	spin_lock(&dev->chanctx_lock);
+	dev->curr_chanctx_idx = chan_id;
+	spin_unlock(&dev->chanctx_lock);
+
+	/* We now try to xmit any frames whose xmission got cancelled due to a
+	 * previous channel switch
+	 */
+	uccp420wlan_tx_proc_send_pend_frms_all(dev, chan_id);
+}
+
+
+unsigned int uccp420wlan_proc_tx_dscrd_chsw(struct mac80211_dev *dev,
+					    int curr_chanctx_idx,
+					    struct umac_event_tx_done *tx_done)
 {
 	struct tx_config *tx = &dev->tx;
-	struct sk_buff_head *txq = NULL;
-	struct sk_buff_head tx_done_list;
+	struct sk_buff_head *txq = NULL, tx_done_list;
 	int chanctx_idx = -1;
 	int pkt = 0;
-#ifdef notyet
-	int i = 0;
-#endif
 	unsigned long flags;
 	int txq_len = 0;
 	struct sk_buff *skb = NULL;
 	struct sk_buff *skb_first = NULL;
 	struct sk_buff *tmp = NULL;
-	int curr_bit = 0;
-	int pool_id = 0;
 	int queue = 0;
-	int ret = 0;
+	int ret = 0, cnt = 0;
 	unsigned int desc_id = 0;
-	int peer_id = -1;
-	int ac = -1;
 	unsigned int *curr_retries = NULL;
 	unsigned int max_retries = 0;
 	struct ieee80211_tx_info tx_info_1st_mpdu;
@@ -915,6 +1107,8 @@
 	bool retries_exceeded = false;
 	unsigned int *rate = NULL;
 	unsigned int *retries = NULL;
+	int start_ac, end_ac;
+	unsigned int pkts_pend = 0;
 
 	skb_queue_head_init(&tx_done_list);
 
@@ -928,8 +1122,11 @@
 	 */
 	chanctx_idx = tx->desc_chan_map[desc_id];
 
-	if (chanctx_idx == -1) {
-		pr_err("%s: Unexpected channel context\n", __func__);
+	if ((chanctx_idx == -1) ||
+	    (chanctx_idx > (MAX_CHANCTX + MAX_OFF_CHANCTX))) {
+		pr_err("%s: Unexpected channel context: %d\n",
+		       __func__,
+		       chanctx_idx);
 		goto out;
 	}
 
@@ -937,7 +1134,10 @@
 	txq_len = skb_queue_len(txq);
 
 	if (!txq_len) {
-		pr_err("%s: TX_DONE received for empty queue\n", __func__);
+		pr_err("%s: TX_DONE received for empty queue: chan: %d desc_id: %d\n",
+		       __func__,
+		       chanctx_idx,
+		       desc_id);
 		goto out;
 	}
 
@@ -951,34 +1151,25 @@
 	pkt = 0;
 
 	skb_first = skb_peek(txq);
+
+	if (!skb_first) {
+		pr_err("%s: Empty txq: chan: %d desc_id: %d\n",
+		       __func__,
+		       chanctx_idx,
+		       desc_id);
+		goto out;
+	}
+
 	curr_retries = &tx->pkt_info[chanctx_idx][desc_id].curr_retries;
 	max_retries = tx->pkt_info[chanctx_idx][desc_id].max_retries;
 	retries = tx->pkt_info[chanctx_idx][desc_id].retries;
 	rate = tx->pkt_info[chanctx_idx][desc_id].rate;
 	tx->pkt_info[chanctx_idx][desc_id].adjusted_rates = true;
 
-	if ((tx_done->retries_num[0] + *curr_retries) > max_retries) {
+	if ((tx_done->retries_num[0] + *curr_retries) > max_retries)
 		retries_exceeded = true;
-	} else {
+	else
 		*curr_retries += tx_done->retries_num[0];
-#ifdef notyet
-		/* Adjust the counters here */
-		for (i = 0; i < 4; i++) {
-			if (tx_done->rate[0] != rate[i])
-				retries[i] = 0;
-			else
-				retries[i] -= tx_done->retries_num[0];
-
-			DEBUG_LOG("%s-UMACTX: %s: %d %s %d == %d retries\n",
-				  dev->name,
-				  __func__,
-				  __LINE__,
-				  "adjusted indices are",
-				  i,
-				  retries[i]);
-		}
-#endif
-	}
 
 	memcpy(&tx_info_1st_mpdu,
 	       (struct ieee80211_tx_info *)IEEE80211_SKB_CB(skb_first),
@@ -1026,79 +1217,69 @@
 		pkt++;
 	}
 
-	if (chanctx_idx != curr_chanctx_idx) {
-		/* First check if there is a packet in the txq of the current
-		 * chanctx that needs to be transmitted
+	/* First check if there is a packet in the txq of the current
+	 * chanctx that needs to be transmitted
+	 */
+	txq = &tx->pkt_info[curr_chanctx_idx][desc_id].pkt;
+	txq_len = skb_queue_len(txq);
+	queue = tx->pkt_info[curr_chanctx_idx][desc_id].queue;
+	pkts_pend = txq_len;
+
+	if (txq_len) {
+		spin_unlock_irqrestore(&tx->lock, flags);
+
+		/* TODO: Currently sending 0 since this param is not
+		 * used as expected in the orig code for multiple
+		 * frames etc Need to set this properly when the orig
+		 * code logic is corrected
 		 */
-		txq = &tx->pkt_info[curr_chanctx_idx][desc_id].pkt;
-		txq_len = skb_queue_len(txq);
-		queue = tx->pkt_info[curr_chanctx_idx][desc_id].queue;
-
-		if (txq_len) {
-			spin_unlock_irqrestore(&tx->lock, flags);
-
-			/* TODO: Currently sending 0 since this param is not
-			 * used as expected in the orig code for multiple
-			 * frames etc Need to set this properly when the orig
-			 * code logic is corrected
+		ret = __uccp420wlan_tx_frame(dev,
+					     queue,
+					     desc_id,
+					     curr_chanctx_idx,
+					     0,
+					     1);
+		if (ret < 0) {
+			/* TODO: Check if we need to clear the TX bitmap
+			 * and desc_chan_map here
 			 */
-			ret = __uccp420wlan_tx_frame(dev,
-						     queue,
-						     desc_id,
-						     curr_chanctx_idx,
-						     0,
-						     1);
-			if (ret < 0) {
-				/* TODO: Check if we need to clear the TX bitmap
-				 * and desc_chan_map here
-				 */
-				pr_err("%s: Queueing of TX frame to FW failed\n",
-				       __func__);
-			} else {
-				spin_lock_irqsave(&tx->lock, flags);
-				tx->desc_chan_map[desc_id] = curr_chanctx_idx;
-				spin_unlock_irqrestore(&tx->lock, flags);
-			}
+			pr_err("%s: Queueing of TX frame to FW failed\n",
+			       __func__);
+		}
 
-			goto tx_done;
+		/* This is needed to avoid freeing up the token
+		 */
+		pkts_pend = 1;
+
+		goto tx_done;
+	} else {
+		/* Check pending queue */
+		/* Reserved token */
+		if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
+			queue = (desc_id % NUM_ACS);
+			start_ac = end_ac = queue;
 		} else {
-			/* Check pending queue */
-			/* Reserved token */
-			if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) {
-				queue = (desc_id % NUM_ACS);
+			/* Spare token:
+			 * Loop through all AC's
+			 */
+			start_ac = WLAN_AC_VO;
+			end_ac = WLAN_AC_BK;
+		}
 
-				peer_id = get_curr_peer_opp(dev,
-							    curr_chanctx_idx,
-							    queue);
-
-				if (peer_id == -1)
-					goto done;
-
-			/* Spare token */
-			} else {
-				for (ac = WLAN_AC_VO; ac >= 0; ac--) {
-					peer_id = get_curr_peer_opp(dev,
-							   curr_chanctx_idx,
-							   ac);
-
-					if (peer_id != -1) {
-						queue = ac;
-						break;
-					}
-				}
-
-				if (ac < 0)
-					goto done;
-			}
-
-			uccp420wlan_tx_proc_pend_frms(dev,
-						      queue,
+		for (cnt = start_ac; cnt >= end_ac; cnt--) {
+			pkts_pend = uccp420wlan_tx_proc_pend_frms(dev,
+						      cnt,
 						      curr_chanctx_idx,
-						      peer_id,
 						      desc_id);
+			if (pkts_pend) {
+				queue = cnt;
+				break;
+			}
+		}
 
-			spin_unlock_irqrestore(&tx->lock, flags);
+		spin_unlock_irqrestore(&tx->lock, flags);
 
+		if (pkts_pend > 0) {
 			/* TODO: Currently sending 0 since this param is not
 			 * used as expected in the orig code for multiple
 			 * frames etc. Need to set this properly when the orig
@@ -1112,32 +1293,13 @@
 						     0);
 
 			if (ret < 0) {
-				/* SDK: Check if we need to clear the TX bitmap
-				 * and desc_chan_map here
-				 */
 				pr_err("%s: Queueing of TX frame to FW failed\n",
 				       __func__);
-			} else {
-				spin_lock_irqsave(&tx->lock, flags);
-				tx->desc_chan_map[desc_id] = curr_chanctx_idx;
-				spin_unlock_irqrestore(&tx->lock, flags);
 			}
-
-			goto tx_done;
 		}
+		goto tx_done;
 	}
 
-done:
-	curr_bit = (desc_id % TX_DESC_BUCKET_BOUND);
-	pool_id = (desc_id / TX_DESC_BUCKET_BOUND);
-
-	/* Mark the token as available */
-	__clear_bit(curr_bit, &tx->buf_pool_bmp[pool_id]);
-
-	tx->desc_chan_map[desc_id] = -1;
-
-	tx->outstanding_tokens[tx_done->queue]--;
-
 	if (txq_len == 1)
 		dev->stats->tx_cmd_send_count_single--;
 	else
@@ -1146,6 +1308,8 @@
 out:
 	spin_unlock_irqrestore(&tx->lock, flags);
 
+	return pkts_pend;
+
 tx_done:
 	skb_queue_walk_safe(&tx_done_list, skb, tmp) {
 			tx_status(skb,
@@ -1154,6 +1318,8 @@
 				  dev,
 				  tx_info_1st_mpdu);
 	}
+
+	return pkts_pend;
 }
 #endif
 
@@ -1187,6 +1353,7 @@
 {
 	int i = 0;
 	int j = 0;
+	int k = 0;
 	struct tx_config *tx = &dev->tx;
 
 	memset(&tx->buf_pool_bmp,
@@ -1197,8 +1364,10 @@
 	tx->next_spare_token_ac = WLAN_AC_BE;
 
 	for (i = 0; i < NUM_ACS; i++) {
-		for (j = 0; j < MAX_PEND_Q_PER_AC; j++)
-			skb_queue_head_init(&tx->pending_pkt[j][i]);
+		for (j = 0; j < MAX_PEND_Q_PER_AC; j++) {
+			for (k = 0; k < MAX_UMAC_VIF_CHANCTX_TYPES; k++)
+				skb_queue_head_init(&tx->pending_pkt[k][j][i]);
+		}
 
 		tx->outstanding_tokens[i] = 0;
 	}
@@ -1207,7 +1376,7 @@
 #ifdef MULTI_CHAN_SUPPORT
 		tx->desc_chan_map[i] = -1;
 
-		for (j = 0; j < MAX_CHANCTX; j++)
+		for (j = 0; j < MAX_CHANCTX + MAX_OFF_CHANCTX ; j++)
 			skb_queue_head_init(&tx->pkt_info[j][i].pkt);
 #else
 		skb_queue_head_init(&tx->pkt_info[i].pkt);
@@ -1228,10 +1397,12 @@
 	tx->persec_timer.function = print_persec_stats;
 	mod_timer(&tx->persec_timer, jiffies + msecs_to_jiffies(1000));
 #endif
+	dev->curr_chanctx_idx = -1;
 	spin_lock_init(&tx->lock);
 	ieee80211_wake_queues(dev->hw);
 
-	DEBUG_LOG("%s-UMACTX:Initialization successful\n", dev->name);
+	DEBUG_LOG("%s-UMACTX: initialization successful\n",
+		  UMACTX_TO_MACDEV(tx)->name);
 }
 
 
@@ -1239,9 +1410,12 @@
 {
 	int i = 0;
 	int j = 0;
-	unsigned long flags = 0;
+	int k = 0;
+	unsigned long flags;
 	struct tx_config *tx = &dev->tx;
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
+	unsigned int qlen = 0;
+	struct sk_buff_head *pend_q = NULL;
 
 	ieee80211_stop_queues(dev->hw);
 
@@ -1251,10 +1425,17 @@
 
 	for (i = 0; i < NUM_TX_DESCS; i++) {
 #ifdef MULTI_CHAN_SUPPORT
-		for (j = 0; j < MAX_CHANCTX; j++)
-			while ((skb = skb_dequeue(&tx->pkt_info[j][i].pkt)) !=
-			       NULL)
-				dev_kfree_skb_any(skb);
+		for (j = 0; j < MAX_CHANCTX + MAX_OFF_CHANCTX; j++) {
+			qlen = skb_queue_len(&tx->pkt_info[j][i].pkt);
+
+			if (qlen) {
+				while ((skb =
+					skb_dequeue(&tx->pkt_info[j][i].pkt)) !=
+				       NULL) {
+					dev_kfree_skb_any(skb);
+				}
+			}
+		}
 #else
 		while ((skb = skb_dequeue(&tx->pkt_info[i].pkt)) != NULL)
 			dev_kfree_skb_any(skb);
@@ -1263,16 +1444,19 @@
 
 	for (i = 0; i < NUM_ACS; i++) {
 		for (j = 0; j < MAX_PEND_Q_PER_AC; j++) {
-			while ((skb =
-				skb_dequeue(&tx->pending_pkt[j][i])) !=
-			       NULL)
-				dev_kfree_skb_any(skb);
+			for (k = 0; k < MAX_UMAC_VIF_CHANCTX_TYPES; k++) {
+				pend_q = &tx->pending_pkt[k][j][i];
+
+				while ((skb = skb_dequeue(pend_q)) != NULL)
+					dev_kfree_skb_any(skb);
+			}
 		}
 	}
 
 	spin_unlock_irqrestore(&tx->lock, flags);
 
-	DEBUG_LOG("%s-UMACTX:Deinitialization successful\n", dev->name);
+	DEBUG_LOG("%s-UMACTX: deinitialization successful\n",
+		  UMACTX_TO_MACDEV(tx)->name);
 }
 
 
@@ -1304,6 +1488,7 @@
 
 		tx_done.descriptor_id = token_id;
 		tx_done.queue = queue;
+		dev->tx.desc_chan_map[token_id] = curr_chanctx_idx;
 
 #ifdef MULTI_CHAN_SUPPORT
 		txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt;
@@ -1344,6 +1529,9 @@
 	struct umac_vif *uvif = NULL;
 	struct umac_sta *usta = NULL;
 	int peer_id = -1;
+#ifdef MULTI_CHAN_SUPPORT
+	int off_chanctx_idx;
+#endif
 
 	uvif = (struct umac_vif *)(tx_info->control.vif->drv_priv);
 
@@ -1357,21 +1545,27 @@
 	if (bcast == false) {
 		queue = tx_queue_map(skb->queue_mapping);
 		more_frames = 0;
+		dev->stats->tx_cmds_from_stack++;
 	} else {
 		queue = WLAN_AC_BCN;
 		/* Hack: skb->priority is used to indicate more frames */
 		more_frames = skb->priority;
 	}
 
-	dev->stats->tx_cmds_from_stack++;
 
 	if (dev->params->production_test == 1)
 		tx_info->flags |= IEEE80211_TX_CTL_AMPDU;
 
-	if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
-		/* These are high priority frames, send them in VO */
-		queue = WLAN_AC_VO;
+	if ((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
+	    (uvif->chanctx &&
+	    uvif->chanctx->index == dev->roc_off_chanctx_idx))  {
 		atomic_inc(&dev->roc_params.roc_mgmt_tx_count);
+		off_chanctx_idx = UMAC_VIF_CHANCTX_TYPE_OFF;
+		DEBUG_LOG("%s-UMACTX: Sending OFFCHAN Frame: %d\n",
+			  dev->name,
+			  atomic_read(&dev->roc_params.roc_mgmt_tx_count));
+	} else {
+		off_chanctx_idx = UMAC_VIF_CHANCTX_TYPE_OPER;
 	}
 
 	mac_hdr = (struct ieee80211_hdr *)(skb->data);
@@ -1385,10 +1579,10 @@
 		  skb->queue_mapping,
 		  ieee80211_is_beacon(mac_hdr->frame_control));
 
-	token_id = uccp420wlan_tx_alloc_buff_req(dev,
+	token_id = uccp420wlan_tx_alloc_token(dev,
 						 queue,
 #ifdef MULTI_CHAN_SUPPORT
-						 uvif,
+						 off_chanctx_idx,
 						 curr_chanctx_idx,
 #endif
 						 peer_id,
@@ -1465,19 +1659,23 @@
 	qlen = skb_queue_len(&dev->tx.pkt_info[token_id].pkt);
 #endif
 
-	DEBUG_LOG("%s-UMACTX:TX Done Rx for desc_id: %d qlen: %d\n",
+	DEBUG_LOG("%s-UMACTX:TX Done Rx for desc_id: %d Q: %d qlen: %d ",
 		  dev->name,
 		  tx_done->descriptor_id,
-		  qlen);
+		  tx_done->queue, qlen);
+	DEBUG_LOG("status: %d chactx: %d out_tok: %d\n",
+		  tx_done->frm_status[0],
+		  curr_chanctx_idx,
+		  dev->tx.outstanding_tokens[tx_done->queue]);
 
 	update_aux_adc_voltage(dev, tx_done->pdout_voltage);
 
 #ifdef MULTI_CHAN_SUPPORT
 	if (tx_done->frm_status[0] == TX_DONE_STAT_DISCARD_CHSW) {
-		uccp420wlan_proc_tx_discard_chsw(dev,
-						 curr_chanctx_idx,
-						 tx_done);
-		return;
+		pkts_pending = uccp420wlan_proc_tx_dscrd_chsw(dev,
+							      curr_chanctx_idx,
+							      tx_done);
+		goto out;
 	}
 #endif
 	pkts_pending = uccp420wlan_tx_free_buff_req(dev,
@@ -1490,12 +1688,6 @@
 
 	if (pkts_pending) {
 		/*TODO..Do we need to check each skb for more_frames??*/
-#if 0
-		if ((queue == WLAN_AC_BCN) && (skb->priority == 1))
-			more_frames = 1;
-		else
-			more_frames = 0;
-#endif
 		more_frames = 0;
 
 		DEBUG_LOG("%s-UMACTX:%s:%d Transfer Pending Frames:\n",
@@ -1515,6 +1707,13 @@
 		DEBUG_LOG("%s-UMACTX:No Pending Packets\n", dev->name);
 	}
 
+out:
+	if (!pkts_pending) {
+		/* Mark the token as available */
+		free_token(dev, token_id, tx_done->queue);
+		dev->tx.desc_chan_map[token_id] = -1;
+	}
+
 	for (vif_index = 0; vif_index < MAX_VIFS; vif_index++) {
 		if (vif_index_bitmap & (1 << vif_index)) {
 			memset(&noa_event, 0, sizeof(noa_event));
@@ -1526,3 +1725,191 @@
 		}
 	}
 }
+
+
+static int uccp420_flush_vif_all_pend_q(struct mac80211_dev *dev,
+					struct umac_vif *uvif,
+					unsigned int hw_queue_map,
+					enum UMAC_VIF_CHANCTX_TYPE chanctx_type)
+{
+	unsigned int pending = 0;
+	int count = 0;
+	int peer_id = -1;
+	unsigned int queue = 0;
+	int pend_q = 0;
+	unsigned long flags;
+	struct sk_buff_head *pend_pkt_q = NULL;
+	struct tx_config *tx = NULL;
+	struct ieee80211_sta *sta = NULL;
+	struct umac_sta *usta = NULL;
+
+	tx = &dev->tx;
+
+	if (!uvif->chanctx) {
+		DEBUG_LOG("%s-UMACTX: Chanctx NULL, returning\n", dev->name);
+		return -1;
+	}
+
+	for (queue = 0; queue < NUM_ACS; queue++) {
+		if (!(BIT(queue) & hw_queue_map))
+			continue;
+
+		for (pend_q = 0; pend_q < MAX_PEND_Q_PER_AC; pend_q++) {
+			if (pend_q < MAX_PEERS) {
+				rcu_read_lock();
+				sta = rcu_dereference(dev->peers[pend_q]);
+
+				if (!sta) {
+					rcu_read_unlock();
+					continue;
+				}
+
+				usta = (struct umac_sta *)(sta->drv_priv);
+
+				if (usta->vif_index == uvif->vif_index)
+					peer_id = pend_q;
+				else {
+					rcu_read_unlock();
+					continue;
+				}
+
+				rcu_read_unlock();
+			} else if (pend_q == uvif->vif_index)
+				peer_id = uvif->vif_index;
+			else
+				continue;
+
+			while (1) {
+				spin_lock_irqsave(&tx->lock, flags);
+
+				pend_pkt_q =
+					&tx->pending_pkt[chanctx_type]
+							[peer_id]
+							[queue];
+
+				/* Assuming all packets for the peer have same
+				 * channel context
+				 */
+				pending = skb_queue_len(pend_pkt_q);
+
+				spin_unlock_irqrestore(&tx->lock, flags);
+
+				if (!pending)
+					break;
+
+				if (count >= QUEUE_FLUSH_TIMEOUT_TICKS)
+					break;
+
+				current->state = TASK_INTERRUPTIBLE;
+
+				if (0 == schedule_timeout(1))
+					count++;
+
+			}
+
+			if (pending) {
+				pr_err("%s-UMACTX: Failed for VIF: %d and Queue: %d, pending: %d\n",
+				       dev->name,
+				       uvif->vif_index,
+				       queue,
+				       pending);
+
+				return -1;
+			}
+		}
+	}
+
+	DEBUG_LOG("%s-UMACTX: Success for VIF: %d and Queue: %d\n",
+			dev->name,
+			uvif->vif_index,
+			queue);
+	return 0;
+}
+
+
+static int uccp420_flush_vif_tx_queues(struct mac80211_dev *dev,
+				       struct umac_vif *uvif,
+				       int chanctx_idx,
+				       unsigned int hw_queue_map)
+{
+	unsigned int tokens = 0;
+	unsigned int i = 0;
+	unsigned long buf_pool_bmp = 0;
+	unsigned long flags;
+	struct tx_pkt_info *pkt_info = NULL;
+	struct tx_config *tx = NULL;
+	int count = 0;
+
+	tx = &dev->tx;
+
+	spin_lock_irqsave(&tx->lock, flags);
+
+	for (i = 0; i < NUM_TX_DESCS; i++) {
+		pkt_info = &tx->pkt_info[chanctx_idx][i];
+
+		if ((pkt_info->vif_index == uvif->vif_index) &&
+		    (BIT(pkt_info->queue) & hw_queue_map))
+			tokens |= BIT(i);
+	}
+
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (!tokens)
+		return 0;
+
+	while (1) {
+		spin_lock_irqsave(&tx->lock, flags);
+		buf_pool_bmp = tx->buf_pool_bmp[0];
+		spin_unlock_irqrestore(&tx->lock, flags);
+
+		if (!(buf_pool_bmp & tokens))
+			break;
+
+		if (count >= QUEUE_FLUSH_TIMEOUT_TICKS)
+			break;
+
+		current->state = TASK_INTERRUPTIBLE;
+
+		if (0 == schedule_timeout(1))
+			count++;
+	}
+
+	if (buf_pool_bmp & tokens) {
+		pr_err("%s-UMACTX: Failed for VIF: %d, buf_pool_bmp : 0x%lx\n",
+		       dev->name,
+		       uvif->vif_index,
+		       buf_pool_bmp);
+
+		return -1;
+	}
+
+	DEBUG_LOG("%s-UMACTX: Success for VIF: %d, buf_pool_bmp : 0x%lx\n",
+			dev->name,
+			uvif->vif_index,
+			buf_pool_bmp);
+	return 0;
+}
+
+
+int uccp420_flush_vif_queues(struct mac80211_dev *dev,
+			     struct umac_vif *uvif,
+			     int chanctx_idx,
+			     unsigned int hw_queue_map,
+			     enum UMAC_VIF_CHANCTX_TYPE vif_chanctx_type)
+{
+	int result  = -1;
+
+	result = uccp420_flush_vif_all_pend_q(dev,
+					      uvif,
+					      hw_queue_map,
+					      vif_chanctx_type);
+
+	if (result == 0) {
+		result = uccp420_flush_vif_tx_queues(dev,
+						     uvif,
+						     chanctx_idx,
+						     hw_queue_map);
+	}
+
+	return result;
+}
diff --git a/drivers/net/wireless/uccp420wlan/src/umac_if.c b/drivers/net/wireless/uccp420wlan/src/umac_if.c
index f37aa30..74bbffd 100644
--- a/drivers/net/wireless/uccp420wlan/src/umac_if.c
+++ b/drivers/net/wireless/uccp420wlan/src/umac_if.c
@@ -581,7 +581,8 @@
 		reset.lmac_mode = lmac_mode;
 		reset.antenna_sel = dev->params->antenna_sel;
 
-		if (dev->params->production_test == 0) {
+		if (dev->params->production_test == 0 &&
+			dev->params->bypass_vpd == 0) {
 			memcpy(reset.rf_params, dev->params->rf_params_vpd,
 			       RF_PARAMS_SIZE);
 		} else {
@@ -839,15 +840,17 @@
 
 int uccp420wlan_prog_roc(unsigned int roc_ctrl,
 			 unsigned int roc_channel,
-			 unsigned int roc_duration)
+			 unsigned int roc_duration,
+			 unsigned int roc_type)
 {
 	struct cmd_roc cmd_roc;
 
 	memset(&cmd_roc, 0, sizeof(struct cmd_roc));
 
-	cmd_roc.roc_ctrl	= roc_ctrl;
+	cmd_roc.roc_ctrl = roc_ctrl;
 	cmd_roc.roc_channel	= roc_channel;
-	cmd_roc.roc_duration	= roc_duration;
+	cmd_roc.roc_duration = roc_duration;
+	cmd_roc.roc_type = roc_type;
 
 	return uccp420wlan_send_cmd((unsigned char *) &cmd_roc,
 			sizeof(struct cmd_roc), UMAC_CMD_ROC_CTRL);
@@ -1302,6 +1305,8 @@
 	dev->cur_chan.freq_band = freq_band;
 	dev->chan_prog_done = 0;
 
+	rcu_read_unlock();
+
 	return uccp420wlan_send_cmd((unsigned char *) &channel,
 				    sizeof(struct cmd_channel),
 				    UMAC_CMD_CHANNEL);
@@ -1404,6 +1409,7 @@
 	unsigned long irq_flags, tx_irq_flags;
 #ifdef MULTI_CHAN_SUPPORT
 	struct tx_pkt_info *pkt_info = NULL;
+	struct tx_config *tx;
 #endif
 
 	memset(&tx_cmd, 0, sizeof(struct cmd_tx_ctrl));
@@ -1419,6 +1425,7 @@
 
 	dev = p->context;
 	spin_lock_irqsave(&dev->tx.lock, tx_irq_flags);
+	tx = &dev->tx;
 #ifdef MULTI_CHAN_SUPPORT
 	txq = &dev->tx.pkt_info[curr_chanctx_idx][descriptor_id].pkt;
 	pkt_info = &dev->tx.pkt_info[curr_chanctx_idx][descriptor_id];
@@ -1461,6 +1468,9 @@
 		hdrlen += tx_info_first->control.hw_key->iv_len;
 	}
 
+	if (tx_info_first->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+		tx_cmd.tx_flags |= (1 << UMAC_TX_FLAG_OFFCHAN_FRM);
+
 	/* For injected frames (wlantest) hw_key is not set,as PMF uses
 	 * CCMP always so hardcode this to CCMP IV LEN 8.
 	 * For Auth3: It is completely handled in SW (mac80211).
@@ -1493,6 +1503,14 @@
 	tx_cmd.pkt_gram_payload_len = hdrlen;
 	tx_cmd.aggregate_mpdu = AMPDU_AGGR_DISABLED;
 
+#ifdef MULTI_CHAN_SUPPORT
+	dev->tx.pkt_info[curr_chanctx_idx][descriptor_id].vif_index = vif_index;
+	dev->tx.pkt_info[curr_chanctx_idx][descriptor_id].queue = queue;
+#else
+	dev->tx.pkt_info[descriptor_id].vif_index = vif_index;
+	dev->tx.pkt_info[descriptor_id].queue = queue;
+#endif
+
 	uvif = (struct umac_vif *) (tx_info_first->control.vif->drv_priv);
 
 	nbuf = alloc_skb(sizeof(struct cmd_tx_ctrl) +
@@ -1541,6 +1559,10 @@
 		  tx_cmd.rate_retries[2],
 		  tx_cmd.rate_retries[3]);
 
+#ifdef MULTI_CHAN_SUPPORT
+	tx->desc_chan_map[descriptor_id] = curr_chanctx_idx;
+#endif
+
 	skb_queue_walk_safe(txq, skb, tmp) {
 		if (!skb || (pkt > tx_cmd.num_frames_per_desc))
 			break;
@@ -1566,11 +1588,8 @@
 #ifdef MULTI_CHAN_SUPPORT
 		dev->tx.pkt_info[curr_chanctx_idx][descriptor_id].hdr_len =
 			hdrlen;
-		dev->tx.pkt_info[curr_chanctx_idx][descriptor_id].queue =
-			queue;
 #else
 		dev->tx.pkt_info[descriptor_id].hdr_len = hdrlen;
-		dev->tx.pkt_info[descriptor_id].queue = queue;
 #endif
 
 		/* Complete packet length */
@@ -2018,6 +2037,19 @@
 				    UMAC_CMD_AUX_ADC_CHAIN_SEL);
 }
 
+int uccp420wlan_cont_tx(int val)
+{
+	struct cmd_cont_tx status;
+
+	memset(&status, 0, sizeof(struct cmd_cont_tx));
+	status.op = val;
+
+	return uccp420wlan_send_cmd((unsigned char *)&status,
+				    sizeof(struct cmd_cont_tx),
+				    UMAC_CMD_CONT_TX);
+}
+
+
 
 int uccp420wlan_prog_mib_stats(void)
 {
@@ -2280,13 +2312,37 @@
 		uccp420wlan_ch_prog_complete(event,
 			(struct umac_event_ch_prog_complete *)buff, p->context);
 	} else if (event == UMAC_EVENT_RF_CALIB_DATA) {
-		struct umac_event_rf_calib_data  *rf_data = (void *) buff;
+		struct umac_event_rf_calib_data  *rf_data = (void *)buff;
 
 		uccp420wlan_rf_calib_data(rf_data, p->context);
+	} else if (event == UMAC_EVENT_ROC_STATUS) {
+		struct umac_event_roc_status *roc_status = (void *)buff;
+		struct delayed_work *work = NULL;
+
+		DEBUG_LOG("%s-UMACIF: ROC status is %d\n",
+			  dev->name,
+			  roc_status->roc_status);
+
+		switch (roc_status->roc_status) {
+		case UMAC_ROC_STAT_STARTED:
+			if (dev->roc_params.roc_in_progress == 0) {
+				dev->roc_params.roc_in_progress = 1;
+				ieee80211_ready_on_channel(dev->hw);
+				DEBUG_LOG("%s-UMACIF: ROC READY..\n",
+					  dev->name);
+			}
+			break;
+		case UMAC_ROC_STAT_DONE:
+		case UMAC_ROC_STAT_STOPPED:
+			if (dev->roc_params.roc_in_progress == 1) {
+				work = &dev->roc_complete_work;
+				ieee80211_queue_delayed_work(dev->hw,
+							     work,
+							     0);
+			}
+			break;
+		}
 #ifdef MULTI_CHAN_SUPPORT
-	/* SDK: Need to see if this will work in tasklet context (due to
-	 * scheduling latencies)
-	 */
 	} else if (event == UMAC_EVENT_CHAN_SWITCH) {
 		uccp420wlan_proc_ch_sw_event((void *)buff,
 					     p->context);
diff --git a/drivers/soc/img/connectivity/img-hostport.c b/drivers/soc/img/connectivity/img-hostport.c
index ee2b8ba..0c8c496 100644
--- a/drivers/soc/img/connectivity/img-hostport.c
+++ b/drivers/soc/img/connectivity/img-hostport.c
@@ -179,7 +179,7 @@
 static void notify_common(u16 user_data, int user_id, gen_handler poke_ready,
 							void *poke_ready_arg)
 {
-	dbgn("snd -- %d:%d:%02X", user_id, user_id, user_data);
+	trace_printk("img-hostport: snd -- %d:%d:%02X\n", user_id, user_id, user_data);
 	if (poke_ready)
 		poke_ready(poke_ready_arg);
 	iowrite32(0x87 << 24 | user_data << 8 | id_to_field(user_id),
@@ -201,27 +201,28 @@
 	/* TODO: need to change that to support platforms other that 32 bit */
 	first_bit = (reg_value & (1 << 31)) >> 31;
 	if (0 == first_bit) {
-		err("unexpected spurious interrupt detected!\n");
+		trace_printk("img-hostport: unexpected spurious interrupt detected (0x%08X)!\n",
+			reg_value);
 		goto exit;
 	}
 
 	callee_id = CALLEE(reg_value);
 	caller_id = CALLER(reg_value);
 	user_message = USERMSG(reg_value);
-	dbgn("rcv -- %d:%d:%02X", callee_id, caller_id, user_message);
+	trace_printk("img-hostport: rcv -%c %d:%d:%02X\n", first_bit ? '-' : '*', callee_id, caller_id, user_message);
 
 	/*
 	 * callee_id is tainted, therefore must be checked.
 	 */
 	if (callee_id > MAX_ENDPOINT_ID) {
-		errn("endpoint with id = %u doesn't exist", callee_id);
+		trace_printk("img-hostport: endpoint with id = %u doesn't exist\n", callee_id);
 		goto deassert;
 	}
 
 	handler = module->endpoints.f[callee_id];
 	handler_in_use = module->endpoints.in_use + callee_id;
 	if (NULL == handler) {
-		errn("endpoint with id = %u not registered", callee_id);
+		trace_printk("img-hostport: endpoint with id = %u not registered\n", callee_id);
 		goto deassert;
 	}
 	spin_lock_irqsave(handler_in_use, flags);
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index c311958..b16ba2c 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -437,6 +437,9 @@
 	u32 val;
 
 	val = spfi_readl(spfi, SPFI_PORT_STATE);
+	val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK <<
+		 SPFI_PORT_STATE_DEV_SEL_SHIFT);
+	val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
 	if (msg->spi->mode & SPI_CPHA)
 		val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
 	else
diff --git a/include/dt-bindings/clock/pistachio-clk.h b/include/dt-bindings/clock/pistachio-clk.h
index dfda0c3..bfb915d 100644
--- a/include/dt-bindings/clock/pistachio-clk.h
+++ b/include/dt-bindings/clock/pistachio-clk.h
@@ -21,6 +21,7 @@
 /* Fixed-factor clocks */
 #define CLK_WIFI_DIV4			16
 #define CLK_WIFI_DIV8			17
+#define CLK_SDHOST_DIV4			18
 
 /* Gate clocks */
 #define CLK_MIPS			32
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index e540952..6f01653 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -178,9 +178,9 @@
 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	int (*read_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-			 u8 *buf, size_t len);
+			 u8 *buf, size_t len, size_t *retlen);
 	int (*write_xfer)(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
-			  u8 *buf, size_t len);
+			  u8 *buf, size_t len, size_t *retlen);
 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
 	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
 			int write_enable);
diff --git a/include/linux/spi/cc2520.h b/include/linux/spi/cc2520.h
index 14137e3..a591179 100644
--- a/include/linux/spi/cc2520.h
+++ b/include/linux/spi/cc2520.h
@@ -22,6 +22,7 @@
 	int reset;
 	int vreg;
 	unsigned int extclockfreq;
+	bool registerclk;
 	bool amplified;
 };
 
diff --git a/sound/soc/img/pistachio.c b/sound/soc/img/pistachio.c
index 1a8a6d7..e4b6546 100644
--- a/sound/soc/img/pistachio.c
+++ b/sound/soc/img/pistachio.c
@@ -30,10 +30,10 @@
 
 #include "pistachio-event-timer.h"
 
-#define	PLL_RATE_8000_16000_32000_48000_96000_192000	147456000
-#define	PLL_RATE_11025_22050_44100_64000_88200_176400	135475200
-#define	PISTACHIO_MAX_DIV				256
-#define	PISTACHIO_MIN_MCLK_FREQ				(135475200 / 256)
+#define	PISTACHIO_PLL_RATE_A		147456000
+#define	PISTACHIO_PLL_RATE_B		135475200
+#define	PISTACHIO_MAX_DIV		256
+#define	PISTACHIO_MIN_MCLK_FREQ		(135475200 / 256)
 
 #define	PISTACHIO_CLOCK_MASTER_EXT	-1
 #define	PISTACHIO_CLOCK_MASTER_LOOPBACK	-2
@@ -398,16 +398,16 @@
 	case 16000:
 	case 32000:
 	case 48000:
+	case 64000:
 	case 96000:
 	case 192000:
-		return PLL_RATE_8000_16000_32000_48000_96000_192000;
+		return PISTACHIO_PLL_RATE_A;
 	case 11025:
 	case 22050:
 	case 44100:
-	case 64000:
 	case 88200:
 	case 176400:
-		return PLL_RATE_11025_22050_44100_64000_88200_176400;
+		return PISTACHIO_PLL_RATE_B;
 	default:
 		return -EINVAL;
 	}
@@ -455,6 +455,7 @@
 	int ret;
 
 	mutex_lock(&pbc->rate_mutex);
+	*active_rate = 0;
 	ret = _pistachio_card_change_rate(pbc, rate, i2s);
 	if (!ret)
 		*active_rate = rate;
@@ -1543,7 +1544,7 @@
 	unsigned int rate;
 	int ret;
 
-	rate = PLL_RATE_11025_22050_44100_64000_88200_176400;
+	rate = PISTACHIO_PLL_RATE_B;
 	ret = clk_set_rate(pbc->audio_pll, rate);
 	if (ret)
 		return ret;