Merge branch 'renesas-drivers-2016-05-17-v4.6/iccom' into v4.6/rcar-3.3.x

* renesas-drivers-2016-05-17-v4.6/iccom:
  hwspinlock: rcar: Add support for R-Car Gen3 Hardware Spinlock
  DT: hwspinlock: Add binding documentation for R-Car Gen3 hwspinlock
  arm64: renesas: Enable RPMSG
  rpmsg: DMA map sgs passed to virtio
  virtio: Add dma variants of virtqueue_add_in and outbuf
  virtio_ring: Add option for DMA mapped sgs in virtqueue_add
  virtio_ring: Break out vring descriptor setup code
  clk: renesas: r8a7796: Add MFIS clock
  clk: renesas: r8a7795: Add MFIS clock
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt
index 0d30e42..8515658 100644
--- a/Documentation/devicetree/bindings/display/renesas,du.txt
+++ b/Documentation/devicetree/bindings/display/renesas,du.txt
@@ -9,6 +9,7 @@
     - "renesas,du-r8a7793" for R8A7793 (R-Car M2-N) compatible DU
     - "renesas,du-r8a7794" for R8A7794 (R-Car E2) compatible DU
     - "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU
+    - "renesas,du-r8a7796" for R8A7796 (R-Car M3) compatible DU
 
   - reg: A list of base address and length of each memory resource, one for
     each entry in the reg-names property.
@@ -50,6 +51,7 @@
  R8A7793 (M2-N)	DPAD		LVDS 0		-		-
  R8A7794 (E2)	DPAD 0		DPAD 1		-		-
  R8A7795 (H3)	DPAD		HDMI 0		HDMI 1		LVDS
+ R8A7796 (M3)	DPAD		HDMI		LVDS		-
 
 
 Example: R8A7790 (R-Car H2) DU
diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
index 5b902ac..0e2065b 100644
--- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt
@@ -1,6 +1,6 @@
 * Renesas R-Car DMA Controller Device Tree bindings
 
-Renesas R-Car Generation 2 SoCs have multiple multi-channel DMA
+Renesas R-Car Generation 2 and 3 SoCs have multiple multi-channel DMA
 controller instances named DMAC capable of serving multiple clients. Channels
 can be dedicated to specific clients or shared between a large number of
 clients.
@@ -22,6 +22,7 @@
 		- "renesas,dmac-r8a7793" (R-Car M2-N)
 		- "renesas,dmac-r8a7794" (R-Car E2)
 		- "renesas,dmac-r8a7795" (R-Car H3)
+		- "renesas,dmac-r8a7796" (R-Car M3)
 
 - reg: base address and length of the registers block for the DMAC
 
diff --git a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
index e7780a1..4987ff6 100644
--- a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
+++ b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt
@@ -8,6 +8,7 @@
 	  - "renesas,r8a7793-usb-dmac" (R-Car M2-N)
 	  - "renesas,r8a7794-usb-dmac" (R-Car E2)
 	  - "renesas,r8a7795-usb-dmac" (R-Car H3)
+	  - "renesas,r8a7796-usb-dmac" (R-Car M3)
 - reg: base address and length of the registers block for the DMAC
 - interrupts: interrupt specifiers for the DMAC, one for each entry in
   interrupt-names.
diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
index f60e2f4..4303b67 100644
--- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
+++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
@@ -10,6 +10,7 @@
     - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller.
     - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
     - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
+    - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3) compatible GPIO controller.
     - "renesas,gpio-rcar": for generic R-Car GPIO controller.
 
   - reg: Base address and length of each memory resource used by the GPIO
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
index cf8bfc9..239632a 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
@@ -11,6 +11,7 @@
 	"renesas,i2c-r8a7793"
 	"renesas,i2c-r8a7794"
 	"renesas,i2c-r8a7795"
+	"renesas,i2c-r8a7796"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: interrupt specifier.
@@ -19,6 +20,9 @@
 - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
   property indicates the default frequency 100 kHz.
 - clocks: clock specifier.
+- dmas: Must contain a list of two references to DMA specifiers, one for
+  transmission, and one for reception.
+- dma-names: Must contain a list of two DMA names, "tx" and "rx".
 
 - i2c-scl-falling-time-ns: see i2c.txt
 - i2c-scl-internal-delay-ns: see i2c.txt
diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
index 3ed027c..98ae900 100644
--- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
+++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
@@ -16,6 +16,7 @@
     - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU.
     - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU.
     - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU.
+    - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU.
     - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU.
 
   - reg: Base address and size of the IPMMU registers.
diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt
index 6a4e61c..285048b 100644
--- a/Documentation/devicetree/bindings/media/rcar_vin.txt
+++ b/Documentation/devicetree/bindings/media/rcar_vin.txt
@@ -6,6 +6,7 @@
 channel which can be either RGB, YUYV or BT656.
 
  - compatible: Must be one or more of the following
+   - "renesas,vin-r8a7796" for the R8A7796 device
    - "renesas,vin-r8a7795" for the R8A7795 device
    - "renesas,vin-r8a7794" for the R8A7794 device
    - "renesas,vin-r8a7793" for the R8A7793 device
diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
index 0f610d4..56e259f 100644
--- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt
@@ -23,6 +23,9 @@
 		"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
 		"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
 		"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
+		"renesas,mmc-r8a7795" - MMC IP on R8A7795 SoC
+		"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
+		"renesas,mmc-r8a7796" - MMC IP on R8A7796 SoC
 
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
diff --git a/Documentation/devicetree/bindings/net/renesas,ravb.txt b/Documentation/devicetree/bindings/net/renesas,ravb.txt
index c8ac222..86e3e10 100644
--- a/Documentation/devicetree/bindings/net/renesas,ravb.txt
+++ b/Documentation/devicetree/bindings/net/renesas,ravb.txt
@@ -10,6 +10,7 @@
 	      "renesas,etheravb-r8a7793" if the device is a part of R8A7793 SoC.
 	      "renesas,etheravb-r8a7794" if the device is a part of R8A7794 SoC.
 	      "renesas,etheravb-r8a7795" if the device is a part of R8A7795 SoC.
+	      "renesas,etheravb-r8a7796" if the device is a part of R8A7796 SoC.
 	      "renesas,etheravb-rcar-gen2" for generic R-Car Gen 2 compatible interface.
 	      "renesas,etheravb-rcar-gen3" for generic R-Car Gen 3 compatible interface.
 
@@ -33,7 +34,7 @@
 - interrupt-parent: the phandle for the interrupt controller that services
 		    interrupts for this device.
 - interrupt-names: A list of interrupt names.
-		   For the R8A7795 SoC this property is mandatory;
+		   For the R8A7795/R8A7796 SoC this property is mandatory;
 		   it should include one entry per channel, named "ch%u",
 		   where %u is the channel number ranging from 0 to 24.
 		   For other SoCs this property is optional; if present
diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt
index 6cf9969..ca1698b 100644
--- a/Documentation/devicetree/bindings/pci/rcar-pci.txt
+++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt
@@ -6,6 +6,7 @@
 	    "renesas,pcie-r8a7791" for the R8A7791 SoC;
 	    "renesas,pcie-r8a7793" for the R8A7793 SoC;
 	    "renesas,pcie-r8a7795" for the R8A7795 SoC;
+	    "renesas,pcie-r8a7796" for the R8A7796 SoC;
 	    "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 compatible device.
 
 	    When compatible with the generic version, nodes must list the
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
index 2281d6c..22b8306 100644
--- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
+++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
@@ -6,6 +6,8 @@
 Required properties:
 - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
 	      SoC.
+	      "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
+	      SoC.
 	      "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
 
 	      When compatible with the generic version, nodes must list the
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index 503bce3..e8078b1 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -31,8 +31,8 @@
     - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
     - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
     - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
-    - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART.
-    - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART.
+    - "renesas,scif-r8a7796" for R8A7796 (R-Car M3) SCIF compatible UART.
+    - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3) HSCIF compatible UART.
     - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
     - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
     - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index c7b29df..15a7316 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -373,6 +373,8 @@
 - #clock-cells			: it must be 0 if your system has audio_clkout
 				  it must be 1 if your system has audio_clkout0/1/2/3
 - clock-frequency		: for all audio_clkout0/1/2/3
+- clkout-lr-asynchronous	: boolean property. it indicates that audio_clkoutn
+				  is asynchronizes with lr-clock.
 
 SSI subnode properties:
 - interrupts			: Should contain SSI interrupt for PIO transfer
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index aa005c1..c2b6251 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -10,6 +10,8 @@
 			 "renesas,msiof-r8a7792" (R-Car V2H)
 			 "renesas,msiof-r8a7793" (R-Car M2-N)
 			 "renesas,msiof-r8a7794" (R-Car E2)
+			 "renesas,msiof-r8a7795" (R-Car H3)
+			 "renesas,msiof-r8a7796" (R-Car M3)
 			 "renesas,msiof-sh73a0" (SH-Mobile AG5)
 - reg                  : A list of offsets and lengths of the register sets for
 			 the device.
diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
new file mode 100644
index 0000000..9b38109
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
@@ -0,0 +1,84 @@
+* Renesas R-Car Gen3 Thermal
+
+Required properties:
+- compatible		: "renesas,thermal-<soctype>",
+			  Examples with soctypes are:
+			    - "renesas,thermal-r8a7795" (R-Car H3)
+			    - "renesas,thermal-r8a7796" (R-Car M3)
+- reg			: Address range of the thermal registers.
+- #thermal-sensor-cells : Please see ./thermal.txt
+
+Option properties:
+
+- interrupts		: use interrupt
+
+Example (non interrupt support):
+
+thermal: thermal@0xe6198000 {
+                        compatible = "renesas,thermal-r8a7795";
+                        reg = <0 0xe6198000 0 0x5c>;
+                };
+
+thermal-zones {
+	cpu_thermal: cpu-thermal {
+		polling-delay-passive	= <250>;
+		polling-delay		= <1000>;
+
+		thermal-sensors = <&thermal>;
+	};
+};
+
+Example (interrupt support):
+
+thermal: thermal@0xe6198000 {
+                        compatible = "renesas,thermal-r8a7795";
+                        reg = <0 0xe6198000 0 0x5c>;
+			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+			             <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+			             <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+                };
+
+thermal-zones {
+	cpu_thermal: cpu-thermal {
+		polling-delay-passive	= <250>;
+		polling-delay		= <0>;
+
+		thermal-sensors = <&thermal>;
+	};
+};
+
+* Emergency shutdown for R-CAR Gen3
+Emergency shutdown functionality provides the specific cooling mechanism
+for R-CAR Gen3. In case of high temperature(e.g over 100 degrees),
+it has the ability to rapidly cool down the system.
+
+Required property:
+- polling-delay:	The maximum number of milliseconds to wait between polls
+  Type: unsigned	when checking temperature for emergency shutdown.
+  Size: one cell
+
+- on-temperature:       This value indicates the emergency temperature and invokes
+  Type: unsigned	emergency shutdown functionality when exceeding this
+  Size: one cell	temperature.
+
+- off-temperature:	This value indicates the temperature to disable emergency
+  Type: unsigned	shutdown.
+  Size: one cell
+
+- status:		Should be "disabled" always.
+  Type: string
+
+- target_cpus:		This property indicates which CPU will be targeted for shutdown.
+  Type: phandle
+
+thermal-zones {
+	emergency {
+		polling-delay = <1000>;    /* milliseconds */
+		on-temperature = <110000>; /* millicelsius */
+		off-temperature = <95000>; /* millicelsius */
+		target_cpus = <&a57_1>,
+			      <&a57_2>,
+			      <&a57_3>;
+		status = "disabled";
+	};
+};
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
index b604056..3b6086e 100644
--- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
+++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
@@ -9,6 +9,7 @@
 	- "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
 	- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
 	- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
+	- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3) compatible device
 	- "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device
 	- "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
 
@@ -24,8 +25,9 @@
   - renesas,buswait: Integer to use BUSWAIT register
   - renesas,enable-gpio: A gpio specifier to check GPIO determining if USB
 			 function should be enabled
-  - phys: phandle + phy specifier pair
+  - phys: phandle of *Generic PHY* + phy specifier pair
   - phy-names: must be "usb"
+  - usb-phy: phandle of usb phy
   - dmas: Must contain a list of references to DMA specifiers.
   - dma-names : named "ch%d", where %d is the channel number ranging from zero
                 to the number of channels (DnFIFOs) minus one.
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 966885c..0b7d857 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -11,6 +11,7 @@
     - "renesas,xhci-r8a7791" for r8a7791 SoC
     - "renesas,xhci-r8a7793" for r8a7793 SoC
     - "renesas,xhci-r8a7795" for r8a7795 SoC
+    - "renesas,xhci-r8a7796" for r8a7796 SoC
     - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device
     - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
     - "xhci-platform" (deprecated)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index df6b67e..8aad18a 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -80,6 +80,7 @@
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
 CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPUFREQ_DT=y
 CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
@@ -190,7 +191,8 @@
 CONFIG_SPI_ORION=y
 CONFIG_SPI_PL022=y
 CONFIG_SPI_QUP=y
-CONFIG_SPI_SPIDEV=m
+CONFIG_SPI_SH_MSIOF=y
+CONFIG_SPI_SPIDEV=y
 CONFIG_SPMI=y
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_PINCTRL_MSM8916=y
@@ -207,8 +209,13 @@
 CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_INA2XX=m
 CONFIG_THERMAL=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
+CONFIG_CPU_THERMAL=y
 CONFIG_THERMAL_EMULATION=y
 CONFIG_EXYNOS_THERMAL=y
+CONFIG_RCAR_GEN3_THERMAL=y
+CONFIG_RCAR_THERMAL_EMS_ENABLED=y
 CONFIG_WATCHDOG=y
 CONFIG_RENESAS_WDT=y
 CONFIG_MFD_SPMI_PMIC=y
@@ -218,6 +225,7 @@
 CONFIG_REGULATOR_BD9571MWV=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_HI655X=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_QCOM_SMD_RPM=y
 CONFIG_REGULATOR_QCOM_SPMI=y
 CONFIG_REGULATOR_S2MPS11=y
@@ -228,6 +236,10 @@
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SOC_CAMERA=y
 CONFIG_SOC_CAMERA_PLATFORM=y
+CONFIG_VIDEO_RCAR_VIN=y
+CONFIG_VIDEO_RCAR_CSI2=y
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+CONFIG_VIDEO_ADV7482=y
 CONFIG_V4L_MEM2MEM_DRIVERS=y
 CONFIG_VIDEO_RENESAS_FCP=y
 CONFIG_VIDEO_RENESAS_VSP1=y
@@ -266,6 +278,8 @@
 CONFIG_USB_MSM_OTG=y
 CONFIG_USB_ULPI=y
 CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS=y
+CONFIG_USB_RENESAS_USBHS_UDC=y
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
@@ -275,6 +289,8 @@
 CONFIG_MMC_SDHCI_TEGRA=y
 CONFIG_MMC_SDHCI_MSM=y
 CONFIG_MMC_SPI=y
+CONFIG_MMC_TMIO_CORE=y
+CONFIG_MMC_SDHI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_EXYNOS=y
 CONFIG_MMC_DW_K3=y
@@ -298,6 +314,7 @@
 CONFIG_TEGRA20_APB_DMA=y
 CONFIG_QCOM_BAM_DMA=y
 CONFIG_RCAR_DMAC=y
+CONFIG_RENESAS_USB_DMAC=y
 CONFIG_VFIO=y
 CONFIG_VFIO_PCI=y
 CONFIG_VIRTIO_PCI=y
@@ -305,8 +322,11 @@
 CONFIG_VIRTIO_MMIO=y
 CONFIG_XEN_GNTDEV=y
 CONFIG_XEN_GRANT_DEV_ALLOC=y
+CONFIG_STAGING=y
+CONFIG_STAGING_BOARD=y
 CONFIG_COMMON_CLK_SCPI=y
 CONFIG_COMMON_CLK_CS2000_CP=y
+CONFIG_COMMON_CLK_5P49V5923A=y
 CONFIG_CLK_QORIQ=y
 CONFIG_COMMON_CLK_QCOM=y
 CONFIG_MSM_GCC_8916=y
@@ -316,6 +336,8 @@
 CONFIG_HI6220_MBOX=y
 CONFIG_IPMMU_VMSA=y
 CONFIG_ARM_SMMU=y
+CONFIG_PWM=y
+CONFIG_PWM_RCAR=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 2dd371d..8667442 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -192,6 +192,13 @@
 	  Adapter driver so that any PWM output can be (mis)used as clock signal
 	  at 50% duty cycle.
 
+config COMMON_CLK_5P49V5923A
+	tristate "Clock driver for 5P49V5923A programmable clock generator"
+	depends on I2C
+	help
+	  If you say yes here you get support for the 5P49V5923A programmable
+	  clock generator.
+
 config COMMON_CLK_PXA
 	def_bool COMMON_CLK && ARCH_PXA
 	---help---
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 6d1e3be..4eb37ec 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -17,6 +17,7 @@
 
 # hardware specific clock types
 # please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_COMMON_CLK_5P49V5923A)	+= clk-5p49v5923a.o
 obj-$(CONFIG_MACH_ASM9260)		+= clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
diff --git a/drivers/clk/clk-5p49v5923a.c b/drivers/clk/clk-5p49v5923a.c
new file mode 100644
index 0000000..f273748
--- /dev/null
+++ b/drivers/clk/clk-5p49v5923a.c
@@ -0,0 +1,340 @@
+/*
+ * drivers/gpu/drm/i2c/5p49v5923a.c
+ *     This file is programmable clock generator driver.
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * This file is based on the drivers/clk/clk-cs2000-cp.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/module.h>
+
+#define REF_CLK		1
+#define CLK_MAX		5
+
+#define INPUT_CLK	25000000
+
+#define C5P49_FB_INT_DIV_REG1	0x17
+#define C5P49_FB_INT_DIV_REG0	0x18
+
+/* offset address*/
+#define C5P49_DIV_FRAC_29_22	0x02
+#define C5P49_DIV_FRAC_21_14	0x03
+#define C5P49_DIV_FRAC_13_6	0x04
+#define C5P49_DIV_FRAC_5_0	0x05
+#define C5P49_DIV_INTEGER_11_4	0x0d
+#define C5P49_DIV_INTEGER_3_0	0x0e
+
+#define C5P49_CLK_OE_SHUTDOWN	0x68
+
+#define hw_to_priv(_hw)		container_of(_hw, struct clk_5p49_priv, hw)
+#define priv_to_client(priv)	(priv->client)
+#define priv_to_dev(priv)	(&(priv_to_client(priv)->dev))
+
+struct clk_5p49_priv {
+	struct		clk_hw hw;
+	struct		i2c_client *client;
+	struct		clk *clk_out;
+	unsigned long	index;
+	unsigned long	clk_rate;
+};
+
+static const struct of_device_id clk_5p49_of_match[] = {
+	{ .compatible = "idt,5p49v5923a", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, clk_5p49_of_match);
+
+static const struct i2c_device_id clk_5p49_id[] = {
+	{ "5p49v5923a",},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, clk_5p49_id);
+
+#define clk_5p49_read(priv, addr) \
+	i2c_smbus_read_byte_data(priv_to_client(priv), \
+	(addr + (0x10 * priv->index)))
+#define clk_5p49_write(priv, addr, val) \
+	i2c_smbus_write_byte_data(priv_to_client(priv), \
+	(addr + (0x10 * priv->index)), val)
+
+static int clk_5p49_set_rate(struct clk_hw *hw,
+			     unsigned long rate, unsigned long parent_rate)
+{
+	return 0;
+}
+
+static void clk_5p49_power(struct clk_hw *hw, bool power)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	u8 reg;
+
+	if (power) {
+		reg = i2c_smbus_read_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN);
+		reg |= (0x80 >> (priv->index - 1));
+		i2c_smbus_write_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN, reg);
+	} else {
+		reg = i2c_smbus_read_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN);
+		reg &= ~(0x80 >> (priv->index - 1));
+		i2c_smbus_write_byte_data(priv->client,
+					C5P49_CLK_OE_SHUTDOWN, reg);
+	}
+}
+
+static int clk_5p49_enable(struct clk_hw *hw)
+{
+	clk_5p49_power(hw, true);
+
+	return 0;
+}
+
+static void clk_5p49_disable(struct clk_hw *hw)
+{
+	clk_5p49_power(hw, false);
+}
+
+static unsigned long clk_5p49_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+
+	return priv->clk_rate;
+}
+
+static int clk_5p49_div_calculation(struct clk_hw *hw, unsigned long rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	int integ_div, frac_div, div, vco_div, vco_clk;
+	u32 shift_1kHz = 1000;
+	u8 frac_0, frac_1, frac_2, frac_3;
+
+	vco_div = ((i2c_smbus_read_byte_data(priv->client,
+			C5P49_FB_INT_DIV_REG0) & 0xF0) >> 4)
+			+ (i2c_smbus_read_byte_data(priv->client,
+			C5P49_FB_INT_DIV_REG1) << 4);
+
+	clk_5p49_power(hw, false);
+
+	vco_clk = INPUT_CLK * vco_div / shift_1kHz;
+	dev_dbg(&priv->client->dev, "vco clock:%d kHz\n", vco_clk);
+
+	vco_clk = (vco_clk / 2);
+	rate = rate / shift_1kHz;
+
+	integ_div = (vco_clk / rate);
+	div = ((vco_clk * shift_1kHz) / rate);
+	frac_div = div - (integ_div * shift_1kHz);
+
+	if (frac_div > 0x3fffffff)
+		return -EINVAL;
+
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_11_4,
+			((0x0ff0 & (u16)integ_div) >> 4));
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_3_0,
+			((0x000f & (u16)integ_div) << 4));
+
+	/* spread = 0.01% */
+	frac_div = frac_div - ((div / (100 * 100 / 1)) / 2);
+	frac_div = ((0x1000000 / shift_1kHz) * frac_div);
+	dev_dbg(&priv->client->dev,
+		"integer:0x%x, fraction:0x%x\n",
+		integ_div, frac_div);
+
+	frac_0 = (frac_div & 0x3fc00000) >> 22;
+	frac_1 = (frac_div & 0x003fc000) >> 14;
+	frac_2 = (frac_div & 0x00003fc0) >> 6;
+	frac_3 = (frac_div & 0x0000003f) << 2;
+
+	clk_5p49_write(priv, C5P49_DIV_FRAC_29_22, frac_0);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_21_14, frac_1);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_13_6,  frac_2);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_5_0,   frac_3);
+
+	clk_5p49_power(hw, true);
+
+	return 0;
+}
+
+static long clk_5p49_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	struct clk_5p49_priv *priv = hw_to_priv(hw);
+	int ret;
+
+	priv->clk_rate = 0;
+
+	ret = clk_5p49_div_calculation(hw, rate);
+	if (ret < 0)
+		return ret;
+
+	priv->clk_rate = rate;
+
+	return 0;
+}
+
+static u8 clk_5p49_get_parent(struct clk_hw *hw)
+{
+	return 0;
+}
+
+static const struct clk_ops clk_5p49_ops = {
+	.get_parent	= clk_5p49_get_parent,
+	.set_rate	= clk_5p49_set_rate,
+	.prepare	= clk_5p49_enable,
+	.unprepare	= clk_5p49_disable,
+	.recalc_rate	= clk_5p49_recalc_rate,
+	.round_rate	= clk_5p49_round_rate,
+};
+
+static int clk_5p49_clk_register(struct clk_5p49_priv *priv,
+				 struct device_node *np)
+{
+	struct clk_init_data init;
+	struct clk *clk;
+	const char *name;
+	static const char *parent_names[REF_CLK];
+	int ret = 0;
+
+	parent_names[0]	= __clk_get_name(of_clk_get(np, 0));
+	name = np->name;
+
+	init.name		= name;
+	init.ops		= &clk_5p49_ops;
+	init.flags		= CLK_IS_BASIC | CLK_SET_RATE_PARENT;
+	init.parent_names	= parent_names;
+	init.num_parents	= ARRAY_SIZE(parent_names);
+
+	priv->hw.init = &init;
+
+	clk = clk_register(NULL, &priv->hw);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (ret < 0) {
+		clk_unregister(clk);
+		return ret;
+	}
+
+	priv->clk_out = clk;
+
+	return 0;
+}
+
+static int clk_5p49_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct clk_5p49_priv *priv = NULL;
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node, *ch_np;
+	int ret, i, ch = 1;	/* ch = 0 reserved.*/
+	u32 probe_cnt = 0;
+
+	for (i = ch; i < CLK_MAX; i++) {
+		char name[20];
+
+		sprintf(name, "5p49v5923a_clk%u", i);
+		ch_np = of_get_child_by_name(np, name);
+		if (!ch_np)
+			continue;
+
+		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+		if (!priv)
+			return -ENOMEM;
+
+		priv->client = client;
+		priv->index = i + 1;
+		i2c_set_clientdata(client, priv);
+
+		ret = clk_5p49_clk_register(priv, ch_np);
+		if (ret < 0)
+			return ret;
+		probe_cnt++;
+	}
+
+	if (probe_cnt == 0) {
+		dev_err(dev, "Device tree error.\n");
+		return -EINVAL;
+	}
+
+	dev_info(dev, "Rev.0x%x, probed\n",
+		i2c_smbus_read_byte_data(priv->client, 0x01));
+
+	return 0;
+}
+
+static int clk_5p49_remove(struct i2c_client *client)
+{
+	struct clk_5p49_priv *priv = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
+
+	of_clk_del_provider(np);
+
+	clk_unregister(priv->clk_out);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int clk_5p49_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int clk_5p49_resume(struct device *dev)
+{
+	struct clk_5p49_priv *priv = dev_get_drvdata(dev);
+
+	/* Initialize value */
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_11_4, 1);
+	clk_5p49_write(priv, C5P49_DIV_INTEGER_3_0, 0x40);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_29_22, 0);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_21_14, 0xC3);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_13_6, 0x94);
+	clk_5p49_write(priv, C5P49_DIV_FRAC_5_0, 0xDC);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(clk_5p49_pm_ops,
+			clk_5p49_suspend, clk_5p49_resume);
+#define DEV_PM_OPS (&clk_5p49_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct i2c_driver clk_5p49_driver = {
+	.driver = {
+		.name = "5p49v5923a",
+		.pm	= DEV_PM_OPS,
+		.of_match_table = clk_5p49_of_match,
+	},
+	.probe		= clk_5p49_probe,
+	.remove		= clk_5p49_remove,
+	.id_table	= clk_5p49_id,
+};
+
+module_i2c_driver(clk_5p49_driver);
+
+MODULE_DESCRIPTION("5p49v5923a programmable clock generator driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index e342565e..dc511e2 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -12,6 +12,7 @@
 #define pr_fmt(fmt) "CPUidle arm: " fmt
 
 #include <linux/cpuidle.h>
+#include <linux/cpufeature.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
@@ -19,7 +20,9 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 
+#include <asm/cpu.h>
 #include <asm/cpuidle.h>
+#include <asm/cputype.h>
 
 #include "dt_idle_states.h"
 
@@ -78,6 +81,28 @@
 	}
 };
 
+static int __init arm_idle_driver_init(struct cpuidle_driver *drv, int part_id)
+{
+	struct cpumask *cpumask;
+	int cpu;
+
+	cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
+	if (!cpumask)
+		return -ENOMEM;
+
+	for_each_possible_cpu(cpu) {
+		struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, cpu);
+		u32 midr = cpuinfo->reg_midr;
+
+		if (MIDR_PARTNUM(midr) == part_id)
+			cpumask_set_cpu(cpu, cpumask);
+	}
+
+	drv->cpumask = cpumask;
+
+	return 0;
+}
+
 static const struct of_device_id arm_idle_state_match[] __initconst = {
 	{ .compatible = "arm,idle-state",
 	  .data = arm_enter_idle_state },
@@ -97,6 +122,11 @@
 	struct cpuidle_driver *drv = &arm_idle_driver;
 	struct cpuidle_device *dev;
 
+	/* Support CPUIdle for Cortex-A57 only */
+	ret = arm_idle_driver_init(drv, ARM_CPU_PART_CORTEX_A57);
+	if (ret)
+		return ret;
+
 	/*
 	 * Initialize idle states data, starting at index 1.
 	 * This driver is DT only, if no DT idle states are detected (ret == 0)
@@ -117,7 +147,7 @@
 	 * Call arch CPU operations in order to initialize
 	 * idle states suspend back-end specific data
 	 */
-	for_each_possible_cpu(cpu) {
+	for_each_cpu(cpu, drv->cpumask) {
 		ret = arm_cpuidle_init(cpu);
 
 		/*
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 6e0685f..55584f1 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -40,7 +40,7 @@
 endif
 
 config RCAR_DMAC
-	tristate "Renesas R-Car Gen2 DMA Controller"
+	tristate "Renesas R-Car Gen2/3 DMA Controller"
 	depends on ARCH_RENESAS || COMPILE_TEST
 	select RENESAS_DMA
 	help
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 03e0458..bb09330 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -485,6 +485,13 @@
 	psci_0_2_set_functions();
 
 	psci_init_migrate();
+	/*
+	 * psci_init_migrate() might fail to get needed information due to
+	 * incomplete firmware support.
+	 * FIXME: Let's assume that Trusted OS services (e.g DDR training)
+	 * always run in CPU0.
+	 */
+	resident_cpu = 0;
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
 		psci_init_cpu_suspend();
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index dd9f640..1b8d0dc 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -584,6 +584,10 @@
 		/* Gen3 GPIO is identical to Gen2. */
 		.data = &gpio_rcar_info_gen2,
 	}, {
+		.compatible = "renesas,gpio-r8a7796",
+		/* Gen3 GPIO is identical to Gen2. */
+		.data = &gpio_rcar_info_gen2,
+	}, {
 		.compatible = "renesas,gpio-rcar",
 		.data = &gpio_rcar_info_gen1,
 	}, {
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 4a64481..e40f065 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -245,8 +245,13 @@
 
 	spin_lock_irqsave(&hdmi->i2c->lock, flags);
 
-	/* Set Fast Mode speed */
-	hdmi_writeb(hdmi, 0x0b, HDMI_I2CM_DIV);
+	if (hdmi->dev_type == RCAR_HDMI) {
+		/* Set Standard Mode speed */
+		hdmi_writeb(hdmi, 0x03, HDMI_I2CM_DIV);
+	} else {
+		/* Set Fast Mode speed */
+		hdmi_writeb(hdmi, 0x0b, HDMI_I2CM_DIV);
+	}
 
 	/* Software reset */
 	hdmi_writeb(hdmi, 0x00, HDMI_I2CM_SOFTRSTZ);
@@ -1709,6 +1714,14 @@
 	hdmi->disabled = false;
 	dw_hdmi_update_power(hdmi);
 	dw_hdmi_update_phy_mask(hdmi);
+
+	if (hdmi->dev_type == RCAR_HDMI) {
+		hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
+				 HDMI_PHY_POL0);
+		dw_hdmi_fb_registered(hdmi);
+		dw_hdmi_i2c_init(hdmi);
+	}
+
 	mutex_unlock(&hdmi->mutex);
 }
 
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index 1f500a1..4537664 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -65,7 +65,10 @@
 		gem_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
 	if (!gem_obj)
 		return ERR_PTR(-ENOMEM);
+
 	cma_obj = container_of(gem_obj, struct drm_gem_cma_object, base);
+	if (!cma_obj->dev)
+		cma_obj->dev = drm->dev;
 
 	ret = drm_gem_object_init(drm, gem_obj, size);
 	if (ret)
@@ -109,7 +112,7 @@
 	if (IS_ERR(cma_obj))
 		return cma_obj;
 
-	cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,
+	cma_obj->vaddr = dma_alloc_wc(cma_obj->dev, size, &cma_obj->paddr,
 				      GFP_KERNEL | __GFP_NOWARN);
 	if (!cma_obj->vaddr) {
 		dev_err(drm->dev, "failed to allocate buffer with size %zu\n",
@@ -192,7 +195,7 @@
 	cma_obj = to_drm_gem_cma_obj(gem_obj);
 
 	if (cma_obj->vaddr) {
-		dma_free_wc(gem_obj->dev->dev, cma_obj->base.size,
+		dma_free_wc(cma_obj->dev, cma_obj->base.size,
 			    cma_obj->vaddr, cma_obj->paddr);
 	} else if (gem_obj->import_attach) {
 		drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index d7c7ffa..fa4b977 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -23,6 +23,7 @@
 config DRM_RCAR_LVDS
 	bool "R-Car DU LVDS Encoder Support"
 	depends on DRM_RCAR_DU
+	select GPIOLIB
 	help
 	  Enable support for the R-Car Display Unit embedded LVDS encoders.
 
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
index 2ade186..435c81b 100644
--- a/drivers/gpu/drm/rcar-du/Makefile
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -3,12 +3,12 @@
 		 rcar_du_encoder.o \
 		 rcar_du_group.o \
 		 rcar_du_kms.o \
-		 rcar_du_lvdscon.o \
 		 rcar_du_plane.o \
 		 rcar_du_vgacon.o
 
 rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI)	+= rcar_du_hdmienc.o
-rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o
+rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS)	+= rcar_du_lvdsenc.o \
+					   rcar_du_lvdscon.o
 
 rcar-du-drm-$(CONFIG_DRM_RCAR_VSP)	+= rcar_du_vsp.o
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index b2da9a3..7ece810 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/mutex.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -108,6 +109,21 @@
 	clk_disable_unprepare(rcrtc->clock);
 }
 
+void rcar_du_crtc_vbk_check(struct rcar_du_group *rgrp)
+{
+	int i;
+
+	for (i = 0; i < rgrp->dev->num_crtcs; ++i) {
+		struct rcar_du_crtc *rcrtc = &rgrp->dev->crtcs[i];
+		struct drm_crtc *crtc = &rcrtc->crtc;
+
+		if (!(rcar_du_crtc_read(rcrtc, DIER) & DIER_VBE))
+			continue;
+
+		drm_crtc_wait_one_vblank(crtc);
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * Hardware Setup
  */
@@ -124,9 +140,14 @@
 	for (n = 39; n < 120; n++) {
 		for (m = 0; m < 4; m++) {
 			for (fdpll = 1; fdpll < 32; fdpll++) {
-				/* 1/2 (FRQSEL=1) for duty rate 50% */
-				dpllclk = extclk * (n + 1) / (m + 1)
+				if (RCAR_PRR_IS_PRODUCT(H3) &&
+					(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+					/* 1/2 (FRQSEL=1) for duty rate 50% */
+					dpllclk = extclk * (n + 1) / (m + 1)
 						 / (fdpll + 1) / 2;
+				else
+					dpllclk = extclk * (n + 1) / (m + 1)
+						 / (fdpll + 1);
 				if (dpllclk >= 400000000)
 					continue;
 
@@ -167,20 +188,11 @@
 	u32 div;
 	u32 dpll_reg = 0;
 	struct dpll_info *dpll;
-	void __iomem *product_reg;
-	bool h3_es1_workaround = false;
 
 	dpll = kzalloc(sizeof(*dpll), GFP_KERNEL);
 	if (dpll == NULL)
 		return;
 
-	/* DU2 DPLL Clock Select bit workaround in R-Car H3(ES1.0) */
-	product_reg = ioremap(PRODUCT_REG, 0x04);
-	if (((readl(product_reg) & PRODUCT_MASK) == PRODUCT_H3_BIT)
-		&& ((readl(product_reg) & CUT_ES1_MASK) == CUT_ES1))
-		h3_es1_workaround = true;
-	iounmap(product_reg);
-
 	/* Compute the clock divisor and select the internal or external dot
 	 * clock based on the requested frequency.
 	 */
@@ -195,6 +207,7 @@
 		unsigned long rate;
 		u32 extdiv;
 
+		clk_set_rate(rcrtc->extclock, mode_clock);
 		extclk = clk_get_rate(rcrtc->extclock);
 
 		if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) {
@@ -216,7 +229,11 @@
 			dev_dbg(rcrtc->group->dev->dev,
 				"crtc%u: using external clock\n", rcrtc->index);
 			if (rcdu->info->dpll_ch & (0x01 << rcrtc->index)) {
-				escr = ESCR_DCLKSEL_DCLKIN | 0x01;
+				if (RCAR_PRR_IS_PRODUCT(H3) &&
+					(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+					escr = ESCR_DCLKSEL_DCLKIN | 0x01;
+				else
+					escr = ESCR_DCLKSEL_DCLKIN;
 				dpll_reg =  DPLLCR_CODE | DPLLCR_M(dpll->m) |
 					DPLLCR_FDPLL(dpll->fdpll) |
 					DPLLCR_CLKE | DPLLCR_N(dpll->n) |
@@ -224,12 +241,13 @@
 
 				if (rcrtc->index == DU_CH_1)
 					dpll_reg |= (DPLLCR_PLCS1 |
-						 DPLLCR_INCS_DPLL01_DOTCLKIN13);
+						DPLLCR_INCS_DPLL01_DOTCLKIN13);
 				if (rcrtc->index == DU_CH_2) {
 					dpll_reg |= (DPLLCR_PLCS0 |
-						 DPLLCR_INCS_DPLL01_DOTCLKIN02);
-					if (h3_es1_workaround)
-						dpll_reg |=  (0x01 << 21);
+						DPLLCR_INCS_DPLL01_DOTCLKIN02);
+					if (RCAR_PRR_IS_PRODUCT(H3) &&
+					   (RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+						dpll_reg |= (0x01 << 21);
 				}
 
 				rcar_du_group_write(rcrtc->group, DPLLCR,
@@ -244,8 +262,9 @@
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
 
 	/* Signal polarities */
-	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
-	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
+	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
+	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
+	      | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? DSMR_ODEV : 0)
 	      | DSMR_DIPM_DISP | DSMR_CSPM;
 	rcar_du_crtc_write(rcrtc, DSMR, value);
 
@@ -267,7 +286,7 @@
 					mode->crtc_vsync_start - 1);
 	rcar_du_crtc_write(rcrtc, VCR,  mode->crtc_vtotal - 1);
 
-	rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
+	rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start - 1);
 	rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
 }
 
@@ -764,6 +783,12 @@
 		return ret;
 	}
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(rcdu->dev, "product register init fail.\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index b52e9be..3476515 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -87,5 +87,6 @@
 			       enum rcar_du_output output);
 int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc);
 void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc);
+void rcar_du_crtc_vbk_check(struct rcar_du_group *rgrp);
 
 #endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index ea06b44..6290193 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -23,10 +23,15 @@
 #include <linux/wait.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_encoder_slave.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
+#include <drm/rcar_du_drm.h>
+
+#include <media/vsp1.h>
 
 #include "rcar_du_crtc.h"
 #include "rcar_du_encoder.h"
@@ -35,6 +40,7 @@
 #include "rcar_du_kms.h"
 #include "rcar_du_lvdsenc.h"
 #include "rcar_du_regs.h"
+#include "rcar_du_vsp.h"
 
 /* -----------------------------------------------------------------------------
  * Device Information
@@ -144,7 +150,8 @@
 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
 		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
 		  | RCAR_DU_FEATURE_VSP1_SOURCE
-		  | RCAR_DU_FEATURE_GEN3_REGS,
+		  | RCAR_DU_FEATURE_GEN3_REGS
+		  | RCAR_DU_FEATURE_DIDSR2_REG,
 	.num_crtcs = 4,
 	.routes = {
 		/* R8A7795 has one RGB output, two HDMI outputs and one
@@ -176,6 +183,38 @@
 	.vsp_num = 5,
 };
 
+static const struct rcar_du_device_info rcar_du_r8a7796_info = {
+	.gen = 3,
+	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
+		  | RCAR_DU_FEATURE_VSP1_SOURCE
+		  | RCAR_DU_FEATURE_GEN3_REGS,
+	.num_crtcs = 3,
+	.routes = {
+		/* R8A7796 has one RGB output, one LVDS output and one
+		 * HDMI outputs.
+		 */
+		[RCAR_DU_OUTPUT_DPAD0] = {
+			.possible_crtcs = BIT(2),
+			.encoder_type = DRM_MODE_ENCODER_NONE,
+			.port = 0,
+		},
+		[RCAR_DU_OUTPUT_HDMI0] = {
+			.possible_crtcs = BIT(1),
+			.encoder_type = RCAR_DU_ENCODER_HDMI,
+			.port = 1,
+		},
+		[RCAR_DU_OUTPUT_LVDS0] = {
+			.possible_crtcs = BIT(0),
+			.encoder_type = DRM_MODE_ENCODER_LVDS,
+			.port = 2,
+		},
+	},
+	.num_lvds = 1,
+	.dpll_ch =  BIT(1),
+	.vsp_num = 5,
+};
+
 static const struct of_device_id rcar_du_of_table[] = {
 	{ .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
 	{ .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
@@ -183,6 +222,7 @@
 	{ .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
 	{ .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
 	{ .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
+	{ .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
 	{ }
 };
 
@@ -445,6 +485,13 @@
 	rcar_du_crtc_enable_vblank(&rcdu->crtcs[pipe], false);
 }
 
+static const struct drm_ioctl_desc rcar_du_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(DRM_RCAR_DU_SET_VMUTE, rcar_du_set_vmute,
+		DRM_UNLOCKED | DRM_CONTROL_ALLOW),
+	DRM_IOCTL_DEF_DRV(DRM_RCAR_DU_SCRSHOT, rcar_du_vsp_write_back,
+		DRM_UNLOCKED | DRM_CONTROL_ALLOW),
+};
+
 static const struct file_operations rcar_du_fops = {
 	.owner		= THIS_MODULE,
 	.open		= drm_open,
@@ -466,6 +513,7 @@
 	.get_vblank_counter	= drm_vblank_no_hw_counter,
 	.enable_vblank		= rcar_du_enable_vblank,
 	.disable_vblank		= rcar_du_disable_vblank,
+	.gem_create_object	= rcar_du_create_object,
 	.gem_free_object	= drm_gem_cma_free_object,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
@@ -486,6 +534,8 @@
 	.date			= "20130110",
 	.major			= 1,
 	.minor			= 0,
+	.ioctls			= rcar_du_ioctls,
+	.num_ioctls		= ARRAY_SIZE(rcar_du_ioctls),
 };
 
 /* -----------------------------------------------------------------------------
@@ -555,14 +605,6 @@
 	}
 #endif
 
-#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
-	list_for_each_entry(encoder,
-		&rcdu->ddev->mode_config.encoder_list, head) {
-		if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
-			rcar_du_hdmienc_enable(encoder);
-	}
-#endif
-
 #ifdef CONFIG_RCAR_DDR_BACKUP
 	ret = rcar_du_restore_regs(rcdu);
 #endif /* CONFIG_RCAR_DDR_BACKUP */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 6413b7e..267488f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -33,6 +33,7 @@
 #define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
 #define RCAR_DU_FEATURE_VSP1_SOURCE	(1 << 2)	/* Has inputs from VSP1 */
 #define RCAR_DU_FEATURE_GEN3_REGS	(1 << 3)	/* Use Gen3 registers */
+#define RCAR_DU_FEATURE_DIDSR2_REG	(1 << 4)	/* Has DIDSR2 register */
 
 #define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
 #define RCAR_DU_QUIRK_LVDS_LANES	(1 << 1)	/* LVDS lanes 1 and 3 inverted */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 55dd3bd..f48fc64 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_group.c  --  R-Car Display Unit Channels Pair
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -101,11 +101,6 @@
 	rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
 
 	rcar_du_group_setup_pins(rgrp);
-	if (rcdu->info->gen == 3) {
-		rcar_du_group_write(rgrp, DEFR6, DEFR6_CODE |
-					  DEFR6_ODPM22_DISP);
-		rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
-	}
 
 	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
 		rcar_du_group_setup_defr8(rgrp);
@@ -113,13 +108,30 @@
 		/* Configure input dot clock routing. We currently hardcode the
 		 * configuration to routing DOTCLKINn to DUn.
 		 */
-		rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
+		if (rcdu->info->gen < 3) {
+			rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
 				    DIDSR_LCDS_DCLKIN(2) |
 				    DIDSR_LCDS_DCLKIN(1) |
 				    DIDSR_LCDS_DCLKIN(0) |
 				    DIDSR_PDCS_CLK(2, 0) |
 				    DIDSR_PDCS_CLK(1, 0) |
 				    DIDSR_PDCS_CLK(0, 0));
+		} else {
+			if (rgrp->index == 0) {
+				rcar_du_group_write(rgrp,
+				    DIDSR, DIDSR_CODE |
+				    DIDSR_LCDS0_DCLKIN |
+				    DIDSR_PDCS_CLK(1, 0) |
+				    DIDSR_PDCS_CLK(0, 0));
+			} else if ((rgrp->index == 1) &&
+				rcar_du_has(rgrp->dev,
+				RCAR_DU_FEATURE_DIDSR2_REG)) {
+				rcar_du_group_write(rgrp,
+				    DIDSR, DIDSR_CODE |
+				    DIDSR_PDCS_CLK(1, 0) |
+				    DIDSR_PDCS_CLK(0, 0));
+			}
+		}
 	}
 
 	if (rcdu->info->gen >= 3)
@@ -171,6 +183,15 @@
 
 static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
 {
+	if (!start) {
+		rcar_du_group_write(rgrp, DSYSR,
+			(rcar_du_group_read(rgrp, DSYSR) &
+			~(DSYSR_DRES | DSYSR_DEN)));
+
+		/* Wait for access stop of vsp */
+		rcar_du_crtc_vbk_check(rgrp);
+	}
+
 	rcar_du_group_write(rgrp, DSYSR,
 		(rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
 		(start ? DSYSR_DEN : DSYSR_DRES));
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index b03973c..7bda47a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -719,6 +719,8 @@
 	temp = readl(smstpcr);
 	writel(temp & ~(0x3 << 28), smstpcr);
 
+	rcar_du_hdmienc_enable(encoder);
+
 	ret = handle_registers(ip, DO_RESTORE);
 	if (ret)
 		pr_err("%s: Failed to restore %s register\n",
@@ -731,8 +733,8 @@
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	const struct drm_bridge_funcs *bfuncs = encoder->bridge->funcs;
 
-	if ((bfuncs) && (bfuncs->post_disable))
-		bfuncs->post_disable(encoder->bridge);
+	if ((bfuncs) && (bfuncs->disable))
+		bfuncs->disable(encoder->bridge);
 
 	if (hdmienc->renc->lvds)
 		rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc,
@@ -898,6 +900,16 @@
 rcar_du_hdmienc_mode_valid(struct drm_connector *connector,
 			    struct drm_display_mode *mode)
 {
+	if ((mode->hdisplay > 3840) || (mode->vdisplay > 2160))
+		return MODE_BAD;
+
+	if (((mode->hdisplay == 3840) && (mode->vdisplay == 2160))
+		&& (mode->vrefresh > 30))
+		return MODE_BAD;
+
+	if (mode->clock > 297000)
+		return MODE_BAD;
+
 	return MODE_OK;
 }
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index d6d9acb..6c24464 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -108,27 +108,35 @@
 	{
 		.fourcc = DRM_FORMAT_RGB332,
 		.bpp = 8,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_ARGB4444,
 		.bpp = 16,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_XRGB4444,
 		.bpp = 16,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_BGR888,
 		.bpp = 24,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_RGB888,
 		.bpp = 24,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_BGRA8888,
 		.bpp = 32,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_BGRX8888,
 		.bpp = 32,
+		.planes = 1,
 	}, {
 		.fourcc = DRM_FORMAT_YVYU,
 		.bpp = 16,
+		.planes = 1,
 	},
 	/* The following formats are not supported on Gen2 and thus have no
 	 * associated .pnmr or .edf settings.
@@ -192,6 +200,35 @@
  * Frame buffer
  */
 
+struct drm_gem_object *rcar_du_create_object(struct drm_device *dev,
+					     size_t size)
+{
+	struct rcar_du_device *rcdu = dev->dev_private;
+	struct drm_gem_cma_object *cma_obj;
+	unsigned int i;
+
+	cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
+	if (!cma_obj)
+		return ERR_PTR(-ENOMEM);
+
+	/* Use struct device from any FCP in case of VSP1_SOURCE. */
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
+		for (i = 0; i < rcdu->num_crtcs; ++i) {
+			struct rcar_du_vsp *vsp = &rcdu->vsps[i];
+
+			if (vsp->fcp) {
+				cma_obj->dev = vsp->fcp;
+				break;
+			}
+		}
+
+		if (!cma_obj->dev)
+			dev_warn(rcdu->dev, "unable to locate FCP\n");
+	}
+
+	return &cma_obj->base;
+}
+
 int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
 			struct drm_mode_create_dumb *args)
 {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
index 10eb51a..d3b27dc 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
@@ -34,6 +34,8 @@
 
 int rcar_du_modeset_init(struct rcar_du_device *rcdu);
 
+struct drm_gem_object *rcar_du_create_object(struct drm_device *dev,
+					     size_t size);
 int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
 			struct drm_mode_create_dumb *args);
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
index d4881ee..07f9e3e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h
@@ -1,7 +1,7 @@
 /*
  * rcar_du_lvdscon.h  --  R-Car Display Unit LVDS Connector
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -17,8 +17,17 @@
 struct rcar_du_device;
 struct rcar_du_encoder;
 
+#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
 int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
 				struct rcar_du_encoder *renc,
 				struct device_node *np);
+#else
+static inline int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
+				struct rcar_du_encoder *renc,
+				struct device_node *np)
+{
+	return -ENOSYS;
+}
+#endif
 
 #endif /* __RCAR_DU_LVDSCON_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index eb40f3e..36c532f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -31,6 +32,7 @@
 	bool enabled;
 
 	enum rcar_lvds_input input;
+	int gpio_pd;
 };
 
 static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
@@ -107,6 +109,13 @@
 	/* Turn the PLL on, set it to LVDS normal mode, wait for the startup
 	 * delay and turn the output on.
 	 */
+
+	/* Turn all the channels on. */
+	rcar_lvds_write(lvds, LVDCR1,
+			LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
+			LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
+			LVDCR1_CLKSTBY_GEN3);
+
 	lvdcr0 = LVDCR0_PLLON;
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 
@@ -117,12 +126,6 @@
 
 	lvdcr0 |= LVDCR0_LVRES;
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
-
-	/* Turn all the channels on. */
-	rcar_lvds_write(lvds, LVDCR1,
-			LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
-			LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
-			LVDCR1_CLKSTBY_GEN3);
 }
 
 int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
@@ -134,6 +137,9 @@
 	if (lvds->enabled)
 		return 0;
 
+	if (gpio_is_valid(lvds->gpio_pd))
+		gpio_set_value(lvds->gpio_pd, 1);
+
 	ret = clk_prepare_enable(lvds->clock);
 	if (ret < 0)
 		return ret;
@@ -182,6 +188,9 @@
 
 	lvds->enabled = false;
 
+	if (gpio_is_valid(lvds->gpio_pd))
+		gpio_set_value(lvds->gpio_pd, 0);
+
 	return 0;
 }
 
@@ -260,6 +269,7 @@
 	struct rcar_du_lvdsenc *lvds;
 	unsigned int i;
 	int ret;
+	char name[16];
 
 	for (i = 0; i < rcdu->info->num_lvds; ++i) {
 		lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
@@ -272,12 +282,20 @@
 		lvds->index = i;
 		lvds->input = i ? RCAR_LVDS_INPUT_DU1 : RCAR_LVDS_INPUT_DU0;
 		lvds->enabled = false;
+		/* Get optional backlight GPIO */
+		lvds->gpio_pd = of_get_named_gpio(rcdu->dev->of_node,
+						 "backlight", 0);
 
 		ret = rcar_du_lvdsenc_get_resources(lvds, pdev);
 		if (ret < 0)
 			return ret;
 
 		rcdu->lvds[i] = lvds;
+
+		sprintf(name, "lvds%u", i);
+		if (gpio_is_valid(lvds->gpio_pd))
+			devm_gpio_request_one(&pdev->dev, lvds->gpio_pd,
+					GPIOF_OUT_INIT_LOW, name);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 7a34bf3..63dad00 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -255,6 +255,8 @@
 
 #define DIDSR			0x20028
 #define DIDSR_CODE		(0x7790 << 16)
+#define DIDSR_LCDS0_DCLKIN	(0 << 9)
+#define DIDSR_LCDS0_LVDSIF	(1 << 9)
 #define DIDSR_LCDS_DCLKIN(n)	(0 << (8 + (n) * 2))
 #define DIDSR_LCDS_LVDS0(n)	(2 << (8 + (n) * 2))
 #define DIDSR_LCDS_LVDS1(n)	(3 << (8 + (n) * 2))
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
index 9d7e5c9..0d63275 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -1,7 +1,7 @@
 /*
  * rcar_du_vgacon.c  --  R-Car Display Unit VGA Connector
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -23,7 +23,7 @@
 
 static int rcar_du_vga_connector_get_modes(struct drm_connector *connector)
 {
-	return 0;
+	return drm_add_modes_noedid(connector, 1024, 768);
 }
 
 static const struct drm_connector_helper_funcs connector_helper_funcs = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 8b55e8d..95269b1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -1,7 +1,7 @@
 /*
- * rcar_du_vsp.h  --  R-Car Display Unit VSP-Based Compositor
+ * rcar_du_vsp.c  --  R-Car Display Unit VSP-Based Compositor
  *
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -12,12 +12,14 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/rcar_du_drm.h>
 
 #include <linux/soc/renesas/s2ram_ddr_backup.h>
 #include <linux/of_platform.h>
@@ -932,6 +934,12 @@
 	};
 	unsigned int i;
 
+	if (plane->plane.state->crtc->mode.flags
+				 & DRM_MODE_FLAG_INTERLACE)
+		cfg.interlaced = true;
+	else
+		cfg.interlaced = false;
+
 	cfg.src.left = state->state.src_x >> 16;
 	cfg.src.top = state->state.src_y >> 16;
 	cfg.src.width = state->state.src_w >> 16;
@@ -965,6 +973,7 @@
 	struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
 	struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
 	struct rcar_du_device *rcdu = rplane->vsp->dev;
+	int hdisplay, vdisplay;
 
 	if (!state->fb || !state->crtc) {
 		rstate->format = NULL;
@@ -977,6 +986,19 @@
 		return -EINVAL;
 	}
 
+	hdisplay = state->crtc->mode.hdisplay;
+	vdisplay = state->crtc->mode.vdisplay;
+
+	if ((state->plane->type == DRM_PLANE_TYPE_OVERLAY) &&
+		(((state->crtc_w + state->crtc_x) > hdisplay) ||
+		((state->crtc_h + state->crtc_y) > vdisplay))) {
+		dev_err(rcdu->dev,
+			"%s: specify (%dx%d) + (%d, %d) < (%dx%d).\n",
+			__func__, state->crtc_w, state->crtc_h, state->crtc_x,
+			state->crtc_y, hdisplay, vdisplay);
+		return -EINVAL;
+	}
+
 	rstate->format = rcar_du_format_info(state->fb->pixel_format);
 
 	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) &&
@@ -1089,6 +1111,162 @@
 	return 0;
 }
 
+static int rcar_du_async_commit(struct drm_device *dev, u32 crtc_id)
+{
+	int ret, index;
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	obj = drm_mode_object_find(dev, crtc_id, DRM_MODE_OBJECT_CRTC);
+	if (!obj)
+		return -EINVAL;
+
+	crtc = obj_to_crtc(obj);
+
+	index = drm_crtc_index(crtc);
+
+	crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
+	if (!crtc_state)
+		return -ENOMEM;
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0) {
+		drm_atomic_helper_crtc_destroy_state(crtc, crtc_state);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rcar_du_vsp_write_back(struct drm_device *dev, void *data,
+			   struct drm_file *file_priv)
+{
+	int ret;
+	struct rcar_du_screen_shot *sh = (struct rcar_du_screen_shot *)data;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+	struct rcar_du_crtc *rcrtc;
+	struct rcar_du_device *rcdu;
+	const struct drm_display_mode *mode;
+	u32 pixelformat, bpp;
+	unsigned int pitch;
+	dma_addr_t mem[3];
+
+	obj = drm_mode_object_find(dev, sh->crtc_id, DRM_MODE_OBJECT_CRTC);
+	if (!obj)
+		return -EINVAL;
+
+	crtc = obj_to_crtc(obj);
+	rcrtc = to_rcar_crtc(crtc);
+	rcdu = rcrtc->group->dev;
+	mode = &rcrtc->crtc.state->adjusted_mode;
+
+	switch (sh->fmt) {
+	case DRM_FORMAT_RGB565:
+		bpp = 16;
+		pixelformat = V4L2_PIX_FMT_RGB565;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		bpp = 16;
+		pixelformat = V4L2_PIX_FMT_ARGB555;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		bpp = 32;
+		pixelformat = V4L2_PIX_FMT_ABGR32;
+		break;
+	default:
+		dev_err(rcdu->dev, "specified format is not supported.\n");
+		return -EINVAL;
+	}
+
+	pitch = mode->hdisplay * bpp / 8;
+
+	mem[0] = sh->buff;
+	mem[1] = 0;
+	mem[2] = 0;
+
+	if ((sh->width != (mode->hdisplay)) ||
+		(sh->height != (mode->vdisplay)))
+		return -EINVAL;
+
+	if ((pitch * mode->vdisplay) > sh->buff_len)
+		return -EINVAL;
+
+	vsp1_du_setup_wb(rcrtc->vsp->vsp, pixelformat, pitch, mem);
+	vsp1_du_wait_wb(rcrtc->vsp->vsp, 2);
+
+	ret = rcar_du_async_commit(dev, sh->crtc_id);
+	if (ret != 0)
+		return ret;
+
+	vsp1_du_wait_wb(rcrtc->vsp->vsp, 1);
+
+	ret = rcar_du_async_commit(dev, sh->crtc_id);
+	if (ret != 0)
+		return ret;
+
+	vsp1_du_wait_wb(rcrtc->vsp->vsp, 0);
+
+	return ret;
+}
+
+int rcar_du_set_vmute(struct drm_device *dev, void *data,
+		struct drm_file *file_priv)
+{
+	struct rcar_du_vmute *vmute =
+		(struct rcar_du_vmute *)data;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+	struct rcar_du_crtc *rcrtc;
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	int ret = 0, index;
+
+	dev_dbg(dev->dev, "CRTC[%d], display:%s\n",
+		vmute->crtc_id, vmute->on ? "off":"on");
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	obj = drm_mode_object_find(dev, vmute->crtc_id,
+					DRM_MODE_OBJECT_CRTC);
+	if (!obj)
+		return -EINVAL;
+	crtc = obj_to_crtc(obj);
+
+	index = drm_crtc_index(crtc);
+
+	rcrtc = to_rcar_crtc(crtc);
+	crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
+	if (!crtc_state)
+		return -ENOMEM;
+
+	state->crtc_states[index] = crtc_state;
+	state->crtcs[index] = crtc;
+	crtc_state->state = state;
+
+	crtc_state->active = true;
+
+	vsp1_du_if_set_mute(rcrtc->vsp->vsp, vmute->on);
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
 static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
@@ -1145,6 +1323,15 @@
 
 	vsp->vsp = &pdev->dev;
 
+	/* Locate FCP device behind the VSP for dma_alloc/free. */
+	np = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
+	if (np) {
+		pdev = of_find_device_by_node(np);
+		of_node_put(np);
+		if (pdev)
+			vsp->fcp = &pdev->dev;
+	}
+
 	ret = vsp1_du_init(vsp->vsp);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
index 30b8f8f..8147fdd 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
@@ -29,6 +29,7 @@
 struct rcar_du_vsp {
 	unsigned int index;
 	struct device *vsp;
+	struct device *fcp;
 	struct rcar_du_device *dev;
 	struct rcar_du_vsp_plane *planes;
 	unsigned int num_planes;
@@ -67,6 +68,10 @@
 void rcar_du_vsp_disable(struct rcar_du_crtc *crtc);
 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc);
 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc);
+int rcar_du_set_vmute(struct drm_device *dev, void *data,
+			struct drm_file *file_priv);
+int rcar_du_vsp_write_back(struct drm_device *dev, void *data,
+			struct drm_file *file_priv);
 #ifdef CONFIG_RCAR_DDR_BACKUP
 int rcar_du_vsp_save_regs(struct rcar_du_crtc *crtc);
 int rcar_du_vsp_restore_regs(struct rcar_du_crtc *crtc);
@@ -77,6 +82,10 @@
 static inline void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) { };
 static inline void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc) { };
 static inline void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc) { };
+static inline int rcar_du_set_vmute(struct drm_device *dev, void *data,
+			struct drm_file *file_priv) { return 0; };
+static inline int rcar_du_vsp_write_back(struct drm_device *dev, void *data,
+			struct drm_file *file_priv) { return 0; };
 #ifdef CONFIG_RCAR_DDR_BACKUP
 static inline int rcar_du_vsp_save_regs(struct rcar_du_crtc *crtc)
 	{ return 0; };
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 2dd40dd..8ffb0d7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -985,6 +985,7 @@
 
 config I2C_RCAR
 	tristate "Renesas R-Car I2C Controller"
+	depends on HAS_DMA
 	depends on ARCH_RENESAS || COMPILE_TEST
 	select I2C_SLAVE
 	help
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index eeb8786..54c1722 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -2,7 +2,7 @@
  * Driver for the Renesas RCar I2C unit
  *
  * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
- * Copyright (C) 2011-2015 Renesas Electronics Corporation
+ * Copyright (C) 2011-2016 Renesas Electronics Corporation
  *
  * Copyright (C) 2012-14 Renesas Solutions Corp.
  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
@@ -21,6 +21,8 @@
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -44,6 +46,8 @@
 #define ICSAR	0x1C	/* slave address */
 #define ICMAR	0x20	/* master address */
 #define ICRXTX	0x24	/* data port */
+#define ICDMAER	0x3c	/* DMA enable */
+#define ICFBSCR	0x38	/* first bit setup cycle */
 
 /* ICSCR */
 #define SDBS	(1 << 3)	/* slave data buffer select */
@@ -79,6 +83,16 @@
 #define MDR	(1 << 1)
 #define MAT	(1 << 0)	/* slave addr xfer done */
 
+/* ICDMAER */
+#define RSDMAE	(1 << 3)	/* DMA Slave Received Enable */
+#define TSDMAE	(1 << 2)	/* DMA Slave Transmitted Enable */
+#define RMDMAE	(1 << 1)	/* DMA Master Received Enable */
+#define TMDMAE	(1 << 0)	/* DMA Master Transmitted Enable */
+
+/* ICFBSCR */
+#define TCYC06	0x04		/*  6*Tcyc delay 1st bit between SDA and SCL */
+#define TCYC17	0x0f		/* 17*Tcyc delay 1st bit between SDA and SCL */
+
 
 #define RCAR_BUS_PHASE_START	(MDBS | MIE | ESG)
 #define RCAR_BUS_PHASE_DATA	(MDBS | MIE)
@@ -121,6 +135,12 @@
 	u32 flags;
 	enum rcar_i2c_type devtype;
 	struct i2c_client *slave;
+
+	struct resource *res;
+	struct dma_chan *dma_tx;
+	struct dma_chan *dma_rx;
+	struct scatterlist sg;
+	enum dma_data_direction dma_direction;
 };
 
 #define rcar_i2c_priv_to_dev(p)		((p)->adap.dev.parent)
@@ -522,6 +542,118 @@
 /*
  *		interrupt functions
  */
+static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
+{
+	struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
+		? priv->dma_rx : priv->dma_tx;
+
+	/* Disable DMA Master Received/Transmitted */
+	rcar_i2c_write(priv, ICDMAER, 0);
+
+	/* Reset default delay */
+	rcar_i2c_write(priv, ICFBSCR, TCYC06);
+
+	dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
+			 priv->msg->len, priv->dma_direction);
+
+	priv->dma_direction = DMA_NONE;
+}
+
+static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
+{
+	if (priv->dma_direction == DMA_NONE)
+		return;
+	else if (priv->dma_direction == DMA_FROM_DEVICE)
+		dmaengine_terminate_all(priv->dma_rx);
+	else if (priv->dma_direction == DMA_TO_DEVICE)
+		dmaengine_terminate_all(priv->dma_tx);
+
+	rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma_callback(void *data)
+{
+	struct rcar_i2c_priv *priv = data;
+
+	priv->pos += sg_dma_len(&priv->sg);
+
+	rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
+{
+	struct device *dev = rcar_i2c_priv_to_dev(priv);
+	struct i2c_msg *msg = priv->msg;
+	bool read = msg->flags & I2C_M_RD;
+	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	struct dma_chan *chan = read ? priv->dma_rx : priv->dma_tx;
+	struct dma_async_tx_descriptor *txdesc;
+	dma_addr_t dma_addr;
+	dma_cookie_t cookie;
+	unsigned char *buf;
+	int len;
+
+	/* Do not use DMA if it's not available or for messages < 8 bytes */
+	if (IS_ERR(chan) || msg->len < 8)
+		return;
+
+	if (read) {
+		/*
+		 * The last two bytes needs to be fetched using PIO in
+		 * order for the STOP phase to work.
+		 */
+		buf = priv->msg->buf;
+		len = priv->msg->len - 2;
+	} else {
+		/*
+		 * First byte in message was sent using PIO.
+		 */
+		buf = priv->msg->buf + 1;
+		len = priv->msg->len - 1;
+	}
+
+	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+	if (dma_mapping_error(dev, dma_addr)) {
+		dev_dbg(dev, "dma map failed, using PIO\n");
+		return;
+	}
+
+	sg_dma_len(&priv->sg) = len;
+	sg_dma_address(&priv->sg) = dma_addr;
+
+	priv->dma_direction = dir;
+
+	txdesc = dmaengine_prep_slave_sg(chan, &priv->sg, 1,
+					 read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!txdesc) {
+		dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
+		rcar_i2c_cleanup_dma(priv);
+		return;
+	}
+
+	txdesc->callback = rcar_i2c_dma_callback;
+	txdesc->callback_param = priv;
+
+	cookie = dmaengine_submit(txdesc);
+	if (dma_submit_error(cookie)) {
+		dev_dbg(dev, "submitting dma failed, using PIO\n");
+		rcar_i2c_cleanup_dma(priv);
+		return;
+	}
+
+	/* Set delay for DMA operations */
+	rcar_i2c_write(priv, ICFBSCR, TCYC17);
+
+	/* Enable DMA Master Received/Transmitted */
+	if (read)
+		rcar_i2c_write(priv, ICDMAER, RMDMAE);
+	else
+		rcar_i2c_write(priv, ICDMAER, TMDMAE);
+
+	dma_async_issue_pending(chan);
+}
+
 static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
 {
 	struct i2c_msg *msg = priv->msg;
@@ -541,6 +673,12 @@
 		rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
 		priv->pos++;
 
+		/*
+		 * Try to use DMA to transmit the rest of the data if
+		 * address transfer pashe just finished.
+		 */
+		if (msr & MAT)
+			rcar_i2c_dma(priv);
 	} else {
 		/*
 		 * The last data was pushed to ICRXTX on _PREV_ empty irq.
@@ -575,7 +713,11 @@
 		return;
 
 	if (msr & MAT) {
-		/* Address transfer phase finished, but no data at this point. */
+		/*
+		 * Address transfer phase finished, but no data at this point.
+		 * Try to use DMA to receive data.
+		 */
+		rcar_i2c_dma(priv);
 	} else if (priv->pos < msg->len) {
 		/* get received data */
 		msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
@@ -707,6 +849,81 @@
 	return IRQ_HANDLED;
 }
 
+static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
+					enum dma_transfer_direction dir,
+					dma_addr_t port_addr)
+{
+	struct dma_chan *chan;
+	struct dma_slave_config cfg;
+	char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
+	int ret;
+
+	chan = dma_request_chan(dev, chan_name);
+	if (IS_ERR(chan)) {
+		ret = PTR_ERR(chan);
+		dev_dbg(dev, "request_channel failed for %s (%d)\n",
+			chan_name, ret);
+		return chan;
+	}
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.direction = dir;
+	if (dir == DMA_MEM_TO_DEV) {
+		cfg.dst_addr = port_addr;
+		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	} else {
+		cfg.src_addr = port_addr;
+		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	}
+
+	ret = dmaengine_slave_config(chan, &cfg);
+	if (ret) {
+		dev_dbg(dev, "slave_config failed for %s (%d)\n",
+			chan_name, ret);
+		dma_release_channel(chan);
+		return ERR_PTR(ret);
+	}
+
+	dev_dbg(dev, "got DMA channel for %s\n", chan_name);
+	return chan;
+}
+
+static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
+				 struct i2c_msg *msg)
+{
+	struct device *dev = rcar_i2c_priv_to_dev(priv);
+	bool read;
+	struct dma_chan *chan;
+	enum dma_transfer_direction dir;
+
+	read = msg->flags & I2C_M_RD;
+
+	chan = read ? priv->dma_rx : priv->dma_tx;
+	if (PTR_ERR(chan) != -EPROBE_DEFER)
+		return;
+
+	dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+	chan = rcar_i2c_request_dma_chan(dev, dir, priv->res->start + ICRXTX);
+
+	if (read)
+		priv->dma_rx = chan;
+	else
+		priv->dma_tx = chan;
+}
+
+static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
+{
+	if (!IS_ERR(priv->dma_tx)) {
+		dma_release_channel(priv->dma_tx);
+		priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+	}
+
+	if (!IS_ERR(priv->dma_rx)) {
+		dma_release_channel(priv->dma_rx);
+		priv->dma_rx = ERR_PTR(-EPROBE_DEFER);
+	}
+}
+
 static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 				struct i2c_msg *msgs,
 				int num)
@@ -728,6 +945,7 @@
 			ret = -EOPNOTSUPP;
 			goto out;
 		}
+		rcar_i2c_request_dma(priv, msgs + i);
 	}
 
 	/* init first message */
@@ -739,6 +957,7 @@
 	time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
 				     num * adap->timeout);
 	if (!time_left) {
+		rcar_i2c_cleanup_dma(priv);
 		rcar_i2c_init(priv);
 		ret = -ETIMEDOUT;
 	} else if (priv->flags & ID_NACK) {
@@ -818,6 +1037,7 @@
 	{ .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
 	{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
 	{ .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
+	{ .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@@ -826,7 +1046,6 @@
 {
 	struct rcar_i2c_priv *priv;
 	struct i2c_adapter *adap;
-	struct resource *res;
 	struct device *dev = &pdev->dev;
 	struct i2c_timings i2c_t;
 	int irq, ret;
@@ -841,8 +1060,9 @@
 		return PTR_ERR(priv->clk);
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->io = devm_ioremap_resource(dev, res);
+	priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	priv->io = devm_ioremap_resource(dev, priv->res);
 	if (IS_ERR(priv->io))
 		return PTR_ERR(priv->io);
 
@@ -861,6 +1081,11 @@
 
 	i2c_parse_fw_timings(dev, &i2c_t, false);
 
+	/* Init DMA */
+	sg_init_table(&priv->sg, 1);
+	priv->dma_direction = DMA_NONE;
+	priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	ret = rcar_i2c_clock_calculate(priv, &i2c_t);
@@ -908,6 +1133,7 @@
 	struct device *dev = &pdev->dev;
 
 	i2c_del_adapter(&priv->adap);
+	rcar_i2c_release_dma(priv);
 	if (priv->flags & ID_P_PM_BLOCKED)
 		pm_runtime_put(dev);
 	pm_runtime_disable(dev);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ad08603..295445f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -273,7 +273,6 @@
 
 config IPMMU_VMSA
 	bool "Renesas VMSA-compatible IPMMU"
-	depends on ARM_LPAE
 	depends on ARCH_RENESAS || COMPILE_TEST
 	select IOMMU_API
 	select IOMMU_IO_PGTABLE_LPAE
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 993dc50..19acc7d 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -204,6 +204,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called adv7183.
 
+config VIDEO_ADV7482
+	tristate "Analog Devices ADV7482 HDMI receiver and video decoder"
+	depends on VIDEO_V4L2 && I2C
+	---help---
+	  Support for the Analog Devices ADV7482 HDMI receiver.
+	  Support for the Analog Devices ADV7482 video decoder.
+	  Video capture data is the HD digital signal that is
+	  received by the Analog Devices ADV7482 HDMI receiver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7482.
+
 config VIDEO_ADV7604
 	tristate "Analog Devices ADV7604 decoder"
 	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 94f2c99..a39ee28 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
 obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
+obj-$(CONFIG_VIDEO_ADV7482) += adv7482.o
 obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
 obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
 obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
diff --git a/drivers/media/i2c/adv7482.c b/drivers/media/i2c/adv7482.c
new file mode 100644
index 0000000..0cca208
--- /dev/null
+++ b/drivers/media/i2c/adv7482.c
@@ -0,0 +1,2412 @@
+/*
+ * drivers/media/i2c/adv7482.c
+ *     This file is Analog Devices ADV7482 HDMI receiver driver.
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
+#include <linux/mutex.h>
+#include <media/soc_camera.h>
+
+#include <linux/delay.h>  /* for msleep() */
+
+#define DRIVER_NAME "adv7482"
+
+/****************************************/
+/* ADV7482 I2C slave address definition */
+/****************************************/
+#define ADV7482_I2C_IO			0x70	/* IO Map */
+#define ADV7482_I2C_DPLL		0x26	/* DPLL Map */
+#define ADV7482_I2C_CP			0x22	/* CP Map */
+#define ADV7482_I2C_HDMI		0x34	/* HDMI Map */
+#define ADV7482_I2C_EDID		0x36	/* EDID Map */
+#define ADV7482_I2C_REPEATER		0x32	/* HDMI RX Repeater Map */
+#define ADV7482_I2C_INFOFRAME		0x31	/* HDMI RX InfoFrame Map */
+#define ADV7482_I2C_CEC			0x41	/* CEC Map */
+#define ADV7482_I2C_SDP			0x79	/* SDP Map */
+#define ADV7482_I2C_TXB			0x48	/* CSI-TXB Map */
+#define ADV7482_I2C_TXA			0x4A	/* CSI-TXA Map */
+#define ADV7482_I2C_WAIT		0xFE	/* Wait x mesec */
+#define ADV7482_I2C_EOR			0xFF	/* End Mark */
+
+/****************************************/
+/* ADV7482 IO register definition       */
+/****************************************/
+
+/* Revision */
+#define ADV7482_IO_RD_INFO1_REG	0xDF	/* chip version register */
+#define ADV7482_IO_RD_INFO2_REG	0xE0	/* chip version register */
+
+#define ADV7482_IO_CP_DATAPATH_REG	0x03	/* datapath ctrl */
+#define ADV7482_IO_CP_COLORSPACE_REG	0x04
+#define ADV7482_IO_CP_VID_STD_REG	0x05	/* Video Standard */
+
+/* Power Management */
+#define ADV7482_IO_PWR_MAN_REG	0x0C	/* Power management register */
+#define ADV7482_IO_PWR_ON		0xE0	/* Power on */
+#define ADV7482_IO_PWR_OFF		0x00	/* Power down */
+
+#define ADV7482_HDMI_DDC_PWRDN	0x73	/* Power DDC pads control register */
+#define ADV7482_HDMI_DDC_PWR_ON		0x00	/* Power on */
+#define ADV7482_HDMI_DDC_PWR_OFF	0x01	/* Power down */
+
+#define ADV7482_IO_CP_VID_STD_480I	0x40
+#define ADV7482_IO_CP_VID_STD_576I	0x41
+#define ADV7482_IO_CP_VID_STD_480P	0x4A
+#define ADV7482_IO_CP_VID_STD_576P	0x4B
+#define ADV7482_IO_CP_VID_STD_720P	0x53
+#define ADV7482_IO_CP_VID_STD_1080I	0x54
+#define ADV7482_IO_CP_VID_STD_1080P	0x5E
+#define ADV7482_IO_CP_VID_STD_SVGA56	0x80
+#define ADV7482_IO_CP_VID_STD_SVGA60	0x81
+#define ADV7482_IO_CP_VID_STD_SVGA72	0x82
+#define ADV7482_IO_CP_VID_STD_SVGA75	0x83
+#define ADV7482_IO_CP_VID_STD_SVGA85	0x84
+#define ADV7482_IO_CP_VID_STD_SXGA60	0x85
+#define ADV7482_IO_CP_VID_STD_SXGA75	0x86
+#define ADV7482_IO_CP_VID_STD_VGA60	0x88
+#define ADV7482_IO_CP_VID_STD_VGA72	0x89
+#define ADV7482_IO_CP_VID_STD_VGA75	0x8A
+#define ADV7482_IO_CP_VID_STD_VGA85	0x8B
+#define ADV7482_IO_CP_VID_STD_XGA60	0x8C
+#define ADV7482_IO_CP_VID_STD_XGA70	0x8D
+#define ADV7482_IO_CP_VID_STD_XGA75	0x8E
+#define ADV7482_IO_CP_VID_STD_XGA85	0x8F
+#define ADV7482_IO_CP_VID_STD_UXGA60	0x96
+
+#define ADV7482_IO_CSI4_EN_ENABLE       0x80
+#define ADV7482_IO_CSI4_EN_DISABLE      0x00
+
+#define ADV7482_IO_CSI1_EN_ENABLE       0x40
+#define ADV7482_IO_CSI1_EN_DISABLE      0x00
+
+/****************************************/
+/* ADV7482 CP register definition       */
+/****************************************/
+
+/* Contrast Control */
+#define ADV7482_CP_CON_REG	0x3a	/* Contrast (unsigned) */
+#define ADV7482_CP_CON_MIN	0	/* Minimum contrast */
+#define ADV7482_CP_CON_DEF	128	/* Default */
+#define ADV7482_CP_CON_MAX	255	/* Maximum contrast */
+
+/* Saturation Control */
+#define ADV7482_CP_SAT_REG	0x3b	/* Saturation (unsigned) */
+#define ADV7482_CP_SAT_MIN	0	/* Minimum saturation */
+#define ADV7482_CP_SAT_DEF	128	/* Default */
+#define ADV7482_CP_SAT_MAX	255	/* Maximum saturation */
+
+/* Brightness Control */
+#define ADV7482_CP_BRI_REG	0x3c	/* Brightness (signed) */
+#define ADV7482_CP_BRI_MIN	-128	/* Luma is -512d */
+#define ADV7482_CP_BRI_DEF	0	/* Luma is 0 */
+#define ADV7482_CP_BRI_MAX	127	/* Luma is 508d */
+
+/* Hue Control */
+#define ADV7482_CP_HUE_REG	0x3d	/* Hue (unsigned) */
+#define ADV7482_CP_HUE_MIN	0	/* -90 degree */
+#define ADV7482_CP_HUE_DEF	0	/* -90 degree */
+#define ADV7482_CP_HUE_MAX	255	/* +90 degree */
+
+/* Video adjustment register */
+#define ADV7482_CP_VID_ADJ_REG		0x3e
+/* Video adjustment mask */
+#define ADV7482_CP_VID_ADJ_MASK		0x7F
+/* Enable color controls */
+#define ADV7482_CP_VID_ADJ_ENABLE	0x80
+
+/****************************************/
+/* ADV7482 HDMI register definition     */
+/****************************************/
+
+/* HDMI status register */
+#define ADV7482_HDMI_STATUS1_REG		0x07
+/* VERT_FILTER_LOCKED flag */
+#define ADV7482_HDMI_VF_LOCKED_FLG		0x80
+/* DE_REGEN_FILTER_LOCKED flag */
+#define ADV7482_HDMI_DERF_LOCKED_FLG		0x20
+/* LINE_WIDTH[12:8] mask */
+#define ADV7482_HDMI_LWIDTH_MSBS_MASK		0x1F
+
+/* LINE_WIDTH[7:0] register */
+#define ADV7482_HDMI_LWIDTH_REG			0x08
+
+/* FIELD0_HEIGHT[12:8] register */
+#define ADV7482_HDMI_F0HEIGHT_MSBS_REG		0x09
+/* FIELD0_HEIGHT[12:8] mask */
+#define ADV7482_HDMI_F0HEIGHT_MSBS_MASK		0x1F
+
+/* FIELD0_HEIGHT[7:0] register */
+#define ADV7482_HDMI_F0HEIGHT_LSBS_REG		0x0A
+
+/* HDMI status register */
+#define ADV7482_HDMI_STATUS2_REG		0x0B
+/* DEEP_COLOR_MODE[1:0] mask */
+#define ADV7482_HDMI_DCM_MASK			0xC0
+/* HDMI_INTERLACED flag */
+#define ADV7482_HDMI_IP_FLAG			0x20
+/* FIELD1_HEIGHT[12:8] mask */
+#define ADV7482_HDMI_F1HEIGHT_MSBS_MASK		0x1F
+
+/* FIELD1_HEIGHT[7:0] register */
+#define ADV7482_HDMI_F1HEIGHT_REG		0x0C
+
+struct adv7482_sdp_main_info {
+	u8			status_reg_10;
+};
+
+/****************************************/
+/* ADV7482 SDP register definition      */
+/****************************************/
+
+#define ADV7482_SDP_MAIN_MAP	0x00
+#define ADV7482_SDP_SUB_MAP1	0x20
+#define ADV7482_SDP_SUB_MAP2	0x40
+
+#define ADV7482_SDP_NO_RO_MAIN_MAP	0x00
+#define ADV7482_SDP_RO_MAIN_MAP		0x01
+#define ADV7482_SDP_RO_SUB_MAP1		0x02
+#define ADV7482_SDP_RO_SUB_MAP2		0x03
+
+#define ADV7482_SDP_MAIN_MAP_RW \
+			(ADV7482_SDP_MAIN_MAP | ADV7482_SDP_NO_RO_MAIN_MAP)
+
+#define ADV7482_SDP_STD_AD_PAL_BG_NTSC_J_SECAM		0x0
+#define ADV7482_SDP_STD_AD_PAL_BG_NTSC_J_SECAM_PED	0x1
+#define ADV7482_SDP_STD_AD_PAL_N_NTSC_J_SECAM		0x2
+#define ADV7482_SDP_STD_AD_PAL_N_NTSC_M_SECAM		0x3
+#define ADV7482_SDP_STD_NTSC_J				0x4
+#define ADV7482_SDP_STD_NTSC_M				0x5
+#define ADV7482_SDP_STD_PAL60				0x6
+#define ADV7482_SDP_STD_NTSC_443			0x7
+#define ADV7482_SDP_STD_PAL_BG				0x8
+#define ADV7482_SDP_STD_PAL_N				0x9
+#define ADV7482_SDP_STD_PAL_M				0xa
+#define ADV7482_SDP_STD_PAL_M_PED			0xb
+#define ADV7482_SDP_STD_PAL_COMB_N			0xc
+#define ADV7482_SDP_STD_PAL_COMB_N_PED			0xd
+#define ADV7482_SDP_STD_PAL_SECAM			0xe
+#define ADV7482_SDP_STD_PAL_SECAM_PED			0xf
+
+#define ADV7482_SDP_REG_INPUT_CONTROL		0x00
+#define ADV7482_SDP_INPUT_CONTROL_INSEL_MASK	0x0f
+
+#define ADV7482_SDP_REG_INPUT_VIDSEL		0x02
+
+#define ADV7482_SDP_REG_CTRL			0x0e
+
+#define ADV7482_SDP_REG_PWR_MAN		0x0f
+#define ADV7482_SDP_PWR_MAN_ON		0x00
+#define ADV7482_SDP_PWR_MAN_OFF		0x20
+#define ADV7482_SDP_PWR_MAN_RES		0x80
+
+/* Contrast */
+#define ADV7482_SDP_REG_CON		0x08	/*Unsigned */
+#define ADV7482_SDP_CON_MIN		0
+#define ADV7482_SDP_CON_DEF		128
+#define ADV7482_SDP_CON_MAX		255
+/* Brightness*/
+#define ADV7482_SDP_REG_BRI		0x0a	/*Signed */
+#define ADV7482_SDP_BRI_MIN		-128
+#define ADV7482_SDP_BRI_DEF		0
+#define ADV7482_SDP_BRI_MAX		127
+/* Hue */
+#define ADV7482_SDP_REG_HUE		0x0b	/*Signed, inverted */
+#define ADV7482_SDP_HUE_MIN		-127
+#define ADV7482_SDP_HUE_DEF		0
+#define ADV7482_SDP_HUE_MAX		128
+
+/* Saturation */
+#define ADV7482_SDP_REG_SD_SAT_CB	0xe3
+#define ADV7482_SDP_REG_SD_SAT_CR	0xe4
+#define ADV7482_SDP_SAT_MIN		0
+#define ADV7482_SDP_SAT_DEF		128
+#define ADV7482_SDP_SAT_MAX		255
+
+#define ADV7482_SDP_INPUT_CVBS_AIN1		0x00
+#define ADV7482_SDP_INPUT_CVBS_AIN2		0x01
+#define ADV7482_SDP_INPUT_CVBS_AIN3		0x02
+#define ADV7482_SDP_INPUT_CVBS_AIN4		0x03
+#define ADV7482_SDP_INPUT_CVBS_AIN5		0x04
+#define ADV7482_SDP_INPUT_CVBS_AIN6		0x05
+#define ADV7482_SDP_INPUT_CVBS_AIN7		0x06
+#define ADV7482_SDP_INPUT_CVBS_AIN8		0x07
+#define ADV7482_SDP_INPUT_SVIDEO_AIN1_AIN2	0x08
+#define ADV7482_SDP_INPUT_SVIDEO_AIN3_AIN4	0x09
+#define ADV7482_SDP_INPUT_SVIDEO_AIN5_AIN6	0x0a
+#define ADV7482_SDP_INPUT_SVIDEO_AIN7_AIN8	0x0b
+#define ADV7482_SDP_INPUT_YPRPB_AIN1_AIN2_AIN3	0x0c
+#define ADV7482_SDP_INPUT_YPRPB_AIN4_AIN5_AIN6	0x0d
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN1_AIN2	0x0e
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN3_AIN4	0x0f
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN5_AIN6	0x10
+#define ADV7482_SDP_INPUT_DIFF_CVBS_AIN7_AIN8	0x11
+
+#define ADV7482_SDP_R_REG_10			0x10
+#define ADV7482_SDP_R_REG_10_IN_LOCK		0x01
+#define ADV7482_SDP_R_REG_10_FSC_LOCK		0x04
+
+#define ADV7482_SDP_R_REG_10_AUTOD_MASK		0x70
+#define ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J	0x00
+#define ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43	0x10
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_M	0x20
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_60	0x30
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G	0x40
+#define ADV7482_SDP_R_REG_10_AUTOD_SECAM	0x50
+#define ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB	0x60
+#define ADV7482_SDP_R_REG_10_AUTOD_SECAM_525	0x70
+
+#define ADV7482_MAX_WIDTH		1920
+#define ADV7482_MAX_HEIGHT		1080
+
+/****************************************/
+/* ADV7482 structure definition         */
+/****************************************/
+
+/* Structure for register values */
+struct adv7482_reg_value {
+	u8 addr;				/* i2c slave address */
+	u8 reg;					/* sub (register) address */
+	u8 value;				/* register value */
+};
+
+#define END_REGISTER_TABLE \
+{ADV7482_I2C_EOR, 0xFF, 0xFF} /* End of register table */
+
+/* Register default values */
+
+static const struct adv7482_reg_value adv7482_sw_reset[] = {
+
+	{ADV7482_I2C_IO, 0xFF, 0xFF},	/* SW reset */
+	{ADV7482_I2C_WAIT, 0x00, 0x05},	/* delay 5 */
+	{ADV7482_I2C_IO, 0x01, 0x76},	/* ADI Required Write */
+	{ADV7482_I2C_IO, 0xF2, 0x01},	/* Enable I2C Read Auto-Increment */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_slave_address[] = {
+
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+/* Supported Formats For Script Below */
+/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */
+static const struct adv7482_reg_value adv7482_init_txa_4lane[] = {
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	/* Disable chip powerdown & Enable HDMI Rx block */
+	{ADV7482_I2C_IO, 0x00, 0x40},
+
+	{ADV7482_I2C_REPEATER, 0x40, 0x83},	/* Enable HDCP 1.1 */
+
+	{ADV7482_I2C_HDMI, 0x00, 0x08},	/* Foreground Channel = A */
+	{ADV7482_I2C_HDMI, 0x98, 0xFF},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x99, 0xA3},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9A, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9B, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x9D, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0xCB, 0x09},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3D, 0x10},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3E, 0x7B},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x3F, 0x5E},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x4E, 0xFE},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x4F, 0x18},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x57, 0xA3},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x58, 0x04},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0x85, 0x10},	/* ADI Required Write */
+
+	{ADV7482_I2C_HDMI, 0x83, 0x00},	/* Enable All Terminations */
+	{ADV7482_I2C_HDMI, 0xA3, 0x01},	/* ADI Required Write */
+	{ADV7482_I2C_HDMI, 0xBE, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_HDMI, 0x6C, 0x01},	/* HPA Manual Enable */
+	{ADV7482_I2C_HDMI, 0xF8, 0x01},	/* HPA Asserted */
+	{ADV7482_I2C_HDMI, 0x0F, 0x00},	/* Audio Mute Speed Set to Fastest */
+					/* (Smallest Step Size) */
+
+	/* EDID */
+	/* Header information(0-19th byte) */
+	{ADV7482_I2C_EDID, 0x00, 0x00},	/* Fixed header pattern */
+	{ADV7482_I2C_EDID, 0x01, 0xFF},
+	{ADV7482_I2C_EDID, 0x02, 0xFF},
+	{ADV7482_I2C_EDID, 0x03, 0xFF},
+	{ADV7482_I2C_EDID, 0x04, 0xFF},
+	{ADV7482_I2C_EDID, 0x05, 0xFF},
+	{ADV7482_I2C_EDID, 0x06, 0xFF},
+	{ADV7482_I2C_EDID, 0x07, 0x00},
+	{ADV7482_I2C_EDID, 0x08, 0x00},	/* Manufacturer ID */
+	{ADV7482_I2C_EDID, 0x09, 0x00},
+	{ADV7482_I2C_EDID, 0x0A, 0x00},	/* Manufacturer product code */
+	{ADV7482_I2C_EDID, 0x0B, 0x00},
+	{ADV7482_I2C_EDID, 0x0C, 0x00},	/* Serial number */
+	{ADV7482_I2C_EDID, 0x0D, 0x00},
+	{ADV7482_I2C_EDID, 0x0E, 0x00},
+	{ADV7482_I2C_EDID, 0x0F, 0x00},
+	{ADV7482_I2C_EDID, 0x10, 0x01},	/* Week of manufacture */
+	{ADV7482_I2C_EDID, 0x11, 0x0C},	/* Year of manufacture */
+	{ADV7482_I2C_EDID, 0x12, 0x01},	/* EDID version */
+	{ADV7482_I2C_EDID, 0x13, 0x03},
+	/* Basic display parameters(20-24th byte) */
+	{ADV7482_I2C_EDID, 0x14, 0x80},	/* Video input parameters bitmap */
+	{ADV7482_I2C_EDID, 0x15, 0x50},	/* Maximum horizontal image size */
+	{ADV7482_I2C_EDID, 0x16, 0x2D},	/* Maximum vertical image size */
+	{ADV7482_I2C_EDID, 0x17, 0x78},	/* Display gamma */
+	{ADV7482_I2C_EDID, 0x18, 0x0A},	/* Supported features bitmap */
+	/* Chromaticity coordinates(25-34th byte) */
+	{ADV7482_I2C_EDID, 0x19, 0x0D},
+	{ADV7482_I2C_EDID, 0x1A, 0xC9},
+	{ADV7482_I2C_EDID, 0x1B, 0xA0},
+	{ADV7482_I2C_EDID, 0x1C, 0x57},
+	{ADV7482_I2C_EDID, 0x1D, 0x47},
+	{ADV7482_I2C_EDID, 0x1E, 0x98},
+	{ADV7482_I2C_EDID, 0x1F, 0x27},
+	{ADV7482_I2C_EDID, 0x20, 0x12},
+	{ADV7482_I2C_EDID, 0x21, 0x48},
+	{ADV7482_I2C_EDID, 0x22, 0x4C},
+	/* Established timing bitmap(35-37th byte) */
+	{ADV7482_I2C_EDID, 0x23, 0x20},
+	{ADV7482_I2C_EDID, 0x24, 0x00},
+	{ADV7482_I2C_EDID, 0x25, 0x00},
+	/* Standard timing information(38-53th byte) */
+	/* Because they are unused, in this field, all values are 0101h. */
+	{ADV7482_I2C_EDID, 0x26, 0x01},
+	{ADV7482_I2C_EDID, 0x27, 0x01},
+	{ADV7482_I2C_EDID, 0x28, 0x01},
+	{ADV7482_I2C_EDID, 0x29, 0x01},
+	{ADV7482_I2C_EDID, 0x2A, 0x01},
+	{ADV7482_I2C_EDID, 0x2B, 0x01},
+	{ADV7482_I2C_EDID, 0x2C, 0x01},
+	{ADV7482_I2C_EDID, 0x2D, 0x01},
+	{ADV7482_I2C_EDID, 0x2E, 0x01},
+	{ADV7482_I2C_EDID, 0x2F, 0x01},
+	{ADV7482_I2C_EDID, 0x30, 0x01},
+	{ADV7482_I2C_EDID, 0x31, 0x01},
+	{ADV7482_I2C_EDID, 0x32, 0x01},
+	{ADV7482_I2C_EDID, 0x33, 0x01},
+	{ADV7482_I2C_EDID, 0x34, 0x01},
+	{ADV7482_I2C_EDID, 0x35, 0x01},
+	/* Descriptor blocks of Descriptor 1(54-71th byte) */
+	{ADV7482_I2C_EDID, 0x36, 0x02},
+	{ADV7482_I2C_EDID, 0x37, 0x3A},
+	{ADV7482_I2C_EDID, 0x38, 0x80},
+	{ADV7482_I2C_EDID, 0x39, 0x18},
+	{ADV7482_I2C_EDID, 0x3A, 0x71},
+	{ADV7482_I2C_EDID, 0x3B, 0x38},
+	{ADV7482_I2C_EDID, 0x3C, 0x2D},
+	{ADV7482_I2C_EDID, 0x3D, 0x40},
+	{ADV7482_I2C_EDID, 0x3E, 0x58},
+	{ADV7482_I2C_EDID, 0x3F, 0x2C},
+	{ADV7482_I2C_EDID, 0x40, 0x45},
+	{ADV7482_I2C_EDID, 0x41, 0x00},
+	{ADV7482_I2C_EDID, 0x42, 0xDC},
+	{ADV7482_I2C_EDID, 0x43, 0x0B},
+	{ADV7482_I2C_EDID, 0x44, 0x11},
+	{ADV7482_I2C_EDID, 0x45, 0x00},
+	{ADV7482_I2C_EDID, 0x46, 0x00},
+	{ADV7482_I2C_EDID, 0x47, 0x1E},
+	/* Descriptor blocks of Descriptor 2(72-89th byte) */
+	{ADV7482_I2C_EDID, 0x48, 0x8C},
+	{ADV7482_I2C_EDID, 0x49, 0x0A},
+	{ADV7482_I2C_EDID, 0x4A, 0xD0},
+	{ADV7482_I2C_EDID, 0x4B, 0x8A},
+	{ADV7482_I2C_EDID, 0x4C, 0x20},
+	{ADV7482_I2C_EDID, 0x4D, 0xE0},
+	{ADV7482_I2C_EDID, 0x4E, 0x2D},
+	{ADV7482_I2C_EDID, 0x4F, 0x10},
+	{ADV7482_I2C_EDID, 0x50, 0x10},
+	{ADV7482_I2C_EDID, 0x51, 0x3E},
+	{ADV7482_I2C_EDID, 0x52, 0x96},
+	{ADV7482_I2C_EDID, 0x53, 0x00},
+	{ADV7482_I2C_EDID, 0x54, 0x58},
+	{ADV7482_I2C_EDID, 0x55, 0xC2},
+	{ADV7482_I2C_EDID, 0x56, 0x21},
+	{ADV7482_I2C_EDID, 0x57, 0x00},
+	{ADV7482_I2C_EDID, 0x58, 0x00},
+	{ADV7482_I2C_EDID, 0x59, 0x18},
+	/* Descriptor blocks of Descriptor 3(90-107th byte) */
+	{ADV7482_I2C_EDID, 0x5A, 0x00},
+	{ADV7482_I2C_EDID, 0x5B, 0x00},
+	{ADV7482_I2C_EDID, 0x5C, 0x00},
+	{ADV7482_I2C_EDID, 0x5D, 0x7C},
+	{ADV7482_I2C_EDID, 0x5E, 0x00},
+	{ADV7482_I2C_EDID, 0x5F, 0x4D},
+	{ADV7482_I2C_EDID, 0x60, 0x59},
+	{ADV7482_I2C_EDID, 0x61, 0x20},
+	{ADV7482_I2C_EDID, 0x62, 0x48},
+	{ADV7482_I2C_EDID, 0x63, 0x44},
+	{ADV7482_I2C_EDID, 0x64, 0x54},
+	{ADV7482_I2C_EDID, 0x65, 0x56},
+	{ADV7482_I2C_EDID, 0x66, 0x0A},
+	{ADV7482_I2C_EDID, 0x67, 0x20},
+	{ADV7482_I2C_EDID, 0x68, 0x20},
+	{ADV7482_I2C_EDID, 0x69, 0x20},
+	{ADV7482_I2C_EDID, 0x6A, 0x20},
+	{ADV7482_I2C_EDID, 0x6B, 0x20},
+	/* Descriptor blocks of Descriptor 4(108-125th byte) */
+	{ADV7482_I2C_EDID, 0x6C, 0x00},
+	{ADV7482_I2C_EDID, 0x6D, 0x00},
+	{ADV7482_I2C_EDID, 0x6E, 0x00},
+	{ADV7482_I2C_EDID, 0x6F, 0x00},
+	{ADV7482_I2C_EDID, 0x70, 0x00},
+	{ADV7482_I2C_EDID, 0x71, 0x00},
+	{ADV7482_I2C_EDID, 0x72, 0x00},
+	{ADV7482_I2C_EDID, 0x73, 0x0A},
+	{ADV7482_I2C_EDID, 0x74, 0x2E},
+	{ADV7482_I2C_EDID, 0x75, 0x06},
+	{ADV7482_I2C_EDID, 0x76, 0x00},
+	{ADV7482_I2C_EDID, 0x77, 0x0A},
+	{ADV7482_I2C_EDID, 0x78, 0x20},
+	{ADV7482_I2C_EDID, 0x79, 0x20},
+	{ADV7482_I2C_EDID, 0x7A, 0x20},
+	{ADV7482_I2C_EDID, 0x7B, 0x20},
+	{ADV7482_I2C_EDID, 0x7C, 0x20},
+	{ADV7482_I2C_EDID, 0x7D, 0x20},
+	/* Number of extensions to follow(126th byte) */
+	{ADV7482_I2C_EDID, 0x7E, 0x01},	/* Extension enable */
+	/* Checksum(127th byte) */
+	{ADV7482_I2C_EDID, 0x7F, 0x75},
+
+	/* CEA EDID Timing Extension Version 3 */
+	{ADV7482_I2C_EDID, 0x80, 0x02},	/* CEA 861 Externsion Block */
+	{ADV7482_I2C_EDID, 0x81, 0x03},
+	{ADV7482_I2C_EDID, 0x82, 0x1E},
+	{ADV7482_I2C_EDID, 0x83, 0x40},
+	{ADV7482_I2C_EDID, 0x84, 0x83},
+	{ADV7482_I2C_EDID, 0x85, 0x7F},
+	{ADV7482_I2C_EDID, 0x86, 0x40},
+	{ADV7482_I2C_EDID, 0x87, 0x05},
+	{ADV7482_I2C_EDID, 0x88, 0x40},
+	{ADV7482_I2C_EDID, 0x89, 0x48},
+	{ADV7482_I2C_EDID, 0x8A, 0x10},	/* 1920x1080p @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x8B, 0x05},	/* 1920x1080i @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x8C, 0x04},	/* 1280x720p @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x8D, 0x01},	/* 640x480p @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x8E, 0x02},	/* 720x480p @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x8F, 0x06},	/* 720(1440)x480i @ 59.94/60 Hz */
+	{ADV7482_I2C_EDID, 0x90, 0x15},	/* 720(1440)x576i @ 50 Hz */
+	{ADV7482_I2C_EDID, 0x91, 0x11},	/* 720x576p @ 50 Hz */
+	{ADV7482_I2C_EDID, 0x92, 0x00},
+	{ADV7482_I2C_EDID, 0x93, 0x00},
+	{ADV7482_I2C_EDID, 0x94, 0x00},
+	{ADV7482_I2C_EDID, 0x95, 0x00},
+	{ADV7482_I2C_EDID, 0x96, 0x00},
+	{ADV7482_I2C_EDID, 0x97, 0x00},
+	{ADV7482_I2C_EDID, 0x98, 0x00},
+	{ADV7482_I2C_EDID, 0x99, 0x00},
+	{ADV7482_I2C_EDID, 0x9A, 0x00},
+	{ADV7482_I2C_EDID, 0x9B, 0x00},
+	{ADV7482_I2C_EDID, 0x9C, 0x00},
+	{ADV7482_I2C_EDID, 0x9D, 0x00},
+	{ADV7482_I2C_EDID, 0x9E, 0x00},
+	{ADV7482_I2C_EDID, 0x9F, 0x00},
+	{ADV7482_I2C_EDID, 0xA0, 0x00},
+	{ADV7482_I2C_EDID, 0xA1, 0x00},
+	{ADV7482_I2C_EDID, 0xA2, 0x00},
+	{ADV7482_I2C_EDID, 0xA3, 0x00},
+	{ADV7482_I2C_EDID, 0xA4, 0x00},
+	{ADV7482_I2C_EDID, 0xA5, 0x00},
+	{ADV7482_I2C_EDID, 0xA6, 0x00},
+	{ADV7482_I2C_EDID, 0xA7, 0x00},
+	{ADV7482_I2C_EDID, 0xA8, 0x00},
+	{ADV7482_I2C_EDID, 0xA9, 0x00},
+	{ADV7482_I2C_EDID, 0xAA, 0x00},
+	{ADV7482_I2C_EDID, 0xAB, 0x00},
+	{ADV7482_I2C_EDID, 0xAC, 0x00},
+	{ADV7482_I2C_EDID, 0xAD, 0x00},
+	{ADV7482_I2C_EDID, 0xAE, 0x00},
+	{ADV7482_I2C_EDID, 0xAF, 0x00},
+	{ADV7482_I2C_EDID, 0xB0, 0x00},
+	{ADV7482_I2C_EDID, 0xB1, 0x00},
+	{ADV7482_I2C_EDID, 0xB2, 0x00},
+	{ADV7482_I2C_EDID, 0xB3, 0x00},
+	{ADV7482_I2C_EDID, 0xB4, 0x00},
+	{ADV7482_I2C_EDID, 0xB5, 0x00},
+	{ADV7482_I2C_EDID, 0xB6, 0x00},
+	{ADV7482_I2C_EDID, 0xB7, 0x00},
+	{ADV7482_I2C_EDID, 0xB8, 0x00},
+	{ADV7482_I2C_EDID, 0xB9, 0x00},
+	{ADV7482_I2C_EDID, 0xBA, 0x20},
+	{ADV7482_I2C_EDID, 0xBB, 0x20},
+	{ADV7482_I2C_EDID, 0xBC, 0x20},
+	{ADV7482_I2C_EDID, 0xBD, 0x20},
+	{ADV7482_I2C_EDID, 0xBE, 0x20},
+	{ADV7482_I2C_EDID, 0xBF, 0x20},
+	{ADV7482_I2C_EDID, 0xC0, 0x20},
+	{ADV7482_I2C_EDID, 0xC1, 0x20},
+	{ADV7482_I2C_EDID, 0xC2, 0x20},
+	{ADV7482_I2C_EDID, 0xC3, 0x20},
+	{ADV7482_I2C_EDID, 0xC4, 0x20},
+	{ADV7482_I2C_EDID, 0xC5, 0x20},
+	{ADV7482_I2C_EDID, 0xC6, 0x00},
+	{ADV7482_I2C_EDID, 0xC7, 0x00},
+	{ADV7482_I2C_EDID, 0xC8, 0x00},
+	{ADV7482_I2C_EDID, 0xC9, 0xFF},
+	{ADV7482_I2C_EDID, 0xCA, 0x00},
+	{ADV7482_I2C_EDID, 0xCB, 0x0A},
+	{ADV7482_I2C_EDID, 0xCC, 0x20},
+	{ADV7482_I2C_EDID, 0xCD, 0x20},
+	{ADV7482_I2C_EDID, 0xCE, 0x20},
+	{ADV7482_I2C_EDID, 0xCF, 0x20},
+	{ADV7482_I2C_EDID, 0xD0, 0x20},
+	{ADV7482_I2C_EDID, 0xD1, 0x20},
+	{ADV7482_I2C_EDID, 0xD2, 0x20},
+	{ADV7482_I2C_EDID, 0xD3, 0x20},
+	{ADV7482_I2C_EDID, 0xD4, 0x20},
+	{ADV7482_I2C_EDID, 0xD5, 0x20},
+	{ADV7482_I2C_EDID, 0xD6, 0x20},
+	{ADV7482_I2C_EDID, 0xD7, 0x20},
+	{ADV7482_I2C_EDID, 0xD8, 0x00},
+	{ADV7482_I2C_EDID, 0xD9, 0x00},
+	{ADV7482_I2C_EDID, 0xDA, 0x00},
+	{ADV7482_I2C_EDID, 0xDB, 0x1B},
+	{ADV7482_I2C_EDID, 0xDC, 0x00},
+	{ADV7482_I2C_EDID, 0xDD, 0x0A},
+	{ADV7482_I2C_EDID, 0xDE, 0x20},
+	{ADV7482_I2C_EDID, 0xDF, 0x20},
+	{ADV7482_I2C_EDID, 0xE0, 0x20},
+	{ADV7482_I2C_EDID, 0xE1, 0x20},
+	{ADV7482_I2C_EDID, 0xE2, 0x20},
+	{ADV7482_I2C_EDID, 0xE3, 0x20},
+	{ADV7482_I2C_EDID, 0xE4, 0x20},
+	{ADV7482_I2C_EDID, 0xE5, 0x20},
+	{ADV7482_I2C_EDID, 0xE6, 0x20},
+	{ADV7482_I2C_EDID, 0xE7, 0x20},
+	{ADV7482_I2C_EDID, 0xE8, 0x20},
+	{ADV7482_I2C_EDID, 0xE9, 0x20},
+	{ADV7482_I2C_EDID, 0xEA, 0x00},
+	{ADV7482_I2C_EDID, 0xEB, 0x00},
+	{ADV7482_I2C_EDID, 0xEC, 0x00},
+	{ADV7482_I2C_EDID, 0xED, 0x00},
+	{ADV7482_I2C_EDID, 0xEE, 0x00},
+	{ADV7482_I2C_EDID, 0xEF, 0x00},
+	{ADV7482_I2C_EDID, 0xF0, 0x00},
+	{ADV7482_I2C_EDID, 0xF1, 0x00},
+	{ADV7482_I2C_EDID, 0xF2, 0x00},
+	{ADV7482_I2C_EDID, 0xF3, 0x00},
+	{ADV7482_I2C_EDID, 0xF4, 0x00},
+	{ADV7482_I2C_EDID, 0xF5, 0x00},
+	{ADV7482_I2C_EDID, 0xF6, 0x00},
+	{ADV7482_I2C_EDID, 0xF7, 0x00},
+	{ADV7482_I2C_EDID, 0xF8, 0x00},
+	{ADV7482_I2C_EDID, 0xF9, 0x00},
+	{ADV7482_I2C_EDID, 0xFA, 0x00},
+	{ADV7482_I2C_EDID, 0xFB, 0x00},
+	{ADV7482_I2C_EDID, 0xFC, 0x00},
+	{ADV7482_I2C_EDID, 0xFD, 0x00},
+	{ADV7482_I2C_EDID, 0xFE, 0x00},
+	{ADV7482_I2C_EDID, 0xFF, 0xD8},	/* Set the Most Significant Bit */
+
+	{ADV7482_I2C_REPEATER, 0x70, 0x10},
+					/* EDID image, in 128-byte blocks. */
+	{ADV7482_I2C_REPEATER, 0x74, 0x01},
+				/* Manual enable active for E-EDID on Port A */
+
+	{ADV7482_I2C_IO, 0x04, 0x02},	/* RGB Out of CP */
+	{ADV7482_I2C_IO, 0x12, 0xF0},
+		/* CSC Depends on ip Packets - SDR 444 */
+	{ADV7482_I2C_IO, 0x17, 0x80},
+		/* Luma & Chroma Values Can Reach 254d */
+	{ADV7482_I2C_IO, 0x03, 0x86},	/* CP-Insert_AV_Code */
+
+	{ADV7482_I2C_CP, 0x7C, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_IO, 0x0C, 0xE0},	/* Enable LLC_DLL & Double LLC Timing */
+	{ADV7482_I2C_IO, 0x0E, 0xDD},	/* LLC/PIX/SPI PINS TRISTATED AUD */
+					/* Outputs Enabled */
+	{ADV7482_I2C_IO, 0x10, 0xA0},	/* Enable 4-lane CSI Tx & Pixel Port */
+
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0x00, 0xA4},	/* Set Auto DPHY Timing */
+	{ADV7482_I2C_TXA, 0xDB, 0x10},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD6, 0x07},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC4, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x71, 0x33},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x72, 0x11},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xF0, 0x00},	/* i2c_dphy_pwdn - 1'b0 */
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXA, 0x00, 0x24 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0x31, 0x80},	/* ADI Required Write */
+
+	/* for debug */
+#ifdef REL_DGB_FORCE_TO_SEND_COLORBAR
+	{ADV7482_I2C_CP, 0x37, 0x81},	/* Output Colorbars Pattern */
+#endif
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+/* 02-01 Analog CVBS to MIPI TX-B CSI 1-Lane - */
+/* Autodetect CVBS Single Ended In Ain 1 - MIPI Out */
+static const struct adv7482_reg_value adv7482_init_txb_1lane[] = {
+
+	{ADV7482_I2C_IO, 0x00, 0x30},
+		/* Disable chip powerdown - powerdown Rx */
+	{ADV7482_I2C_IO, 0xF2, 0x01},	/* Enable I2C Read Auto-Increment */
+
+	/* I2C Slave Address settings */
+	{ADV7482_I2C_IO, 0xF3, ADV7482_I2C_DPLL * 2},	/* DPLL Map */
+	{ADV7482_I2C_IO, 0xF4, ADV7482_I2C_CP * 2},	/* CP Map */
+	{ADV7482_I2C_IO, 0xF5, ADV7482_I2C_HDMI * 2},	/* HDMI Map */
+	{ADV7482_I2C_IO, 0xF6, ADV7482_I2C_EDID * 2},	/* EDID Map */
+	{ADV7482_I2C_IO, 0xF7, ADV7482_I2C_REPEATER * 2},
+						/* HDMI RX Repeater Map */
+	{ADV7482_I2C_IO, 0xF8, ADV7482_I2C_INFOFRAME * 2},
+						/* HDMI RX InfoFrame Map */
+	{ADV7482_I2C_IO, 0xFA, ADV7482_I2C_CEC * 2},	/* CEC Map */
+	{ADV7482_I2C_IO, 0xFB, ADV7482_I2C_SDP * 2},	/* SDP Map */
+	{ADV7482_I2C_IO, 0xFC, ADV7482_I2C_TXB * 2},	/* CSI-TXB Map */
+	{ADV7482_I2C_IO, 0xFD, ADV7482_I2C_TXA * 2},	/* CSI-TXA Map */
+
+	{ADV7482_I2C_IO, 0x0E, 0xFF},	/* LLC/PIX/AUD/SPI PINS TRISTATED */
+
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_PWR_MAN, ADV7482_SDP_PWR_MAN_ON},
+		/* Exit Power Down Mode */
+	{ADV7482_I2C_SDP, 0x52, 0xCD},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_INPUT_CONTROL,
+		ADV7482_SDP_INPUT_CVBS_AIN8},	/* INSEL = CVBS in on Ain 8 */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_CTRL, 0x80},
+		/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x9C, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x9C, 0xFF},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, ADV7482_SDP_REG_CTRL, ADV7482_SDP_MAIN_MAP_RW},
+		/* ADI Required Write */
+
+	/* ADI recommended writes for improved video quality */
+	{ADV7482_I2C_SDP, 0x80, 0x51},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x81, 0x51},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0x82, 0x68},	/* ADI Required Write */
+
+	{ADV7482_I2C_SDP, 0x03, 0x42},
+		/* Tri-S Output Drivers, PwrDwn 656 pads */
+	{ADV7482_I2C_SDP, 0x04, 0xB5},	/* ITU-R BT.656-4 compatible */
+	{ADV7482_I2C_SDP, 0x13, 0x00},	/* ADI Required Write */
+
+	{ADV7482_I2C_SDP, 0x17, 0x41},	/* Select SH1 */
+	{ADV7482_I2C_SDP, 0x31, 0x12},	/* ADI Required Write */
+	{ADV7482_I2C_SDP, 0xE6, 0x4F},
+		/* Set V bit end position manually in NTSC mode */
+
+#ifdef REL_DGB_FORCE_TO_SEND_COLORBAR
+	{ADV7482_I2C_SDP, 0x0C, 0x01},	/* ColorBar */
+	{ADV7482_I2C_SDP, 0x14, 0x01},	/* ColorBar */
+#endif
+	/* Enable 1-Lane MIPI Tx, */
+	/* enable pixel output and route SD through Pixel port */
+	{ADV7482_I2C_IO, 0x10, 0x70},
+
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 1-lane MIPI */
+	{ADV7482_I2C_TXB, 0x00, 0xA1},	/* Set Auto DPHY Timing */
+#if 0 /* If CVBS input only is used, please enable this code. */
+	{ADV7482_I2C_TXA, 0xF0, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD6, 0x07},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC0, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC3, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC6, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xC9, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xCC, 0x3C},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xD5, 0x03},	/* ADI Required Write */
+#endif
+	{ADV7482_I2C_TXB, 0xD2, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xC4, 0x0A},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x71, 0x33},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x72, 0x11},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xF0, 0x00},	/* i2c_dphy_pwdn - 1'b0 */
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXB, 0x00, 0x21 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_txa_4lane[] = {
+
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0x00, 0xA4},	/* Set Auto DPHY Timing */
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXA, 0x00, 0x24 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXA, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_txa_4lane[] = {
+
+	{ADV7482_I2C_TXA, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x1E, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXA, 0x00, 0x84},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXA, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_TXA, 0xC1, 0x3B},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_txb_1lane[] = {
+
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 1-lane MIPI */
+	{ADV7482_I2C_TXB, 0x00, 0xA1},	/* Set Auto DPHY Timing */
+
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x40},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_WAIT, 0x00, 0x02},	/* delay 2 */
+	{ADV7482_I2C_TXB, 0x00, 0x21 },	/* Power-up CSI-TX */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x2B},	/* ADI Required Write */
+	{ADV7482_I2C_WAIT, 0x00, 0x01},	/* delay 1 */
+	{ADV7482_I2C_TXB, 0x31, 0x80},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_txb_1lane[] = {
+
+	{ADV7482_I2C_TXB, 0x31, 0x82},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x1E, 0x00},	/* ADI Required Write */
+	{ADV7482_I2C_TXB, 0x00, 0x81},	/* Enable 4-lane MIPI */
+	{ADV7482_I2C_TXB, 0xDA, 0x01},	/* i2c_mipi_pll_en - 1'b1 */
+	{ADV7482_I2C_TXB, 0xC1, 0x3B},	/* ADI Required Write */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_up_hdmi_rx[] = {
+
+	/* Disable chip powerdown & Enable HDMI Rx block */
+	{ADV7482_I2C_IO, 0x00, 0x40},
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_power_down_hdmi_rx[] = {
+
+	{ADV7482_I2C_IO, 0x00, 0x30},	/* Disable chip powerdown */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_enable_csi4_csi1[] = {
+
+	{ADV7482_I2C_IO, 0x10, 0xE0},	/* Enable 4-lane CSI Tx & Pixel Port */
+
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel0[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x00},	/* Set virtual channel 0 */
+	{ADV7482_I2C_TXA, 0x0D, 0x00},	/* Set virtual channel 0 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel1[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x40},	/* Set virtual channel 1 */
+	{ADV7482_I2C_TXA, 0x0D, 0x40},	/* Set virtual channel 1 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel2[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0x80},	/* Set virtual channel 2 */
+	{ADV7482_I2C_TXA, 0x0D, 0x80},	/* Set virtual channel 2 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+static const struct adv7482_reg_value adv7482_set_virtual_channel3[] = {
+
+	{ADV7482_I2C_TXB, 0x0D, 0xC0},	/* Set virtual channel 3 */
+	{ADV7482_I2C_TXA, 0x0D, 0xC0},	/* Set virtual channel 3 */
+	{ADV7482_I2C_EOR, 0xFF, 0xFF}	/* End of register table */
+};
+
+enum decoder_input_interface {
+	DECODER_INPUT_INTERFACE_RGB888,
+	DECODER_INPUT_INTERFACE_YCBCR422,
+};
+
+/**
+ * struct adv7482_link_config - Describes adv7482 hardware configuration
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ */
+struct adv7482_link_config {
+	enum decoder_input_interface	input_interface;
+	struct adv7482_reg_value	*regs;
+
+	struct adv7482_reg_value	*power_up;
+	struct adv7482_reg_value	*power_down;
+
+	int (*init_device)(void *);
+	int (*init_controls)(void *);
+	int (*s_power)(void *);
+	int (*s_ctrl)(void *);
+	int (*enum_mbus_code)(void *);
+	int (*set_pad_format)(void *);
+	int (*get_pad_format)(void *);
+	int (*s_std)(void *);
+	int (*querystd)(void *);
+	int (*g_input_status)(void *);
+	int (*s_routing)(void *);
+	int (*g_mbus_config)(void *);
+
+	struct device	*dev;
+	bool		sw_reset;
+	bool		hdmi_in;
+	bool		sdp_in;
+	int		vc_ch;
+};
+
+struct adv7482_state {
+	struct v4l2_ctrl_handler		ctrl_hdl;
+	struct v4l2_subdev			sd;
+	struct media_pad			pad;
+	 /* mutual excl. when accessing chip */
+	struct mutex				mutex;
+	int					irq;
+	v4l2_std_id				curr_norm;
+	bool					autodetect;
+	bool					powered;
+	const struct adv7482_color_format	*cfmt;
+	u32					width;
+	u32					height;
+
+	struct i2c_client			*client;
+	unsigned int				register_page;
+	struct i2c_client			*csi_client;
+	enum v4l2_field				field;
+
+	struct device				*dev;
+	struct adv7482_link_config		mipi_csi2_link[2];
+};
+
+/*****************************************************************************/
+/*  Private functions                                                        */
+/*****************************************************************************/
+
+#define to_adv7482_sd(_ctrl) (&container_of(_ctrl->handler,		\
+					    struct adv7482_state,	\
+					    ctrl_hdl)->sd)
+
+static inline struct adv7482_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7482_state, sd);
+}
+
+/*
+ * adv7482_write_registers() - Write adv7482 device registers
+ * @client: pointer to i2c_client structure
+ * @regs: pointer to adv7482_reg_value structure
+ *
+ * Write the specified adv7482 register's values.
+ */
+static int adv7482_write_registers(struct i2c_client *client,
+					const struct adv7482_reg_value *regs)
+{
+	struct i2c_msg msg;
+	u8 data_buf[2];
+	int ret = -EINVAL;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &data_buf[0];
+
+	while (regs->addr != ADV7482_I2C_EOR) {
+
+		if (regs->addr == ADV7482_I2C_WAIT)
+			msleep(regs->value);
+		else {
+			msg.addr = regs->addr;
+			data_buf[0] = regs->reg;
+			data_buf[1] = regs->value;
+
+			ret = i2c_transfer(client->adapter, &msg, 1);
+			if (ret < 0)
+				break;
+		}
+		regs++;
+	}
+
+	return (ret < 0) ? ret : 0;
+}
+
+/*
+ * adv7482_write_register() - Write adv7482 device register
+ * @client: pointer to i2c_client structure
+ * @addr: i2c slave address of adv7482 device
+ * @reg: adv7482 device register address
+ * @value: the value to be written
+ *
+ * Write the specified adv7482 register's value.
+ */
+static int adv7482_write_register(struct i2c_client *client,
+		u8 addr, u8 reg, u8 value)
+{
+	struct adv7482_reg_value regs[2];
+	int ret;
+
+	regs[0].addr = addr;
+	regs[0].reg = reg;
+	regs[0].value = value;
+	regs[1].addr = ADV7482_I2C_EOR;
+	regs[1].reg = 0xFF;
+	regs[1].value = 0xFF;
+
+	ret = adv7482_write_registers(client, regs);
+
+	return ret;
+}
+
+/*
+ * adv7482_read_register() - Read adv7482 device register
+ * @client: pointer to i2c_client structure
+ * @addr: i2c slave address of adv7482 device
+ * @reg: adv7482 device register address
+ * @value: pointer to the value
+ *
+ * Read the specified adv7482 register's value.
+ */
+static int adv7482_read_register(struct i2c_client *client,
+		u8 addr, u8 reg, u8 *value)
+{
+	struct i2c_msg msg[2];
+	u8 reg_buf, data_buf;
+	int ret;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg[0].addr = addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &reg_buf;
+	msg[1].addr = addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 1;
+	msg[1].buf = &data_buf;
+
+	reg_buf = reg;
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	*value = data_buf;
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int adv7482_read_sdp_main_info(struct i2c_client *client,
+		struct adv7482_sdp_main_info *info)
+{
+	int ret;
+	u8 value;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+				ADV7482_SDP_REG_CTRL, ADV7482_SDP_RO_MAIN_MAP);
+	if (ret < 0)
+		return ret;
+
+	/* status_reg_10 */
+	ret = adv7482_read_register(client, ADV7482_I2C_SDP,
+			ADV7482_SDP_R_REG_10, &value);
+	if (ret < 0)
+		return ret;
+
+	info->status_reg_10 = value;
+
+	return ret;
+}
+
+static v4l2_std_id adv7482_std_to_v4l2(u8 status_reg_10)
+{
+	/* in case V4L2_IN_ST_NO_SIGNAL */
+	if (!(status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK))
+		return V4L2_STD_UNKNOWN;
+
+	switch (status_reg_10 & ADV7482_SDP_R_REG_10_AUTOD_MASK) {
+	case ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J:
+		return V4L2_STD_NTSC;
+	case ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43:
+		return V4L2_STD_NTSC_443;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_M:
+		return V4L2_STD_PAL_M;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_60:
+		return V4L2_STD_PAL_60;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G:
+		return V4L2_STD_PAL;
+	case ADV7482_SDP_R_REG_10_AUTOD_SECAM:
+		return V4L2_STD_SECAM;
+	case ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB:
+		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
+	case ADV7482_SDP_R_REG_10_AUTOD_SECAM_525:
+		return V4L2_STD_SECAM;
+	default:
+		return V4L2_STD_UNKNOWN;
+	}
+}
+
+static u32 adv7482_status_to_v4l2(u8 status_reg_10)
+{
+	if (!(status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK))
+		return V4L2_IN_ST_NO_SIGNAL;
+
+	return 0;
+}
+
+static int __adv7482_status(struct adv7482_state *state, u32 *status,
+			    v4l2_std_id *std)
+{
+	int ret;
+	u8 status_reg_10;
+	struct adv7482_sdp_main_info sdp_info;
+
+	ret = adv7482_read_sdp_main_info(state->client, &sdp_info);
+	if (ret < 0)
+		return ret;
+
+	status_reg_10 = sdp_info.status_reg_10;
+
+	if (status_reg_10 < 0)
+		return (int)status_reg_10;
+
+	if (status)
+		*status = adv7482_status_to_v4l2(status_reg_10);
+	if (std)
+		*std = adv7482_std_to_v4l2(status_reg_10);
+
+	return 0;
+}
+
+/*
+ * adv7482_get_vid_info() - Get video information
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @progressive: progressive or interlace
+ * @width: line width
+ * @height: lines per frame
+ *
+ * Get video information.
+ */
+static int adv7482_get_vid_info(struct v4l2_subdev *sd, u8 *progressive,
+				u32 *width, u32 *height, u8 *signal)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u8 hdmi_int;
+	u8 msb;
+	u8 lsb;
+	int ret;
+
+	if (signal)
+		*signal = 0;
+
+	/* decide line width */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_STATUS1_REG, &msb);
+	if (ret < 0)
+		return ret;
+
+	if (!(msb & ADV7482_HDMI_VF_LOCKED_FLG) ||
+	    !(msb & ADV7482_HDMI_DERF_LOCKED_FLG))
+		return -EIO;
+
+	if (signal)
+		*signal = 1;
+
+	/* decide interlaced or progressive */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_STATUS2_REG, &hdmi_int);
+	if (ret < 0)
+		return ret;
+
+	*progressive =  1;
+	if ((hdmi_int & ADV7482_HDMI_IP_FLAG) != 0)
+		*progressive =  0;
+
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_LWIDTH_REG, &lsb);
+	if (ret < 0)
+		return ret;
+
+	*width = (u32)(ADV7482_HDMI_LWIDTH_MSBS_MASK & msb);
+	*width = (lsb | (*width << 8));
+
+	/* decide lines per frame */
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_F0HEIGHT_MSBS_REG, &msb);
+	if (ret < 0)
+		return ret;
+
+	ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+			ADV7482_HDMI_F0HEIGHT_LSBS_REG, &lsb);
+	if (ret < 0)
+		return ret;
+
+	*height = (u32)(ADV7482_HDMI_F0HEIGHT_MSBS_MASK & msb);
+	*height = (lsb | (*height << 8));
+	if (!(*progressive))
+		*height = *height * 2;
+
+	if (*width == 0 || *height == 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int adv7482_set_vid_info(struct v4l2_subdev *sd)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	u8 progressive;
+	u8 signal;
+	u8 val = ADV7482_IO_CP_VID_STD_480P;
+	u32 width;
+	u32 height;
+	int ret;
+
+	/* Get video information */
+	ret = adv7482_get_vid_info(sd, &progressive, &width, &height, &signal);
+	if (ret < 0) {
+		width		= ADV7482_MAX_WIDTH;
+		height		= ADV7482_MAX_HEIGHT;
+		progressive	= 1;
+	} else {
+		if ((width == 640) &&
+			(height == 480) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_VGA60;
+			dev_info(state->dev,
+				 "Changed active resolution to 640x480p\n");
+		} else if ((width == 720) &&
+			(height == 480) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_480P;
+			dev_info(state->dev,
+				 "Changed active resolution to 720x480p\n");
+		} else if ((width == 720) &&
+			(height == 576) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_576P;
+			dev_info(state->dev,
+				 "Changed active resolution to 720x576p\n");
+		} else if ((width == 1280) &&
+			(height == 720) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_720P;
+			dev_info(state->dev,
+				 "Changed active resolution to 1280x720p\n");
+		} else if ((width == 1920) &&
+			(height == 1080) && (progressive == 1)) {
+			val = ADV7482_IO_CP_VID_STD_1080P;
+			dev_info(state->dev,
+				 "Changed active resolution to 1920x1080p\n");
+		} else if ((width == 1920) &&
+			(height == 1080) && (progressive == 0)) {
+			val = ADV7482_IO_CP_VID_STD_1080I;
+			dev_info(state->dev,
+				 "Changed active resolution to 1920x1080i\n");
+		} else {
+			dev_err(state->dev,
+				 "Not support resolution %dx%d%c\n",
+				  width, height, (progressive) ? 'p' : 'i');
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * The resolution of 720p, 1080i and 1080p is Hsync width of 40 pixel
+	 * clock cycles. These resolutions must be shifted horizontally to
+	 * the left in active video mode.
+	 */
+	if ((val == ADV7482_IO_CP_VID_STD_1080I) ||
+		(val == ADV7482_IO_CP_VID_STD_1080P)) {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x43);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0xD4);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x4F);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0xD4);
+	} else if (val == ADV7482_IO_CP_VID_STD_720P) {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x43);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0xD8);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x4F);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0xD8);
+	} else {
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x40);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8C, 0x00);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8B, 0x40);
+		ret = adv7482_write_register(client,
+					ADV7482_I2C_CP, 0x8D, 0x00);
+	}
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_CP_VID_STD_REG, val);
+
+	return ret;
+}
+
+/*****************************************************************************/
+/*  V4L2 decoder i/f handler for v4l2_subdev_core_ops                        */
+/*****************************************************************************/
+
+/*
+ * adv7482_querystd() - V4L2 decoder i/f handler for querystd
+ * @sd: ptr to v4l2_subdev struct
+ * @std: standard input video id
+ *
+ * Obtains the video standard input id
+ */
+static int adv7482_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	int err = mutex_lock_interruptible(&state->mutex);
+
+	if (err)
+		return err;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		/* when we are interrupt driven we know the state */
+		if (!state->autodetect)
+			*std = state->curr_norm;
+		else
+			err = __adv7482_status(state, NULL, std);
+	else
+		*std = V4L2_STD_ATSC;
+
+	mutex_unlock(&state->mutex);
+
+	return err;
+}
+
+/*
+ * adv7482_g_input_status() - V4L2 decoder i/f handler for g_input_status
+ * @sd: ptr to v4l2_subdev struct
+ * @status: video input status flag
+ *
+ * Obtains the video input status flags.
+ */
+static int adv7482_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	u8 status1 = 0;
+	int ret = mutex_lock_interruptible(&state->mutex);
+
+	if (ret)
+		return ret;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = __adv7482_status(state, status, NULL);
+	else {
+		ret = adv7482_read_register(client, ADV7482_I2C_HDMI,
+				ADV7482_HDMI_STATUS1_REG, &status1);
+		if (ret < 0)
+			goto out;
+
+		if (!(status1 & ADV7482_HDMI_VF_LOCKED_FLG))
+			*status = V4L2_IN_ST_NO_SIGNAL;
+		else if (!(status1 & ADV7482_HDMI_DERF_LOCKED_FLG))
+			*status = V4L2_IN_ST_NO_SIGNAL;
+		else
+			*status = 0;
+	}
+
+	ret = 0;
+out:
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7482_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (code->index != 0)
+		return -EINVAL;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		code->code = MEDIA_BUS_FMT_YUYV8_2X8;
+	else
+		code->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+	return 0;
+}
+
+static int adv7482_mbus_fmt(struct v4l2_subdev *sd,
+			    struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7482_state *state = to_state(sd);
+
+	u8 progressive;
+	u8 signal;
+	u32 width;
+	u32 height;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+	u8 status_reg_10;
+	struct adv7482_sdp_main_info sdp_info;
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
+		fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+		fmt->width = 720;
+		fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
+
+		/* Get video information */
+		ret = adv7482_read_sdp_main_info(client, &sdp_info);
+		if (ret < 0)
+			return ret;
+
+		status_reg_10 = sdp_info.status_reg_10;
+
+		if (status_reg_10 < 0)
+			dev_info(state->dev,
+				"Not detect any video input signal\n");
+		else {
+			if ((status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK) &&
+				(status_reg_10 & ADV7482_SDP_R_REG_10_FSC_LOCK)
+				&& (((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_M) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_M) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_60) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_60) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_B_G) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB) ==
+				ADV7482_SDP_R_REG_10_AUTOD_PAL_COMB)))
+				dev_info(state->dev,
+				   "Detected the PAL video input signal\n");
+			else if ((status_reg_10 & ADV7482_SDP_R_REG_10_IN_LOCK)
+				&& (status_reg_10 &
+				ADV7482_SDP_R_REG_10_FSC_LOCK) &&
+				(((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43) ==
+				ADV7482_SDP_R_REG_10_AUTOD_NTSC_4_43) ||
+				((status_reg_10 &
+				ADV7482_SDP_R_REG_10_AUTOD_MASK) ==
+				ADV7482_SDP_R_REG_10_AUTOD_NTSM_M_J)))
+				dev_info(state->dev,
+				   "Detected the NTSC video input signal\n");
+			else
+				dev_info(state->dev,
+				   "Not detect any video input signal\n");
+		}
+
+		state->width = fmt->width;
+		state->height = fmt->height;
+		state->field = V4L2_FIELD_INTERLACED;
+
+	} else {
+		fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
+		fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+			&width, &height, &signal);
+		if (ret < 0) {
+			width		= ADV7482_MAX_WIDTH;
+			height		= ADV7482_MAX_HEIGHT;
+			progressive	= 1;
+		}
+
+		if (signal)
+			dev_info(state->dev,
+			 "Detected the HDMI video input signal (%dx%d%c)\n",
+			  width, height, (progressive) ? 'p' : 'i');
+		else
+			dev_info(state->dev,
+				"Not detect any video input signal\n");
+
+		state->width = width;
+		state->height = height;
+		state->field =
+		      (progressive) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED;
+
+		fmt->width = state->width;
+		fmt->height = state->height;
+	}
+
+	return 0;
+}
+
+/*
+ * adv7482_cropcap() - V4L2 decoder i/f handler for cropcap
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 cropcap structure
+ *
+ * Gets cropping limits, default cropping rectangle and pixel aspect.
+ */
+static int adv7482_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+	struct adv7482_state *state = to_state(sd);
+	u8 progressive;
+	u32 width;
+	u32 height;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	/* cropping limits */
+	a->bounds.left = 0;
+	a->bounds.top  = 0;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		a->bounds.width  = 720;
+		a->bounds.height = state->curr_norm & V4L2_STD_525_60
+							 ? 480 : 576;
+	} else {
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+						 &width, &height, NULL);
+		if (ret < 0) {
+			a->bounds.width  = ADV7482_MAX_WIDTH;
+			a->bounds.height = ADV7482_MAX_HEIGHT;
+		} else {
+			a->bounds.width  = width;
+			a->bounds.height = height;
+		}
+	}
+
+	/* default cropping rectangle */
+	a->defrect = a->bounds;
+
+	/* does not support scaling */
+	a->pixelaspect.numerator   = 1;
+	a->pixelaspect.denominator = 1;
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+/*
+ * adv7482_g_crop() - V4L2 decoder i/f handler for g_crop
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 cropcap structure
+ *
+ * Gets current cropping rectangle.
+ */
+static int adv7482_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct adv7482_state *state = to_state(sd);
+	u8 progressive;
+	u32 width;
+	u32 height;
+	int ret;
+
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	a->c.left = 0;
+	a->c.top  = 0;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = __adv7482_status(state, NULL, &state->curr_norm);
+		if (ret < 0)
+			return ret;
+
+		a->c.width  = 720;
+		a->c.height = state->curr_norm & V4L2_STD_525_60
+							 ? 480 : 576;
+	} else {
+		/* Get video information */
+		ret = adv7482_get_vid_info(sd, &progressive,
+						 &width, &height, NULL);
+		if (ret < 0) {
+			a->c.width  = ADV7482_MAX_WIDTH;
+			a->c.height = ADV7482_MAX_HEIGHT;
+		} else {
+			a->c.width  = width;
+			a->c.height = height;
+		}
+	}
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
+static int adv7482_set_field_mode(struct adv7482_state *state)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static int adv7482_set_power(struct adv7482_state *state, bool on)
+{
+	u8 val;
+	int ret;
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422) {
+		ret = adv7482_read_register(state->client, ADV7482_I2C_TXB,
+				0x1E, &val);
+		if (ret < 0)
+			return ret;
+
+		if (on && ((val & 0x40) == 0)) {
+			/* Power up */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_up_txb_1lane);
+			if (ret < 0)
+				goto fail;
+		} else {
+			/* Power down */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_down_txb_1lane);
+			if (ret < 0)
+				goto fail;
+		}
+	} else {
+		/* set active resolution */
+		ret = adv7482_set_vid_info(&state->sd);
+		ret = adv7482_read_register(state->client, ADV7482_I2C_TXA,
+				0x1E, &val);
+		if (ret < 0)
+			return ret;
+
+		if (on && ((val & 0x40) == 0)) {
+			/* Power up */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_up_txa_4lane);
+			if (ret < 0)
+				goto fail;
+		} else {
+			/* Power down */
+			ret = adv7482_write_registers(state->client,
+					adv7482_power_down_txa_4lane);
+			if (ret < 0)
+				goto fail;
+		}
+	}
+
+	return 0;
+fail:
+	pr_info("%s: Failed set power operation, ret = %d\n", __func__, ret);
+	return ret;
+}
+
+static int adv7482_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct adv7482_state *state = to_state(sd);
+	int ret;
+
+	ret = mutex_lock_interruptible(&state->mutex);
+	if (ret)
+		return ret;
+
+	ret = adv7482_set_power(state, on);
+	if (ret == 0)
+		state->powered = on;
+
+	mutex_unlock(&state->mutex);
+	return ret;
+}
+
+static int adv7482_get_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7482_state *state = to_state(sd);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+		format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+	else {
+		adv7482_mbus_fmt(sd, &format->format);
+		format->format.field = state->field;
+	}
+
+	return 0;
+}
+
+static int adv7482_set_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_format *format)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct v4l2_mbus_framefmt *framefmt;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		framefmt = &format->format;
+		if (state->field != format->format.field) {
+			state->field = format->format.field;
+			adv7482_set_power(state, false);
+			adv7482_set_field_mode(state);
+			adv7482_set_power(state, true);
+		}
+	} else {
+		adv7482_mbus_fmt(sd, &format->format);
+
+		if (format->format.field == V4L2_FIELD_ANY)
+			format->format.field = state->field;
+
+		return 0;
+	}
+
+	return adv7482_mbus_fmt(sd, framefmt);
+}
+
+/*
+ * adv7482_g_mbus_config() - V4L2 decoder i/f handler for g_mbus_config
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @cfg: pointer to V4L2 mbus_config structure
+ *
+ * Get mbus configuration.
+ */
+static int adv7482_g_mbus_config(struct v4l2_subdev *sd,
+					struct v4l2_mbus_config *cfg)
+{
+	struct adv7482_state *state = to_state(sd);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		cfg->flags = V4L2_MBUS_CSI2_1_LANE |
+				V4L2_MBUS_CSI2_CHANNEL_0 |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	else
+		cfg->flags = V4L2_MBUS_CSI2_LANES |
+				V4L2_MBUS_CSI2_CHANNELS |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	cfg->type = V4L2_MBUS_CSI2;
+
+	return 0;
+}
+
+
+/*****************************************************************************/
+/*  V4L2 decoder i/f handler for v4l2_ctrl_ops                               */
+/*****************************************************************************/
+static int adv7482_cp_s_ctrl(struct v4l2_ctrl *ctrl, struct i2c_client *client)
+{
+	u8 val;
+	int ret;
+
+	/* Enable video adjustment first */
+	ret = adv7482_read_register(client, ADV7482_I2C_CP,
+			ADV7482_CP_VID_ADJ_REG, &val);
+	if (ret < 0)
+		return ret;
+	val |= ADV7482_CP_VID_ADJ_ENABLE;
+	ret = adv7482_write_register(client, ADV7482_I2C_CP,
+			ADV7482_CP_VID_ADJ_REG, val);
+	if (ret < 0)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctrl->val < ADV7482_CP_BRI_MIN) ||
+					(ctrl->val > ADV7482_CP_BRI_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_BRI_REG, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		if ((ctrl->val < ADV7482_CP_HUE_MIN) ||
+					(ctrl->val > ADV7482_CP_HUE_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_HUE_REG, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->val < ADV7482_CP_CON_MIN) ||
+					(ctrl->val > ADV7482_CP_CON_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_CON_REG, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		if ((ctrl->val < ADV7482_CP_SAT_MIN) ||
+					(ctrl->val > ADV7482_CP_SAT_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_CP,
+					ADV7482_CP_SAT_REG, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int adv7482_sdp_s_ctrl(struct v4l2_ctrl *ctrl, struct i2c_client *client)
+{
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+			ADV7482_SDP_REG_CTRL, ADV7482_SDP_MAIN_MAP_RW);
+	if (ret < 0)
+		return ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if ((ctrl->val < ADV7482_SDP_BRI_MIN) ||
+					(ctrl->val > ADV7482_SDP_BRI_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_BRI, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		if ((ctrl->val < ADV7482_SDP_HUE_MIN) ||
+					(ctrl->val > ADV7482_SDP_HUE_MAX))
+			ret = -ERANGE;
+		else
+			/*Hue is inverted according to HSL chart */
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_HUE, -ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		if ((ctrl->val < ADV7482_SDP_CON_MIN) ||
+					(ctrl->val > ADV7482_SDP_CON_MAX))
+			ret = -ERANGE;
+		else
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_CON, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		/*
+		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
+		 *Let's not confuse the user, everybody understands saturation
+		 */
+		if ((ctrl->val < ADV7482_SDP_SAT_MIN) ||
+					(ctrl->val > ADV7482_SDP_SAT_MAX))
+			ret = -ERANGE;
+		else {
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_SD_SAT_CB, ctrl->val);
+			if (ret < 0)
+				break;
+
+			ret = adv7482_write_register(client, ADV7482_I2C_SDP,
+					ADV7482_SDP_REG_SD_SAT_CR, ctrl->val);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * adv7482_s_ctrl() - V4L2 decoder i/f handler for s_ctrl
+ * @ctrl: pointer to standard V4L2 control structure
+ *
+ * Set a control in ADV7482 decoder device.
+ */
+static int adv7482_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct v4l2_subdev *sd = to_adv7482_sd(ctrl);
+	struct adv7482_state *state = to_state(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+	struct adv7482_link_config *config = &state->mipi_csi2_link[0];
+
+	if (ret)
+		return ret;
+
+	if (config->input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = adv7482_sdp_s_ctrl(ctrl, client);
+	else
+		ret = adv7482_cp_s_ctrl(ctrl, client);
+
+	mutex_unlock(&state->mutex);
+
+	return ret;
+}
+
+
+static const struct v4l2_subdev_core_ops adv7482_core_ops = {
+	.queryctrl = v4l2_subdev_queryctrl,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.querymenu = v4l2_subdev_querymenu,
+	.s_power = adv7482_s_power,
+};
+
+static const struct v4l2_subdev_video_ops adv7482_video_ops = {
+	.querystd	= adv7482_querystd,
+	.g_input_status = adv7482_g_input_status,
+	.cropcap	= adv7482_cropcap,
+	.g_crop		= adv7482_g_crop,
+	.g_mbus_config	= adv7482_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops adv7482_pad_ops = {
+	.enum_mbus_code = adv7482_enum_mbus_code,
+	.set_fmt = adv7482_set_pad_format,
+	.get_fmt = adv7482_get_pad_format,
+};
+
+static const struct v4l2_subdev_ops adv7482_ops = {
+	.core = &adv7482_core_ops,
+	.video = &adv7482_video_ops,
+	.pad = &adv7482_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops adv7482_ctrl_ops = {
+	.s_ctrl = adv7482_s_ctrl,
+};
+
+/*
+ * adv7482_init_controls() - Init controls
+ * @state: pointer to private state structure
+ *
+ * Init ADV7482 supported control handler.
+ */
+static int adv7482_cp_init_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, ADV7482_CP_BRI_MIN,
+			  ADV7482_CP_BRI_MAX, 1, ADV7482_CP_BRI_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_CONTRAST, ADV7482_CP_CON_MIN,
+			  ADV7482_CP_CON_MAX, 1, ADV7482_CP_CON_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_SATURATION, ADV7482_CP_SAT_MIN,
+			  ADV7482_CP_SAT_MAX, 1, ADV7482_CP_SAT_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_HUE, ADV7482_CP_HUE_MIN,
+			  ADV7482_CP_HUE_MAX, 1, ADV7482_CP_HUE_DEF);
+	state->sd.ctrl_handler = &state->ctrl_hdl;
+	if (state->ctrl_hdl.error) {
+		int err = state->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&state->ctrl_hdl);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+	return 0;
+}
+
+static int adv7482_sdp_init_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_BRIGHTNESS, ADV7482_SDP_BRI_MIN,
+			  ADV7482_SDP_BRI_MAX, 1, ADV7482_SDP_BRI_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_CONTRAST, ADV7482_SDP_CON_MIN,
+			  ADV7482_SDP_CON_MAX, 1, ADV7482_SDP_CON_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_SATURATION, ADV7482_SDP_SAT_MIN,
+			  ADV7482_SDP_SAT_MAX, 1, ADV7482_SDP_SAT_DEF);
+	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7482_ctrl_ops,
+			  V4L2_CID_HUE, ADV7482_SDP_HUE_MIN,
+			  ADV7482_SDP_HUE_MAX, 1, ADV7482_SDP_HUE_DEF);
+
+	state->sd.ctrl_handler = &state->ctrl_hdl;
+	if (state->ctrl_hdl.error) {
+		int err = state->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&state->ctrl_hdl);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+	return 0;
+}
+
+static void adv7482_exit_controls(struct adv7482_state *state)
+{
+	v4l2_ctrl_handler_free(&state->ctrl_hdl);
+}
+
+/*****************************************************************************/
+/*  i2c driver interface handlers                                            */
+/*****************************************************************************/
+
+static int adv7482_parse_dt(struct device_node *np,
+			    struct adv7482_link_config *config)
+{
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *endpoint;
+	const char *str;
+	int ret;
+	int ch;
+
+	/* Parse the endpoint. */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint)
+		return -EINVAL;
+
+	v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+	of_node_put(endpoint);
+
+	/* check input-interface */
+	ret = of_property_read_string(np, "adi,input-interface", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "rgb888")) {
+		config->input_interface = DECODER_INPUT_INTERFACE_RGB888;
+		config->regs =
+		(struct adv7482_reg_value *)adv7482_init_txa_4lane;
+		config->power_up =
+		(struct adv7482_reg_value *)adv7482_power_up_txa_4lane;
+		config->power_down =
+		(struct adv7482_reg_value *)adv7482_power_down_txa_4lane;
+		config->init_controls =
+		(int (*)(void *))adv7482_cp_init_controls;
+	} else {
+		config->input_interface = DECODER_INPUT_INTERFACE_YCBCR422;
+		config->regs =
+		(struct adv7482_reg_value *)adv7482_init_txb_1lane;
+		config->power_up =
+		(struct adv7482_reg_value *)adv7482_power_up_txb_1lane;
+		config->power_down =
+		(struct adv7482_reg_value *)adv7482_power_down_txb_1lane;
+		config->init_controls =
+		(int (*)(void *))adv7482_sdp_init_controls;
+	}
+
+	ret = of_property_read_string(np, "adi,input-hdmi", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->hdmi_in = 1;
+	else
+		config->hdmi_in = 0;
+
+	ret = of_property_read_string(np, "adi,input-sdp", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->sdp_in = 1;
+	else
+		config->sdp_in = 0;
+
+	ret = of_property_read_string(np, "adi,sw-reset", &str);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(str, "on"))
+		config->sw_reset = 1;
+	else
+		config->sw_reset = 0;
+
+	ret = of_property_read_u32(np, "adi,virtual-channel", &ch);
+	if (ret < 0)
+		return ret;
+
+	if ((ch < 0) || (ch > 3))
+		return -EINVAL;
+
+	config->vc_ch = ch;
+
+	config->init_device    = NULL;
+	config->s_power        = NULL;
+	config->s_ctrl         = NULL;
+	config->enum_mbus_code = NULL;
+	config->set_pad_format = NULL;
+	config->get_pad_format = NULL;
+	config->s_std          = NULL;
+	config->querystd       = NULL;
+	config->g_input_status = NULL;
+	config->s_routing      = NULL;
+	config->g_mbus_config  = NULL;
+
+	return 0;
+}
+
+/*
+ * adv7482_probe - Probe a ADV7482 device
+ * @client: pointer to i2c_client structure
+ * @id: pointer to i2c_device_id structure
+ *
+ * Initialize the ADV7482 device
+ */
+static int adv7482_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct adv7482_state *state;
+	struct adv7482_link_config link_config;
+	struct device *dev = &client->dev;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7482_state), GFP_KERNEL);
+	if (state == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	state->client = client;
+	state->irq = client->irq;
+
+	ret = adv7482_parse_dt(dev->of_node, &link_config);
+	if (ret) {
+		dev_err(&client->dev, "adv7482 parse error\n");
+		return ret;
+	}
+
+	state->mipi_csi2_link[0].input_interface = link_config.input_interface;
+
+	mutex_init(&state->mutex);
+	state->autodetect = true;
+	state->powered = true;
+	sd = &state->sd;
+	state->width = ADV7482_MAX_WIDTH;
+	state->height = ADV7482_MAX_HEIGHT;
+	state->field = V4L2_FIELD_NONE;
+
+	v4l2_i2c_subdev_init(sd, client, &adv7482_ops);
+
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	state->dev		= dev;
+	state->mipi_csi2_link[0].dev = dev;
+
+	/* SW reset ADV7482 to its default values */
+	if (link_config.sw_reset) {
+		ret = adv7482_write_registers(client, adv7482_sw_reset);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* check rd_info */
+		{
+			u8 msb;
+			u8 lsb;
+
+			ret = adv7482_read_register(client, ADV7482_I2C_IO,
+					ADV7482_IO_RD_INFO1_REG, &lsb);
+			if (ret < 0)
+				return ret;
+
+			ret = adv7482_read_register(client, ADV7482_I2C_IO,
+					ADV7482_IO_RD_INFO2_REG, &msb);
+			if (ret < 0)
+				return ret;
+
+			v4l_info(client, "adv7482 revision is %02x%02x\n",
+					lsb, msb);
+		}
+	}
+
+	if (link_config.hdmi_in) {
+		ret = adv7482_write_registers(client,
+				adv7482_init_txa_4lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Power down */
+		ret = adv7482_write_registers(client,
+				adv7482_power_down_txa_4lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 txa power down\n");
+	} else
+		v4l_info(client, "adv7482 hdmi_in is disabled.\n");
+
+	/* Initializes ADV7482 to its default values */
+	if (link_config.sdp_in) {
+		ret = adv7482_write_registers(client,
+						adv7482_init_txb_1lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Power down */
+		ret = adv7482_write_registers(client,
+						adv7482_power_down_txb_1lane);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 txb power down\n");
+	} else
+		v4l_info(client, "adv7482 sdp_in is disabled.\n");
+
+	if (link_config.sdp_in && link_config.hdmi_in) {
+		/* Power up hdmi rx */
+		ret = adv7482_write_registers(client,
+						adv7482_power_up_hdmi_rx);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		/* Enable csi4 and sci1 */
+		ret = adv7482_write_registers(client,
+						adv7482_enable_csi4_csi1);
+		if (ret < 0)
+			goto err_unreg_subdev;
+
+		v4l_info(client, "adv7482 enable csi1 and csi4\n");
+	}
+
+	if (link_config.input_interface == DECODER_INPUT_INTERFACE_YCBCR422)
+		ret = adv7482_sdp_init_controls(state);
+	else
+		ret = adv7482_cp_init_controls(state);
+	if (ret)
+		goto err_unreg_subdev;
+
+	/* Setting virtual channel for ADV7482 */
+	if (link_config.vc_ch == 0)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel0);
+	else if (link_config.vc_ch == 1)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel1);
+	else if (link_config.vc_ch == 2)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel2);
+	else if (link_config.vc_ch == 3)
+		ret = adv7482_write_registers(client,
+					adv7482_set_virtual_channel3);
+	if (ret < 0)
+		goto err_unreg_subdev;
+
+	state->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER;
+	ret = media_entity_pads_init(&sd->entity, 1, &state->pad);
+	if (ret)
+		goto err_free_ctrl;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret)
+		goto err_free_ctrl;
+
+	return 0;
+
+err_free_ctrl:
+	adv7482_exit_controls(state);
+
+err_unreg_subdev:
+	mutex_destroy(&state->mutex);
+	v4l2_device_unregister_subdev(sd);
+	kfree(state);
+err:
+	dev_err(&client->dev, ": Failed to probe: %d\n", ret);
+	return ret;
+}
+
+/*
+ * adv7482_remove - Remove ADV7482 device support
+ * @client: pointer to i2c_client structure
+ *
+ * Reset the ADV7482 device
+ */
+static int adv7482_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7482_state *state = to_state(sd);
+
+	v4l2_async_unregister_subdev(sd);
+
+	media_entity_cleanup(&sd->entity);
+	adv7482_exit_controls(state);
+
+	mutex_destroy(&state->mutex);
+	kfree(to_state(sd));
+	return 0;
+}
+
+static const struct i2c_device_id adv7482_id[] = {
+	{DRIVER_NAME, 0},
+	{},
+};
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * adv7482_suspend - Suspend ADV7482 device
+ * @client: pointer to i2c_client structure
+ * @state: power management state
+ *
+ * Power down the ADV7482 device
+ */
+static int adv7482_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_PWR_MAN_REG, ADV7482_IO_PWR_OFF);
+
+	return ret;
+}
+
+/*
+ * adv7482_resume - Resume ADV7482 device
+ * @client: pointer to i2c_client structure
+ *
+ * Power on and initialize the ADV7482 device
+ */
+static int adv7482_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adv7482_link_config link_config;
+	int ret;
+
+	ret = adv7482_write_register(client, ADV7482_I2C_IO,
+				ADV7482_IO_PWR_MAN_REG, ADV7482_IO_PWR_ON);
+	if (ret < 0)
+		return ret;
+
+	ret = adv7482_parse_dt(dev->of_node, &link_config);
+	if (ret)
+		return ret;
+
+	/* Initializes ADV7482 to its default values */
+	ret = adv7482_write_registers(client, link_config.regs);
+
+	/* Power down */
+	ret = adv7482_write_registers(client, link_config.power_down);
+
+	if (link_config.sdp_in && link_config.hdmi_in) {
+		/* Power up hdmi rx */
+		ret = adv7482_write_registers(client,
+						adv7482_power_up_hdmi_rx);
+		if (ret < 0)
+			return ret;
+
+		/* Enable csi4 and sci1 */
+		ret = adv7482_write_registers(client,
+						adv7482_enable_csi4_csi1);
+		if (ret < 0)
+			return ret;
+	}
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(adv7482_pm_ops, adv7482_suspend, adv7482_resume);
+#define ADV7482_PM_OPS (&adv7482_pm_ops)
+
+#else
+#define ADV7482_PM_OPS NULL
+#endif
+
+MODULE_DEVICE_TABLE(i2c, adv7482_id);
+
+static const struct of_device_id adv7482_of_ids[] = {
+	{ .compatible = "adi,adv7482", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7482_of_ids);
+
+static struct i2c_driver adv7482_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.pm = ADV7482_PM_OPS,
+		.of_match_table = adv7482_of_ids,
+	},
+	.probe		= adv7482_probe,
+	.remove		= adv7482_remove,
+	.id_table	= adv7482_id,
+};
+
+module_i2c_driver(adv7482_driver);
+
+MODULE_DESCRIPTION("HDMI Receiver ADV7482 video decoder driver");
+MODULE_ALIAS("platform:adv7482");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 0141af8..611b40c 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -273,6 +273,27 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called vsp1.
 
+config VIDEO_RENESAS_DEBUG
+	bool "Renesas VSP1 underrun debug messages"
+	depends on VIDEO_RENESAS_VSP1
+	---help---
+	  Enable debug underrun messages on Renesas VSP1 Video Processing
+	  Engine driver.
+	  If you set to enable, When an underrun occurred, a debug underrun
+	  message is output.
+
+config VIDEO_RENESAS_VSP_ALPHA_BIT_ARGB1555
+	int "Renesas VSP alpha bit function of ARGB1555"
+	depends on VIDEO_RENESAS_VSP1
+	range 0 1
+	default 0
+	help
+	  Choose this option if you select A bit function of ARGB1555.
+	  If you set value to 0, pixel alpha blending is performed
+	  when the value of A is 0.
+	  If you set value to 1, pixel alpha blending is performed
+	  when the value of A is 1.
+
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c
index 6a7bcc3..f674c68 100644
--- a/drivers/media/platform/rcar-fcp.c
+++ b/drivers/media/platform/rcar-fcp.c
@@ -107,6 +107,16 @@
 EXPORT_SYMBOL_GPL(rcar_fcp_enable);
 
 /**
+ * rcar_fcp_device - Get FCP device
+ * @fcp: The FCP instance
+ */
+struct device *rcar_fcp_device(struct rcar_fcp_device *fcp)
+{
+	return fcp ? fcp->dev : NULL;
+}
+EXPORT_SYMBOL_GPL(rcar_fcp_device);
+
+/**
  * rcar_fcp_disable - Disable an FCP
  * @fcp: The FCP instance
  *
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index 83029a4..826a958 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -35,6 +35,22 @@
 	---help---
 	  This is a v4l2 driver for the R-Car VIN Interface
 
+config VIDEO_RCAR_VIN_DEBUG
+	bool "Renesas VIN overflow debug messages"
+	depends on VIDEO_RCAR_VIN
+	---help---
+	  Enable debug overflow messages on R-Car Video
+	  Input driver.
+	  If you set to enable, When an overflow occurred,
+	  a debug overflow message is output.
+
+config VIDEO_RCAR_CSI2
+	tristate "R-Car MIPI CSI-2 Interface driver"
+	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+	depends on ARCH_R8A7795 || ARCH_R8A7796 || COMPILE_TEST
+	---help---
+	  This is a v4l2 driver for the R-Car CSI-2 Interface
+
 config VIDEO_SH_MOBILE_CSI2
 	tristate "SuperH Mobile MIPI CSI-2 Interface driver"
 	depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index 7ee71ae..0a193bd 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -10,4 +10,5 @@
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)	+= sh_mobile_csi2.o
+obj-$(CONFIG_VIDEO_RCAR_CSI2)		+= rcar_csi2.o
 obj-$(CONFIG_VIDEO_RCAR_VIN)		+= rcar_vin.o
diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
new file mode 100644
index 0000000..851a4ca
--- /dev/null
+++ b/drivers/media/platform/soc_camera/rcar_csi2.c
@@ -0,0 +1,708 @@
+/*
+ * drivers/media/platform/soc_camera/rcar_csi2.c
+ *     This file is the driver for the R-Car MIPI CSI-2 unit.
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ *
+ * This file is based on the drivers/media/platform/soc_camera/sh_mobile_csi2.c
+ *
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/rcar_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#include <media/v4l2-of.h>
+
+#define DRV_NAME "rcar_csi2"
+#define CONNECT_SLAVE_NAME "adv7482"
+#define VC_MAX_CHANNEL		4
+
+#define RCAR_CSI2_TREF		0x00
+#define RCAR_CSI2_SRST		0x04
+#define RCAR_CSI2_PHYCNT	0x08
+#define RCAR_CSI2_CHKSUM	0x0C
+#define RCAR_CSI2_VCDT		0x10
+
+#define RCAR_CSI2_VCDT2			0x14 /* Channel Data Type Select */
+#define RCAR_CSI2_FRDT			0x18 /* Frame Data Type Select */
+#define RCAR_CSI2_FLD			0x1C /* Field Detection Control */
+#define RCAR_CSI2_ASTBY			0x20 /* Automatic standby control */
+#define RCAR_CSI2_LNGDT0		0x28
+#define RCAR_CSI2_LNGDT1		0x2C
+#define RCAR_CSI2_INTEN			0x30
+#define RCAR_CSI2_INTCLOSE		0x34
+#define RCAR_CSI2_INTSTATE		0x38
+#define RCAR_CSI2_INTERRSTATE		0x3C
+
+#define RCAR_CSI2_SHPDAT		0x40
+#define RCAR_CSI2_SHPCNT		0x44
+
+#define RCAR_CSI2_LINKCNT		0x48
+#define RCAR_CSI2_LSWAP			0x4C
+#define RCAR_CSI2_PHTC			0x58
+#define RCAR_CSI2_PHYPLL		0x68
+
+#define RCAR_CSI2_PHEERM		0x74
+#define RCAR_CSI2_PHCLM			0x78
+#define RCAR_CSI2_PHDLM			0x7C
+
+#define RCAR_CSI2_PHYCNT_SHUTDOWNZ		(1 << 17)
+#define RCAR_CSI2_PHYCNT_RSTZ			(1 << 16)
+#define RCAR_CSI2_PHYCNT_ENABLECLK		(1 << 4)
+#define RCAR_CSI2_PHYCNT_ENABLE_3		(1 << 3)
+#define RCAR_CSI2_PHYCNT_ENABLE_2		(1 << 2)
+#define RCAR_CSI2_PHYCNT_ENABLE_1		(1 << 1)
+#define RCAR_CSI2_PHYCNT_ENABLE_0		(1 << 0)
+
+#define RCAR_CSI2_VCDT_VCDTN_EN			(1 << 15)
+#define RCAR_CSI2_VCDT_SEL_VCN			(1 << 8)
+#define RCAR_CSI2_VCDT_SEL_DTN_ON		(1 << 6)
+#define RCAR_CSI2_VCDT_SEL_DTN			(1 << 0)
+
+#define RCAR_CSI2_LINKCNT_MONITOR_EN		(1 << 31)
+#define RCAR_CSI2_LINKCNT_REG_MONI_PACT_EN	(1 << 25)
+
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE0		(0 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE1		(1 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE2		(2 << 6)
+#define RCAR_CSI2_LSWAP_L3SEL_PLANE3		(3 << 6)
+
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE0		(0 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE1		(1 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE2		(2 << 4)
+#define RCAR_CSI2_LSWAP_L2SEL_PLANE3		(3 << 4)
+
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE0		(0 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE1		(1 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE2		(2 << 2)
+#define RCAR_CSI2_LSWAP_L1SEL_PLANE3		(3 << 2)
+
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE0		(0 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE1		(1 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE2		(2 << 0)
+#define RCAR_CSI2_LSWAP_L0SEL_PLANE3		(3 << 0)
+
+#define RCAR_CSI2_PHTC_TESTCLR			(1 << 0)
+
+/* interrupt status registers */
+#define RCAR_CSI2_INTSTATE_EBD_CH1		(1 << 29)
+#define RCAR_CSI2_INTSTATE_LESS_THAN_WC		(1 << 28)
+#define RCAR_CSI2_INTSTATE_AFIFO_OF		(1 << 27)
+#define RCAR_CSI2_INTSTATE_VD4_START		(1 << 26)
+#define RCAR_CSI2_INTSTATE_VD4_END		(1 << 25)
+#define RCAR_CSI2_INTSTATE_VD3_START		(1 << 24)
+#define RCAR_CSI2_INTSTATE_VD3_END		(1 << 23)
+#define RCAR_CSI2_INTSTATE_VD2_START		(1 << 22)
+#define RCAR_CSI2_INTSTATE_VD2_END		(1 << 21)
+#define RCAR_CSI2_INTSTATE_VD1_START		(1 << 20)
+#define RCAR_CSI2_INTSTATE_VD1_END		(1 << 19)
+#define RCAR_CSI2_INTSTATE_SHP			(1 << 18)
+#define RCAR_CSI2_INTSTATE_FSFE			(1 << 17)
+#define RCAR_CSI2_INTSTATE_LNP			(1 << 16)
+#define RCAR_CSI2_INTSTATE_CRC_ERR		(1 << 15)
+#define RCAR_CSI2_INTSTATE_HD_WC_ZERO		(1 << 14)
+#define RCAR_CSI2_INTSTATE_FRM_SEQ_ERR1		(1 << 13)
+#define RCAR_CSI2_INTSTATE_FRM_SEQ_ERR2		(1 << 12)
+#define RCAR_CSI2_INTSTATE_ECC_ERR		(1 << 11)
+#define RCAR_CSI2_INTSTATE_ECC_CRCT_ERR		(1 << 10)
+#define RCAR_CSI2_INTSTATE_LPDT_START		(1 << 9)
+#define RCAR_CSI2_INTSTATE_LPDT_END		(1 << 8)
+#define RCAR_CSI2_INTSTATE_ULPS_START		(1 << 7)
+#define RCAR_CSI2_INTSTATE_ULPS_END		(1 << 6)
+#define RCAR_CSI2_INTSTATE_RESERVED		(1 << 5)
+#define RCAR_CSI2_INTSTATE_ERRSOTHS		(1 << 4)
+#define RCAR_CSI2_INTSTATE_ERRSOTSYNCCHS	(1 << 3)
+#define RCAR_CSI2_INTSTATE_ERRESC		(1 << 2)
+#define RCAR_CSI2_INTSTATE_ERRSYNCESC		(1 << 1)
+#define RCAR_CSI2_INTSTATE_ERRCONTROL		(1 << 0)
+
+/* monitoring registers of interrupt error status */
+#define RCAR_CSI2_INTSTATE_ECC_ERR		(1 << 11)
+#define RCAR_CSI2_INTSTATE_ECC_CRCT_ERR		(1 << 10)
+#define RCAR_CSI2_INTSTATE_LPDT_START		(1 << 9)
+#define RCAR_CSI2_INTSTATE_LPDT_END		(1 << 8)
+#define RCAR_CSI2_INTSTATE_ULPS_START		(1 << 7)
+#define RCAR_CSI2_INTSTATE_ULPS_END		(1 << 6)
+#define RCAR_CSI2_INTSTATE_RESERVED		(1 << 5)
+#define RCAR_CSI2_INTSTATE_ERRSOTHS		(1 << 4)
+#define RCAR_CSI2_INTSTATE_ERRSOTSYNCCHS	(1 << 3)
+#define RCAR_CSI2_INTSTATE_ERRESC		(1 << 2)
+#define RCAR_CSI2_INTSTATE_ERRSYNCESC		(1 << 1)
+#define RCAR_CSI2_INTSTATE_ERRCONTROL		(1 << 0)
+
+enum chip_id {
+	RCAR_GEN3,
+	RCAR_GEN2,
+};
+
+enum decoder_input_interface {
+	DECODER_INPUT_INTERFACE_RGB888,
+	DECODER_INPUT_INTERFACE_YCBCR422,
+	DECODER_INPUT_INTERFACE_NONE,
+};
+
+/**
+ * struct rcar_csi2_link_config - Describes rcar_csi2 hardware configuration
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ */
+struct rcar_csi2_link_config {
+	enum decoder_input_interface input_interface;
+	unsigned char lanes;
+	unsigned long vcdt;
+	unsigned long vcdt2;
+};
+
+#define INIT_RCAR_CSI2_LINK_CONFIG(m) \
+{	\
+	m.input_interface = DECODER_INPUT_INTERFACE_NONE; \
+	m.lanes = 0; \
+}
+
+struct rcar_csi_irq_counter_log {
+	unsigned long crc_err;
+};
+
+struct rcar_csi2 {
+	struct v4l2_subdev		subdev;
+	struct v4l2_mbus_framefmt	*mf;
+	unsigned int			irq;
+	unsigned long			mipi_flags;
+	void __iomem			*base;
+	struct platform_device		*pdev;
+	struct rcar_csi2_client_config	*client;
+	unsigned long			vcdt;
+	unsigned long			vcdt2;
+
+	unsigned int			field;
+	unsigned int			code;
+	unsigned int			lanes;
+	spinlock_t			lock;
+};
+
+#define RCAR_CSI_80MBPS		0
+#define RCAR_CSI_90MBPS		1
+#define RCAR_CSI_100MBPS	2
+#define RCAR_CSI_110MBPS	3
+#define RCAR_CSI_120MBPS	4
+#define RCAR_CSI_130MBPS	5
+#define RCAR_CSI_140MBPS	6
+#define RCAR_CSI_150MBPS	7
+#define RCAR_CSI_160MBPS	8
+#define RCAR_CSI_170MBPS	9
+#define RCAR_CSI_180MBPS	10
+#define RCAR_CSI_190MBPS	11
+#define RCAR_CSI_205MBPS	12
+#define RCAR_CSI_220MBPS	13
+#define RCAR_CSI_235MBPS	14
+#define RCAR_CSI_250MBPS	15
+#define RCAR_CSI_275MBPS	16
+#define RCAR_CSI_300MBPS	17
+#define RCAR_CSI_325MBPS	18
+#define RCAR_CSI_350MBPS	19
+#define RCAR_CSI_400MBPS	20
+#define RCAR_CSI_450MBPS	21
+#define RCAR_CSI_500MBPS	22
+#define RCAR_CSI_550MBPS	23
+#define RCAR_CSI_600MBPS	24
+#define RCAR_CSI_650MBPS	25
+#define RCAR_CSI_700MBPS	26
+#define RCAR_CSI_750MBPS	27
+#define RCAR_CSI_800MBPS	28
+#define RCAR_CSI_850MBPS	29
+#define RCAR_CSI_900MBPS	30
+#define RCAR_CSI_950MBPS	31
+#define RCAR_CSI_1000MBPS	32
+#define RCAR_CSI_1050MBPS	33
+#define RCAR_CSI_1100MBPS	34
+#define RCAR_CSI_1150MBPS	35
+#define RCAR_CSI_1200MBPS	36
+#define RCAR_CSI_1250MBPS	37
+#define RCAR_CSI_1300MBPS	38
+#define RCAR_CSI_1350MBPS	39
+#define RCAR_CSI_1400MBPS	40
+#define RCAR_CSI_1450MBPS	41
+#define RCAR_CSI_1500MBPS	42
+
+static int rcar_csi2_set_phy_freq(struct rcar_csi2 *priv)
+{
+	const uint32_t const hs_freq_range[43] = {
+		0x00, 0x10, 0x20, 0x30, 0x01,  /* 0-4   */
+		0x11, 0x21, 0x31, 0x02, 0x12,  /* 5-9   */
+		0x22, 0x32, 0x03, 0x13, 0x23,  /* 10-14 */
+		0x33, 0x04, 0x14, 0x05, 0x15,  /* 15-19 */
+		0x25, 0x06, 0x16, 0x07, 0x17,  /* 20-24 */
+		0x08, 0x18, 0x09, 0x19, 0x29,  /* 25-29 */
+		0x39, 0x0A, 0x1A, 0x2A, 0x3A,  /* 30-34 */
+		0x0B, 0x1B, 0x2B, 0x3B, 0x0C,  /* 35-39 */
+		0x1C, 0x2C, 0x3C               /* 40-42 */
+	};
+	uint32_t bps_per_lane = RCAR_CSI_190MBPS;
+
+	dev_dbg(&priv->pdev->dev, "Input size (%dx%d%c)\n",
+			 priv->mf->width, priv->mf->height,
+			 (priv->mf->field == V4L2_FIELD_NONE) ? 'p' : 'i');
+
+	switch (priv->lanes) {
+	case 1:
+		bps_per_lane = RCAR_CSI_400MBPS;
+		break;
+	case 4:
+		if (priv->mf->field == V4L2_FIELD_NONE) {
+			if ((priv->mf->width == 1920) &&
+				(priv->mf->height == 1080))
+				bps_per_lane = RCAR_CSI_900MBPS;
+			else if ((priv->mf->width == 1280) &&
+				 (priv->mf->height == 720))
+				bps_per_lane = RCAR_CSI_450MBPS;
+			else if ((priv->mf->width == 720) &&
+				 (priv->mf->height == 480))
+				bps_per_lane = RCAR_CSI_190MBPS;
+			else if ((priv->mf->width == 720) &&
+				 (priv->mf->height == 576))
+				bps_per_lane = RCAR_CSI_190MBPS;
+			else if ((priv->mf->width == 640) &&
+				 (priv->mf->height == 480))
+				bps_per_lane = RCAR_CSI_100MBPS;
+			else
+				goto error;
+		} else {
+			if ((priv->mf->width == 1920) &&
+				(priv->mf->height == 1080))
+				bps_per_lane = RCAR_CSI_450MBPS;
+			else
+				goto error;
+		}
+		break;
+	default:
+		dev_err(&priv->pdev->dev, "ERROR: lanes is invalid (%d)\n",
+								 priv->lanes);
+		return -EINVAL;
+	}
+
+	dev_dbg(&priv->pdev->dev, "bps_per_lane (%d)\n", bps_per_lane);
+
+	iowrite32((hs_freq_range[bps_per_lane] << 16),
+				priv->base + RCAR_CSI2_PHYPLL);
+	return 0;
+
+error:
+	dev_err(&priv->pdev->dev, "Not support resolution (%dx%d%c)\n",
+		 priv->mf->width, priv->mf->height,
+		 (priv->mf->field == V4L2_FIELD_NONE) ? 'p' : 'i');
+	return -EINVAL;
+}
+
+static irqreturn_t rcar_csi2_irq(int irq, void *data)
+{
+	struct rcar_csi2 *priv = data;
+	u32 int_status;
+	unsigned int handled = 0;
+
+	spin_lock(&priv->lock);
+
+	int_status = ioread32(priv->base + RCAR_CSI2_INTSTATE);
+	if (!int_status)
+		goto done;
+
+	/* ack interrupts */
+	iowrite32(int_status, priv->base + RCAR_CSI2_INTSTATE);
+	handled = 1;
+
+done:
+	spin_unlock(&priv->lock);
+
+	return IRQ_RETVAL(handled);
+
+}
+
+static void rcar_csi2_hwdeinit(struct rcar_csi2 *priv)
+{
+	iowrite32(0, priv->base + RCAR_CSI2_PHYCNT);
+
+	/* reset CSI2 hardware */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_SRST);
+}
+
+static int rcar_csi2_hwinit(struct rcar_csi2 *priv)
+{
+	int ret;
+	__u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+	/* Reflect registers immediately */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_TREF);
+	/* reset CSI2 hardware */
+	iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
+	udelay(5);
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_SRST);
+
+	iowrite32(0x00000000, priv->base + RCAR_CSI2_PHTC);
+
+	/* setting HS reception frequency */
+	{
+		switch (priv->lanes) {
+		case 1:
+			/* First field number setting */
+			iowrite32(0x0001000f, priv->base + RCAR_CSI2_FLD);
+			tmp |= 0x1;
+			break;
+		case 4:
+			/* First field number setting */
+			iowrite32(0x0002000f, priv->base + RCAR_CSI2_FLD);
+			tmp |= 0xF;
+			break;
+		default:
+			dev_err(&priv->pdev->dev,
+				"ERROR: lanes is invalid (%d)\n",
+				priv->lanes);
+			return -EINVAL;
+		}
+
+		/* set PHY frequency */
+		ret = rcar_csi2_set_phy_freq(priv);
+		if (ret < 0)
+			return ret;
+
+		/* Enable lanes */
+		iowrite32(tmp, priv->base + RCAR_CSI2_PHYCNT);
+
+		iowrite32(tmp | RCAR_CSI2_PHYCNT_SHUTDOWNZ,
+					priv->base + RCAR_CSI2_PHYCNT);
+		iowrite32(tmp | (RCAR_CSI2_PHYCNT_SHUTDOWNZ |
+					RCAR_CSI2_PHYCNT_RSTZ),
+					priv->base + RCAR_CSI2_PHYCNT);
+	}
+
+	iowrite32(0x00000003, priv->base + RCAR_CSI2_CHKSUM);
+	iowrite32(priv->vcdt, priv->base + RCAR_CSI2_VCDT);
+	iowrite32(priv->vcdt2, priv->base + RCAR_CSI2_VCDT2);
+	iowrite32(0x00010000, priv->base + RCAR_CSI2_FRDT);
+	udelay(10);
+	iowrite32(0x83000000, priv->base + RCAR_CSI2_LINKCNT);
+	iowrite32(0x000000e4, priv->base + RCAR_CSI2_LSWAP);
+
+	dev_dbg(&priv->pdev->dev, "CSI2 VCDT:  0x%x\n",
+			 ioread32(priv->base + RCAR_CSI2_VCDT));
+	dev_dbg(&priv->pdev->dev, "CSI2 VCDT2: 0x%x\n",
+			 ioread32(priv->base + RCAR_CSI2_VCDT2));
+
+	/* wait until video decoder power off */
+	msleep(10);
+	{
+		int timeout = 100;
+
+		/* Read the PHY clock lane monitor register (PHCLM). */
+		while (!(ioread32(priv->base + RCAR_CSI2_PHCLM) & 0x01)
+			&& timeout) {
+			timeout--;
+		}
+		if (timeout == 0)
+			dev_err(&priv->pdev->dev,
+				"Timeout of reading the PHY clock lane\n");
+		else
+			dev_dbg(&priv->pdev->dev,
+				"Detected the PHY clock lane\n");
+
+		timeout = 100;
+
+		/* Read the PHY data lane monitor register (PHDLM). */
+		while (!(ioread32(priv->base + RCAR_CSI2_PHDLM) & 0x01)
+			&& timeout) {
+			timeout--;
+		}
+		if (timeout == 0)
+			dev_err(&priv->pdev->dev,
+				"Timeout of reading the PHY data lane\n");
+		else
+			dev_dbg(&priv->pdev->dev,
+				"Detected the PHY data lane\n");
+	}
+
+	return 0;
+}
+
+static int rcar_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct rcar_csi2 *priv = container_of(sd, struct rcar_csi2, subdev);
+	struct v4l2_subdev *tmp_sd;
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_mbus_framefmt *mf = &fmt.format;
+	int ret = 0;
+
+	if (on) {
+		v4l2_device_for_each_subdev(tmp_sd, sd->v4l2_dev) {
+			if (strncmp(tmp_sd->name, CONNECT_SLAVE_NAME,
+				sizeof(CONNECT_SLAVE_NAME) - 1) == 0) {
+				v4l2_subdev_call(tmp_sd, pad, get_fmt,
+							 NULL, &fmt);
+				if (ret < 0)
+					return ret;
+			}
+		}
+		priv->mf = mf;
+		pm_runtime_get_sync(&priv->pdev->dev);
+		ret = rcar_csi2_hwinit(priv);
+		if (ret < 0)
+			return ret;
+	} else {
+		rcar_csi2_hwdeinit(priv);
+		pm_runtime_put_sync(&priv->pdev->dev);
+	}
+
+	return ret;
+}
+
+static struct v4l2_subdev_core_ops rcar_csi2_subdev_core_ops = {
+	.s_power	= rcar_csi2_s_power,
+};
+
+static struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
+	.core	= &rcar_csi2_subdev_core_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rcar_csi2_of_table[] = {
+	{ .compatible = "renesas,csi2-r8a7796", .data = (void *)RCAR_GEN3 },
+	{ .compatible = "renesas,csi2-r8a7795", .data = (void *)RCAR_GEN3 },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
+#endif
+
+static struct platform_device_id rcar_csi2_id_table[] = {
+	{ "r8a7796-csi2",  RCAR_GEN3 },
+	{ "r8a7795-csi2",  RCAR_GEN3 },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, rcar_csi2_id_table);
+
+static int rcar_csi2_parse_dt(struct device_node *np,
+			struct rcar_csi2_link_config *config)
+{
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *endpoint;
+	struct device_node *vc_np, *vc_ch;
+	const char *str;
+	char csi_name[9];
+	int ret;
+	int i, ch;
+
+	/* Parse the endpoint. */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint)
+		return -EINVAL;
+
+	v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+	of_node_put(endpoint);
+
+	config->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+
+	ret = of_property_read_string(np, "adi,input-interface", &str);
+	if (ret < 0)
+		return ret;
+
+	vc_np = of_get_child_by_name(np, "virtual,channel");
+
+	config->vcdt = 0;
+	config->vcdt2 = 0;
+	for (i = 0; i < VC_MAX_CHANNEL; i++) {
+		sprintf(csi_name, "csi2_vc%d", i);
+
+		vc_ch = of_get_child_by_name(vc_np, csi_name);
+		if (!vc_ch)
+			continue;
+		ret = of_property_read_string(vc_ch, "data,type", &str);
+		if (ret < 0)
+			return ret;
+		ret = of_property_read_u32(vc_ch, "receive,vc", &ch);
+		if (ret < 0)
+			return ret;
+
+		if (i < 2) {
+			if (!strcmp(str, "rgb888"))
+				config->vcdt |= (0x24 << (i * 16));
+			else if (!strcmp(str, "ycbcr422"))
+				config->vcdt |= (0x1e << (i * 16));
+			else
+				config->vcdt |= 0;
+
+			config->vcdt |= (ch << (8 + (i * 16)));
+			config->vcdt |= (RCAR_CSI2_VCDT_VCDTN_EN << (i * 16)) |
+					(RCAR_CSI2_VCDT_SEL_DTN_ON << (i * 16));
+		}
+		if (i >= 2) {
+			int j = (i - 2);
+
+			if (!strcmp(str, "rgb888"))
+				config->vcdt2 |= (0x24 << (j * 16));
+			else if (!strcmp(str, "ycbcr422"))
+				config->vcdt2 |= (0x1e << (j * 16));
+			else
+				config->vcdt2 |= 0;
+
+			config->vcdt2 |= (ch << (8 + (j * 16)));
+			config->vcdt2 |= (RCAR_CSI2_VCDT_VCDTN_EN << (j * 16)) |
+					(RCAR_CSI2_VCDT_SEL_DTN_ON << (j * 16));
+		}
+	}
+
+	return 0;
+}
+
+static int rcar_csi2_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned int irq;
+	int ret;
+	struct rcar_csi2 *priv;
+	/* Platform data specify the PHY, lanes, ECC, CRC */
+	struct rcar_csi2_pdata *pdata;
+	struct rcar_csi2_link_config link_config;
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	INIT_RCAR_CSI2_LINK_CONFIG(link_config);
+
+	if (pdev->dev.of_node) {
+		ret = rcar_csi2_parse_dt(pdev->dev.of_node, &link_config);
+		if (ret)
+			return ret;
+
+		if (link_config.lanes == 4)
+			dev_info(&pdev->dev,
+				"Detected rgb888 in rcar_csi2_parse_dt\n");
+		else
+			dev_info(&pdev->dev,
+				"Detected YCbCr422 in rcar_csi2_parse_dt\n");
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdata)
+			return -EINVAL;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct rcar_csi2), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	/* Interrupt unused so far */
+	irq = platform_get_irq(pdev, 0);
+
+	if (!res || (int)irq <= 0) {
+		dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+		return -ENODEV;
+	}
+
+	priv->irq = irq;
+
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	ret = devm_request_irq(&pdev->dev, irq, rcar_csi2_irq, IRQF_SHARED,
+			       dev_name(&pdev->dev), priv);
+	if (ret)
+		return ret;
+
+	priv->pdev = pdev;
+	priv->subdev.owner = THIS_MODULE;
+	priv->subdev.dev = &pdev->dev;
+	priv->lanes = link_config.lanes;
+	priv->vcdt = link_config.vcdt;
+	priv->vcdt2 = link_config.vcdt2;
+
+	platform_set_drvdata(pdev, &priv->subdev);
+
+	v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
+	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+	snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "rcar_csi2.%s",
+		 dev_name(&pdev->dev));
+
+	ret = v4l2_async_register_subdev(&priv->subdev);
+	if (ret < 0)
+		return ret;
+
+	spin_lock_init(&priv->lock);
+
+	pm_runtime_enable(&pdev->dev);
+
+	dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+	return 0;
+}
+
+static int rcar_csi2_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+	struct rcar_csi2 *priv = container_of(subdev, struct rcar_csi2, subdev);
+
+	v4l2_async_unregister_subdev(&priv->subdev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_csi2_suspend(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static int rcar_csi2_resume(struct device *dev)
+{
+	/* Empty function for now */
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_csi2_pm_ops,
+			rcar_csi2_suspend, rcar_csi2_resume);
+#define DEV_PM_OPS (&rcar_csi2_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver __refdata rcar_csi2_pdrv = {
+	.remove	= rcar_csi2_remove,
+	.probe	= rcar_csi2_probe,
+	.driver	= {
+		.name	= DRV_NAME,
+		.pm	= DEV_PM_OPS,
+		.of_match_table	= of_match_ptr(rcar_csi2_of_table),
+	},
+	.id_table	= rcar_csi2_id_table,
+};
+
+module_platform_driver(rcar_csi2_pdrv);
+
+MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:rcar-csi2");
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 7653da3..0c0027e 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -1,6 +1,7 @@
 /*
  * SoC-camera host driver for Renesas R-Car VIN unit
  *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2011-2013 Renesas Solutions Corp.
  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
  *
@@ -14,6 +15,10 @@
  * option) any later version.
  */
 
+#ifdef CONFIG_VIDEO_RCAR_VIN_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -25,6 +30,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <linux/list.h>
 
 #include <media/soc_camera.h>
 #include <media/drv-intf/soc_mediabus.h>
@@ -36,6 +42,8 @@
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-dma-contig.h>
 
+#include <media/rcar_csi2.h>
+
 #include "soc_scale_crop.h"
 
 #define DRV_NAME "rcar_vin"
@@ -90,6 +98,8 @@
 
 /* Register bit fields for R-Car VIN */
 /* Video n Main Control Register bits */
+#define VNMC_DPINE		(1 << 27)
+#define VNMC_SCLE		(1 << 26)
 #define VNMC_FOC		(1 << 21)
 #define VNMC_YCAL		(1 << 19)
 #define VNMC_INF_YUV8_BT656	(0 << 16)
@@ -98,6 +108,7 @@
 #define VNMC_INF_YUV10_BT601	(3 << 16)
 #define VNMC_INF_YUV16		(5 << 16)
 #define VNMC_INF_RGB888		(6 << 16)
+#define VNMC_INF_MASK		(7 << 16)
 #define VNMC_VUP		(1 << 10)
 #define VNMC_IM_ODD		(0 << 3)
 #define VNMC_IM_ODD_EVEN	(1 << 3)
@@ -119,12 +130,19 @@
 /* Video n Interrupt Enable Register bits */
 #define VNIE_FIE		(1 << 4)
 #define VNIE_EFE		(1 << 1)
+#define VNIE_FOE		(1 << 0)
+
+/* Video n Interrupt Status Register bits */
+#define VNINTS_FIS		(1 << 4)
+#define VNINTS_EFS		(1 << 1)
+#define VNINTS_FOS		(1 << 0)
 
 /* Video n Data Mode Register bits */
 #define VNDMR_EXRGB		(1 << 8)
 #define VNDMR_BPSM		(1 << 4)
 #define VNDMR_DTMD_YCSEP	(1 << 1)
 #define VNDMR_DTMD_ARGB		(1 << 0)
+#define VNDMR_DTMD_YCSEP_YCBCR420	(3 << 0)
 
 /* Video n Data Mode Register 2 bits */
 #define VNDMR2_VPS		(1 << 30)
@@ -132,8 +150,25 @@
 #define VNDMR2_FTEV		(1 << 17)
 #define VNDMR2_VLV(n)		((n & 0xf) << 12)
 
-#define VIN_MAX_WIDTH		2048
-#define VIN_MAX_HEIGHT		2048
+/* setting CSI2 on R-Car Gen3*/
+#define VNCSI_IFMD_REG	0x20	/* Video n CSI2 Interface Mode Register */
+
+#define VNCSI_IFMD_DES1		(1 << 26) /* CSI20 */
+#define VNCSI_IFMD_DES0		(1 << 25) /* H3:CSI40/41, M3:CSI40 */
+
+#define VNCSI_IFMD_CSI_CHSEL(n)	(n << 0)
+#define VNCSI_IFMD_SEL_NUMBER	5
+
+/* UDS */
+#define VNUDS_CTRL_REG		0x80	/* Scaling Control Registers */
+#define VNUDS_CTRL_AMD		(1 << 30)
+#define VNUDS_CTRL_BC		(1 << 20)
+#define VNUDS_CTRL_TDIPC	(1 << 1)
+
+#define VNUDS_SCALE_REG		0x84	/* Scaling Factor Register */
+#define VNUDS_PASS_BWIDTH_REG	0x90	/* Passband Registers */
+#define VNUDS_IPC_REG		0x98	/* 2D IPC Setting Register */
+#define VNUDS_CLIP_SIZE_REG	0xA4	/* UDS Output Size Clipping Register */
 
 #define TIMEOUT_MS		100
 
@@ -141,15 +176,196 @@
 #define RCAR_VIN_VSYNC_ACTIVE_LOW	(1 << 1)
 #define RCAR_VIN_BT601			(1 << 2)
 #define RCAR_VIN_BT656			(1 << 3)
+#define RCAR_VIN_CSI2			(1 << 4)
+
+static int ifmd0_reg_match[VNCSI_IFMD_SEL_NUMBER];
+static int ifmd4_reg_match[VNCSI_IFMD_SEL_NUMBER];
+static int ifmd0_init = true;
+static int ifmd4_init = true;
 
 enum chip_id {
 	RCAR_GEN3,
+	RCAR_M3,
+	RCAR_H3,
 	RCAR_GEN2,
 	RCAR_H1,
 	RCAR_M1,
 	RCAR_E1,
 };
 
+enum csi2_ch {
+	RCAR_CSI_CH_NONE = -1,
+	RCAR_CSI40,
+	RCAR_CSI20,
+	RCAR_CSI41,
+	RCAR_CSI21,
+	RCAR_CSI_MAX,
+};
+
+enum gen3_vin_ch {
+	RCAR_VIN_CH_NONE = -1,
+	RCAR_VIDEO_0,
+	RCAR_VIDEO_1,
+	RCAR_VIDEO_2,
+	RCAR_VIDEO_3,
+	RCAR_VIDEO_4,
+	RCAR_VIDEO_5,
+	RCAR_VIDEO_6,
+	RCAR_VIDEO_7,
+	RCAR_VIDEO_MAX,
+};
+
+enum virtual_ch {
+	RCAR_VIRTUAL_NONE = -1,
+	RCAR_VIRTUAL_CH0,
+	RCAR_VIRTUAL_CH1,
+	RCAR_VIRTUAL_CH2,
+	RCAR_VIRTUAL_CH3,
+	RCAR_VIRTUAL_MAX,
+};
+
+struct vin_gen3_virtual_sel {
+	enum csi2_ch csi2_ch;
+	enum virtual_ch vc;
+};
+
+struct vin_gen3_ifmd {
+	unsigned int set_reg;
+	struct vin_gen3_virtual_sel v_sel[8];
+};
+
+static const struct vin_gen3_ifmd vin_h3_vc_ifmd[] = {
+	{ 0x0000,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0001,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0002,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0003,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI41, RCAR_VIRTUAL_CH3},
+		}
+	},
+	{ 0x0004,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+		}
+	},
+};
+
+static const struct vin_gen3_ifmd vin_m3_vc_ifmd[] = {
+	{ 0x0000,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0001,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+		}
+	},
+	{ 0x0002,
+		{
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI_CH_NONE, RCAR_VIN_CH_NONE},
+		}
+	},
+	{ 0x0003,
+		{
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI40, RCAR_VIRTUAL_CH3},
+		}
+	},
+	{ 0x0004,
+		{
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH0},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH1},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH2},
+			{RCAR_CSI20, RCAR_VIRTUAL_CH3},
+		}
+	},
+};
+
+enum csi2_fmt {
+	RCAR_CSI_FMT_NONE = -1,
+	RCAR_CSI_RGB888,
+	RCAR_CSI_YCBCR422,
+};
+
 struct vin_coeff {
 	unsigned short xs_value;
 	u32 coeff_set[24];
@@ -474,6 +690,19 @@
 	STOPPING,
 };
 
+struct rcar_vin_async_client {
+	struct v4l2_async_subdev *sensor;
+	struct v4l2_async_notifier notifier;
+	struct platform_device *pdev;
+	struct list_head list;		/* needed for clean up */
+};
+
+struct soc_of_info {
+	struct soc_camera_async_subdev	sasd;
+	struct rcar_vin_async_client	sasc;
+	struct v4l2_async_subdev	*subdev;
+};
+
 struct rcar_vin_priv {
 	void __iomem			*base;
 	spinlock_t			lock;
@@ -492,6 +721,23 @@
 	bool				request_to_stop;
 	struct completion		capture_stop;
 	enum chip_id			chip;
+	unsigned int			max_width;
+	unsigned int			max_height;
+	unsigned int			ratio_h;
+	unsigned int			ratio_v;
+	bool				error_flag;
+	enum csi2_ch			csi_ch;
+	enum csi2_fmt			csi_fmt;
+	enum virtual_ch			vc;
+	bool				csi_sync;
+
+	struct rcar_vin_async_client	*async_client;
+	/* Asynchronous CSI2 linking */
+	struct v4l2_subdev		*csi2_sd;
+	/* Synchronous probing compatibility */
+	struct platform_device		*csi2_pdev;
+
+	unsigned int			index;
 };
 
 #define is_continuous_transfer(priv)	(priv->vb_count > MAX_BUFFER_NUM)
@@ -526,6 +772,69 @@
 	const struct soc_mbus_pixelfmt	*extra_fmt;
 };
 
+#define VIN_UT_IRQ	0x01
+
+static unsigned int vin_debug;
+module_param_named(debug, vin_debug, int, 0600);
+static int overflow_video[RCAR_VIDEO_MAX];
+module_param_array(overflow_video, int, NULL, 0600);
+
+#ifdef CONFIG_VIDEO_RCAR_VIN_DEBUG
+#define VIN_IRQ_DEBUG(fmt, args...)					\
+	do {								\
+		if (unlikely(vin_debug & VIN_UT_IRQ))			\
+			vin_ut_debug_printk(__func__, fmt, ##args);	\
+	} while (0)
+#else
+#define VIN_IRQ_DEBUG(fmt, args...)
+#endif
+
+void vin_ut_debug_printk(const char *function_name, const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	pr_debug("[" DRV_NAME ":%s] %pV", function_name, &vaf);
+
+	va_end(args);
+}
+
+static void rcar_vin_cpg_enable_for_ifmd(unsigned int ch, bool enable)
+{
+	void __iomem *smstpcr8;
+
+	smstpcr8 = ioremap(0xE6150990, 0x04);
+
+	if (enable) {
+		if (ch < RCAR_VIDEO_4)
+			iowrite32((ioread32(smstpcr8) & 0xFFFFF7FF), smstpcr8);
+		else
+			iowrite32((ioread32(smstpcr8) & 0xFFFFFF7F), smstpcr8);
+	} else {
+		if (ch < RCAR_VIDEO_4)
+			iowrite32((ioread32(smstpcr8) | 0x00000800), smstpcr8);
+		else
+			iowrite32((ioread32(smstpcr8) | 0x00000080), smstpcr8);
+	}
+
+	iounmap(smstpcr8);
+}
+
+static inline int is_scaling(struct rcar_vin_cam *cam)
+{
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+
+	if ((cam_subrect->width != cam->out_width) ||
+		(cam_subrect->height != cam->out_height))
+		return 1;
+
+	return 0;
+}
+
 /*
  * .queue_setup() is called to check whether the driver can accept the requested
  * number of buffers and to fill in plane sizes for the current frame format if
@@ -539,6 +848,22 @@
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct rcar_vin_priv *priv = ici->priv;
+	struct rcar_vin_cam *cam = icd->host_priv;
+
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		if ((priv->ratio_h > 0x10000) || (priv->ratio_v > 0x10000)) {
+			dev_err(icd->parent, "Scaling rate parameter error\n");
+			return -EINVAL;
+		}
+		if (is_scaling(cam) && (cam->out_width % 32)) {
+			dev_err(icd->parent, "Scaling parameter error\n");
+			return -EINVAL;
+		}
+		if (!is_scaling(cam) && (cam->out_width % 16)) {
+			dev_err(icd->parent, "Image stride parameter error\n");
+			return -EINVAL;
+		}
+	}
 
 	alloc_ctxs[0] = priv->alloc_ctx;
 
@@ -628,8 +953,19 @@
 
 	/* output format */
 	switch (icd->current_fmt->host_fmt->fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+			iowrite32(ALIGN((cam->out_width * cam->out_height),
+					 0x80), priv->base + VNUVAOF_REG);
+			dmr = VNDMR_DTMD_YCSEP_YCBCR420;
+			output_is_yuv = true;
+		} else {
+			dev_warn(icd->parent, "Not support format\n");
+			return -EINVAL;
+		}
+		break;
 	case V4L2_PIX_FMT_NV16:
-		iowrite32(ALIGN(cam->width * cam->height, 0x80),
+		iowrite32(ALIGN((cam->out_width * cam->out_height), 0x80),
 			  priv->base + VNUVAOF_REG);
 		dmr = VNDMR_DTMD_YCSEP;
 		output_is_yuv = true;
@@ -642,21 +978,22 @@
 		dmr = 0;
 		output_is_yuv = true;
 		break;
-	case V4L2_PIX_FMT_RGB555X:
+	case V4L2_PIX_FMT_ARGB555:
 		dmr = VNDMR_DTMD_ARGB;
 		break;
 	case V4L2_PIX_FMT_RGB565:
 		dmr = 0;
 		break;
-	case V4L2_PIX_FMT_RGB32:
-		if (priv->chip != RCAR_GEN2 && priv->chip != RCAR_H1 &&
+	case V4L2_PIX_FMT_XBGR32:
+		if (priv->chip != RCAR_H3 && priv->chip != RCAR_M3 &&
+		    priv->chip != RCAR_GEN2 && priv->chip != RCAR_H1 &&
 		    priv->chip != RCAR_E1)
 			goto e_format;
 
 		dmr = VNDMR_EXRGB;
 		break;
-	case V4L2_PIX_FMT_ARGB32:
-		if (priv->chip != RCAR_GEN3)
+	case V4L2_PIX_FMT_ABGR32:
+		if (priv->chip != RCAR_H3 && priv->chip != RCAR_M3)
 			goto e_format;
 
 		dmr = VNDMR_EXRGB | VNDMR_DTMD_ARGB;
@@ -672,9 +1009,24 @@
 	if (input_is_yuv == output_is_yuv)
 		vnmc |= VNMC_BPS;
 
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		if (priv->pdata_flags & RCAR_VIN_CSI2)
+			vnmc &= ~VNMC_DPINE;
+		else
+			vnmc |= VNMC_DPINE;
+
+		if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+			&& is_scaling(cam))
+			vnmc |= VNMC_SCLE;
+	}
+
 	/* progressive or interlaced mode */
 	interrupts = progressive ? VNIE_FIE : VNIE_EFE;
 
+	/* Enable Overflow */
+	if (vin_debug)
+		interrupts |= VNIE_FOE;
+
 	/* ack interrupts */
 	iowrite32(interrupts, priv->base + VNINTS_REG);
 	/* enable interrupts */
@@ -874,16 +1226,25 @@
 	bool can_run = false, hw_stopped;
 	int slot;
 	unsigned int handled = 0;
+	int vin_ovr_cnt = 0;
 
 	spin_lock(&priv->lock);
 
 	int_status = ioread32(priv->base + VNINTS_REG);
 	if (!int_status)
 		goto done;
+
 	/* ack interrupts */
 	iowrite32(int_status, priv->base + VNINTS_REG);
 	handled = 1;
 
+	/* overflow occurs */
+	if (vin_debug && (int_status & VNINTS_FOS)) {
+		vin_ovr_cnt = ++overflow_video[priv->index];
+		VIN_IRQ_DEBUG("overflow occurrs num[%d] at VIN (%s)\n",
+				vin_ovr_cnt, dev_name(priv->ici.v4l2_dev.dev));
+	}
+
 	/* nothing to do if capture status is 'STOPPED' */
 	if (priv->state == STOPPED)
 		goto done;
@@ -897,31 +1258,36 @@
 		else
 			slot = 0;
 
-		priv->queue_buf[slot]->field = priv->field;
-		priv->queue_buf[slot]->sequence = priv->sequence++;
-		priv->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
-		vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf,
-				VB2_BUF_STATE_DONE);
-		priv->queue_buf[slot] = NULL;
+		if (!is_continuous_transfer(priv) || ((priv->state == RUNNING)
+			&& !list_empty(&priv->capture))) {
+			priv->queue_buf[slot]->field = priv->field;
+			priv->queue_buf[slot]->sequence = priv->sequence++;
+			priv->queue_buf[slot]->vb2_buf.timestamp =
+							 ktime_get_ns();
+			vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf,
+							VB2_BUF_STATE_DONE);
+			priv->queue_buf[slot] = NULL;
 
-		if (priv->state != STOPPING)
 			can_run = rcar_vin_fill_hw_slot(priv);
-
-		if (hw_stopped || !can_run) {
-			priv->state = STOPPED;
-		} else if (is_continuous_transfer(priv) &&
-			   list_empty(&priv->capture) &&
-			   priv->state == RUNNING) {
-			/*
-			 * The continuous capturing requires an explicit stop
-			 * operation when there is no buffer to be set into
-			 * the VnMBm registers.
-			 */
-			rcar_vin_request_capture_stop(priv);
-		} else {
-			rcar_vin_capture(priv);
 		}
 
+		if (is_continuous_transfer(priv)) {
+			if (hw_stopped)
+				priv->state = STOPPED;
+			else if (list_empty(&priv->capture) &&
+				priv->state == RUNNING)
+				/*
+				 * The continuous capturing requires an
+				 * explicit stop operation when there is no
+				 * buffer to be set into the VnMBm registers.
+				 */
+				rcar_vin_request_capture_stop(priv);
+		} else {
+			if (can_run)
+				rcar_vin_capture(priv);
+			else
+				priv->state = STOPPED;
+		}
 	} else if (hw_stopped) {
 		priv->state = STOPPED;
 		priv->request_to_stop = false;
@@ -934,6 +1300,21 @@
 	return IRQ_RETVAL(handled);
 }
 
+static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev)
+{
+	struct v4l2_subdev *sd;
+	char name[] = "rcar_csi2";
+
+	v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) {
+		if (!strncmp(name, sd->name, sizeof(name) - 1)) {
+			pcdev->csi2_sd = sd;
+			return sd;
+		}
+	}
+
+	return NULL;
+}
+
 static int rcar_vin_add_device(struct soc_camera_device *icd)
 {
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -945,8 +1326,40 @@
 
 	pm_runtime_get_sync(ici->v4l2_dev.dev);
 
-	dev_dbg(icd->parent, "R-Car VIN driver attached to camera %d\n",
-		icd->devnum);
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		struct v4l2_subdev *csi2_sd = find_csi2(priv);
+		int ret;
+
+		if (csi2_sd) {
+			csi2_sd->grp_id = soc_camera_grp_id(icd);
+			v4l2_set_subdev_hostdata(csi2_sd, icd);
+
+			ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
+			priv->csi_sync = true;
+
+			if (ret < 0 && ret != -EINVAL)
+				priv->csi_sync = false;
+
+			if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+				return ret;
+		}
+		/*
+		 * -ENODEV is special:
+		 * either csi2_sd == NULL or the CSI-2 driver
+		 * has not found this soc-camera device among its clients
+		 */
+		if (csi2_sd && ret == -ENODEV)
+			csi2_sd->grp_id = 0;
+
+		dev_dbg(icd->parent,
+			"R-Car VIN/CSI-2 driver attached to camera %d\n",
+			icd->devnum);
+
+	} else
+		dev_dbg(icd->parent, "R-Car VIN driver attached to camera %d\n",
+			icd->devnum);
+
+	priv->error_flag = false;
 
 	return 0;
 }
@@ -956,6 +1369,7 @@
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct rcar_vin_priv *priv = ici->priv;
 	struct vb2_v4l2_buffer *vbuf;
+	struct v4l2_subdev *csi2_sd = find_csi2(priv);
 	int i;
 
 	/* disable capture, disable interrupts */
@@ -965,6 +1379,7 @@
 
 	priv->state = STOPPED;
 	priv->request_to_stop = false;
+	priv->error_flag = false;
 
 	/* make sure active buffer is cancelled */
 	spin_lock_irq(&priv->lock);
@@ -979,10 +1394,83 @@
 
 	pm_runtime_put(ici->v4l2_dev.dev);
 
+	if ((csi2_sd) && (priv->csi_sync))
+		v4l2_subdev_call(csi2_sd, core, s_power, 0);
+
 	dev_dbg(icd->parent, "R-Car VIN driver detached from camera %d\n",
 		icd->devnum);
 }
 
+struct rcar_vin_uds_regs {
+	unsigned long ctrl;
+	unsigned long scale;
+	unsigned long pass_bwidth;
+	unsigned long clip_size;
+};
+
+static unsigned long rcar_vin_get_bwidth(unsigned long ratio)
+{
+	unsigned long bwidth;
+	unsigned long mant, frac;
+
+	mant = (ratio & 0xF000) >> 12;
+	frac = ratio & 0x0FFF;
+	if (mant)
+		bwidth = 64 * 4096 * mant / (4096 * mant + frac);
+	else
+		bwidth = 64;
+
+	return bwidth;
+}
+
+static unsigned long rcar_vin_compute_ratio(unsigned int input,
+		unsigned int output)
+{
+	return ((input * 4096 / output) == 0x10000) ?
+		 0xFFFF : (input * 4096 / output);
+}
+
+int rcar_vin_uds_set(struct rcar_vin_priv *priv, struct rcar_vin_cam *cam)
+{
+	struct rcar_vin_uds_regs regs;
+	unsigned long ratio_h, ratio_v;
+	unsigned long bwidth_h, bwidth_v;
+	unsigned long ctrl;
+	unsigned long clip_size;
+	struct v4l2_rect *cam_subrect = &cam->subrect;
+	u32 vnmc;
+
+	ratio_h = rcar_vin_compute_ratio(cam_subrect->width, cam->out_width);
+	ratio_v = rcar_vin_compute_ratio(cam_subrect->height, cam->out_height);
+
+	priv->ratio_h = ratio_h;
+	priv->ratio_v = ratio_v;
+
+	bwidth_h = rcar_vin_get_bwidth(ratio_h);
+	bwidth_v = rcar_vin_get_bwidth(ratio_v);
+
+	ctrl = VNUDS_CTRL_AMD;
+
+	if (priv->field == V4L2_FIELD_NONE)
+		clip_size = (cam->out_width << 16) | (cam->out_height);
+	else
+		clip_size = (cam->out_width << 16) | (cam->out_height / 2);
+
+	regs.ctrl = ctrl;
+	regs.scale = (ratio_h << 16) | ratio_v;
+	regs.pass_bwidth = (bwidth_h << 16) | bwidth_v;
+	regs.clip_size = clip_size;
+
+	vnmc = ioread32(priv->base + VNMC_REG);
+	iowrite32(vnmc | VNMC_SCLE, priv->base + VNMC_REG);
+	iowrite32(regs.ctrl, priv->base + VNUDS_CTRL_REG);
+	iowrite32(regs.scale, priv->base + VNUDS_SCALE_REG);
+	iowrite32(regs.pass_bwidth, priv->base + VNUDS_PASS_BWIDTH_REG);
+	iowrite32(regs.clip_size, priv->base + VNUDS_CLIP_SIZE_REG);
+
+	return 0;
+}
+
 static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs)
 {
 	int i;
@@ -1047,6 +1535,7 @@
 	unsigned char dsize = 0;
 	struct v4l2_rect *cam_subrect = &cam->subrect;
 	u32 value;
+	int ret = 0;
 
 	dev_dbg(icd->parent, "Crop %ux%u@%u:%u\n",
 		icd->user_width, icd->user_height, cam->vin_left, cam->vin_top);
@@ -1054,7 +1543,7 @@
 	left_offset = cam->vin_left;
 	top_offset = cam->vin_top;
 
-	if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_RGB32 &&
+	if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_XBGR32 &&
 	    priv->chip == RCAR_E1)
 		dsize = 1;
 
@@ -1083,49 +1572,69 @@
 		break;
 	}
 
-	/* Set scaling coefficient */
-	value = 0;
-	if (cam_subrect->height != cam->out_height)
-		value = (4096 * cam_subrect->height) / cam->out_height;
-	dev_dbg(icd->parent, "YS Value: %x\n", value);
-	iowrite32(value, priv->base + VNYS_REG);
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		if ((icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_NV12)
+			&& is_scaling(cam)) {
+			ret = rcar_vin_uds_set(priv, cam);
+			if (ret < 0)
+				return ret;
+		}
+		if (is_scaling(cam) ||
+		   (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV16) ||
+		   (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV12))
+			iowrite32(ALIGN(cam->out_width, 0x20),
+				 priv->base + VNIS_REG);
+		else
+			iowrite32(ALIGN(cam->out_width, 0x10),
+				 priv->base + VNIS_REG);
+	} else {
+		/* Set scaling coefficient */
+		value = 0;
+		if (cam_subrect->height != cam->out_height)
+			value = (4096 * cam_subrect->height) / cam->out_height;
+		dev_dbg(icd->parent, "YS Value: %x\n", value);
+		iowrite32(value, priv->base + VNYS_REG);
 
-	value = 0;
-	if (cam_subrect->width != cam->out_width)
-		value = (4096 * cam_subrect->width) / cam->out_width;
+		value = 0;
+		if (cam_subrect->width != cam->out_width)
+			value = (4096 * cam_subrect->width) / cam->out_width;
 
-	/* Horizontal upscaling is up to double size */
-	if (0 < value && value < 2048)
-		value = 2048;
+		/* Horizontal upscaling is up to double size */
+		if (value < 2048)
+			value = 2048;
 
-	dev_dbg(icd->parent, "XS Value: %x\n", value);
-	iowrite32(value, priv->base + VNXS_REG);
+		dev_dbg(icd->parent, "XS Value: %x\n", value);
+		iowrite32(value, priv->base + VNXS_REG);
 
-	/* Horizontal upscaling is carried out by scaling down from double size */
-	if (value < 4096)
-		value *= 2;
+		/* Horizontal upscaling is carried out */
+		/* by scaling down from double size */
+		if (value < 4096)
+			value *= 2;
 
-	set_coeff(priv, value);
+		set_coeff(priv, value);
 
-	/* Set Start/End Pixel/Line Post-Clip */
-	iowrite32(0, priv->base + VNSPPOC_REG);
-	iowrite32(0, priv->base + VNSLPOC_REG);
-	iowrite32((cam->out_width - 1) << dsize, priv->base + VNEPPOC_REG);
-	switch (priv->field) {
-	case V4L2_FIELD_INTERLACED:
-	case V4L2_FIELD_INTERLACED_TB:
-	case V4L2_FIELD_INTERLACED_BT:
-		iowrite32(cam->out_height / 2 - 1,
-			  priv->base + VNELPOC_REG);
-		break;
-	default:
-		iowrite32(cam->out_height - 1, priv->base + VNELPOC_REG);
-		break;
+		/* Set Start/End Pixel/Line Post-Clip */
+		iowrite32(0, priv->base + VNSPPOC_REG);
+		iowrite32(0, priv->base + VNSLPOC_REG);
+		iowrite32((cam->out_width - 1) << dsize,
+			priv->base + VNEPPOC_REG);
+		switch (priv->field) {
+		case V4L2_FIELD_INTERLACED:
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+			iowrite32(cam->out_height / 2 - 1,
+				  priv->base + VNELPOC_REG);
+			break;
+		default:
+			iowrite32(cam->out_height - 1,
+				priv->base + VNELPOC_REG);
+			break;
+		}
+
+		iowrite32(ALIGN(cam->out_width, 0x10), priv->base + VNIS_REG);
 	}
 
-	iowrite32(ALIGN(cam->out_width, 0x10), priv->base + VNIS_REG);
-
-	return 0;
+	return ret;
 }
 
 static void capture_stop_preserve(struct rcar_vin_priv *priv, u32 *vnmc)
@@ -1214,7 +1723,17 @@
 	if (ret < 0 && ret != -ENOIOCTLCMD)
 		return ret;
 
-	val = VNDMR2_FTEV | VNDMR2_VLV(1);
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		if (cfg.type == V4L2_MBUS_CSI2)
+			vnmc &= ~VNMC_DPINE;
+		else
+			vnmc |= VNMC_DPINE;
+	}
+
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3)
+		val = VNDMR2_FTEV;
+	else
+		val = VNDMR2_FTEV | VNDMR2_VLV(1);
 	if (!(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
 		val |= VNDMR2_VPS;
 	if (!(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
@@ -1267,6 +1786,14 @@
 
 static const struct soc_mbus_pixelfmt rcar_vin_formats[] = {
 	{
+		.fourcc			= V4L2_PIX_FMT_NV12,
+		.name			= "NV12",
+		.bits_per_sample	= 8,
+		.packing		= SOC_MBUS_PACKING_1_5X8,
+		.order			= SOC_MBUS_ORDER_LE,
+		.layout			= SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+	},
+	{
 		.fourcc			= V4L2_PIX_FMT_NV16,
 		.name			= "NV16",
 		.bits_per_sample	= 8,
@@ -1299,7 +1826,7 @@
 		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 	{
-		.fourcc			= V4L2_PIX_FMT_RGB555X,
+		.fourcc			= V4L2_PIX_FMT_ARGB555,
 		.name			= "ARGB1555",
 		.bits_per_sample	= 16,
 		.packing		= SOC_MBUS_PACKING_NONE,
@@ -1307,7 +1834,7 @@
 		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 	{
-		.fourcc			= V4L2_PIX_FMT_RGB32,
+		.fourcc			= V4L2_PIX_FMT_XBGR32,
 		.name			= "RGB888",
 		.bits_per_sample	= 32,
 		.packing		= SOC_MBUS_PACKING_NONE,
@@ -1315,7 +1842,7 @@
 		.layout			= SOC_MBUS_LAYOUT_PACKED,
 	},
 	{
-		.fourcc			= V4L2_PIX_FMT_ARGB32,
+		.fourcc			= V4L2_PIX_FMT_ABGR32,
 		.name			= "ARGB8888",
 		.bits_per_sample	= 32,
 		.packing		= SOC_MBUS_PACKING_NONE,
@@ -1332,6 +1859,8 @@
 	int ret, k, n;
 	int formats = 0;
 	struct rcar_vin_cam *cam;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct rcar_vin_priv *priv = ici->priv;
 	struct v4l2_subdev_mbus_code_enum code = {
 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
 		.index = idx,
@@ -1382,8 +1911,8 @@
 		 * 1280x960, 640x480, 320x240
 		 */
 		for (shift = 0; shift < 3; shift++) {
-			if (mf->width <= VIN_MAX_WIDTH &&
-			    mf->height <= VIN_MAX_HEIGHT)
+			if (mf->width <= priv->max_width &&
+			    mf->height <= priv->max_height)
 				break;
 
 			mf->width = 1280 >> shift;
@@ -1474,6 +2003,294 @@
 	icd->host_priv = NULL;
 }
 
+static bool rcar_vin_is_smaller(const struct v4l2_rect *r1,
+				const struct v4l2_rect *r2)
+{
+	return r1->width < r2->width || r1->height < r2->height;
+}
+
+static bool rcar_vin_is_inside(const struct v4l2_rect *r1,
+			       const struct v4l2_rect *r2)
+{
+	return r1->left > r2->left || r1->top > r2->top ||
+		r1->left + r1->width < r2->left + r2->width ||
+		r1->top + r1->height < r2->top + r2->height;
+}
+
+static void rcar_vin_update_subrect(struct v4l2_rect *rect,
+				    struct v4l2_rect *subrect)
+{
+	if (rect->width < subrect->width)
+		subrect->width = rect->width;
+
+	if (rect->height < subrect->height)
+		subrect->height = rect->height;
+
+	if (rect->left > subrect->left)
+		subrect->left = rect->left;
+	else if (rect->left + rect->width <
+		 subrect->left + subrect->width)
+		subrect->left = rect->left + rect->width -
+			subrect->width;
+
+	if (rect->top > subrect->top)
+		subrect->top = rect->top;
+	else if (rect->top + rect->height <
+		 subrect->top + subrect->height)
+		subrect->top = rect->top + rect->height -
+			subrect->height;
+}
+
+/* Iterative set_fmt, also updates cached client crop on success */
+static int rcar_vin_client_set_fmt(struct soc_camera_device *icd,
+			struct v4l2_rect *rect, struct v4l2_rect *subrect,
+			unsigned int max_width, unsigned int max_height,
+			struct v4l2_subdev_format *format, bool host_can_scale)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct device *dev = icd->parent;
+	struct v4l2_mbus_framefmt *mf = &format->format;
+	unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
+	struct v4l2_cropcap cap;
+	bool host_1to1;
+	int ret;
+
+	ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					 soc_camera_grp_id(icd), pad,
+					 set_fmt, NULL, format);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "camera scaled to %ux%u\n", mf->width, mf->height);
+
+	if (width == mf->width && height == mf->height) {
+		/* Perfect! The client has done it all. */
+		host_1to1 = true;
+		goto update_cache;
+	}
+
+	host_1to1 = false;
+	if (!host_can_scale)
+		goto update_cache;
+
+	cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	if (max_width > cap.bounds.width)
+		max_width = cap.bounds.width;
+	if (max_height > cap.bounds.height)
+		max_height = cap.bounds.height;
+
+	/* Camera set a format, but geometry is not precise, try to improve */
+	tmp_w = mf->width;
+	tmp_h = mf->height;
+
+	/* width <= max_width && height <= max_height - guaranteed by try_fmt */
+	while ((width > tmp_w || height > tmp_h) &&
+	       tmp_w < max_width && tmp_h < max_height) {
+		tmp_w = min(2 * tmp_w, max_width);
+		tmp_h = min(2 * tmp_h, max_height);
+		mf->width = tmp_w;
+		mf->height = tmp_h;
+		ret = v4l2_device_call_until_err(sd->v4l2_dev,
+					soc_camera_grp_id(icd), pad,
+					set_fmt, NULL, format);
+		dev_dbg(dev, "Camera scaled to %ux%u\n",
+			mf->width, mf->height);
+		if (ret < 0) {
+			/* This shouldn't happen */
+			dev_err(dev, "Client failed to set format: %d\n", ret);
+			return ret;
+		}
+	}
+
+update_cache:
+	/* Update cache */
+	ret = soc_camera_client_g_rect(sd, rect);
+	if (ret < 0)
+		return ret;
+
+	if (!host_1to1)
+		rcar_vin_update_subrect(rect, subrect);
+
+	return 0;
+}
+
+int rcar_vin_client_scale(struct soc_camera_device *icd,
+			struct v4l2_rect *rect, struct v4l2_rect *subrect,
+			struct v4l2_mbus_framefmt *mf,
+			unsigned int *width, unsigned int *height,
+			bool host_can_scale, unsigned int shift)
+{
+	struct device *dev = icd->parent;
+	struct v4l2_subdev_format fmt_tmp = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.format = *mf,
+	};
+	struct v4l2_mbus_framefmt *mf_tmp = &fmt_tmp.format;
+	unsigned int scale_h, scale_v;
+	int ret;
+
+	/*
+	 * 5. Apply iterative camera S_FMT for camera user window (also updates
+	 *    client crop cache and the imaginary sub-rectangle).
+	 */
+	ret = rcar_vin_client_set_fmt(icd, rect, subrect, *width, *height,
+			   &fmt_tmp, host_can_scale);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "5: camera scaled to %ux%u\n",
+		mf_tmp->width, mf_tmp->height);
+
+	/* 6. Retrieve camera output window (g_fmt) */
+
+	/* unneeded - it is already in "mf_tmp" */
+
+	/* 7. Calculate new client scales. */
+	scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp->width);
+	scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp->height);
+
+	mf->width	= mf_tmp->width;
+	mf->height	= mf_tmp->height;
+	mf->colorspace	= mf_tmp->colorspace;
+
+	/*
+	 * 8. Calculate new host crop - apply camera scales to previously
+	 *    updated "effective" crop.
+	 */
+	*width = soc_camera_shift_scale(subrect->width, shift, scale_h);
+	*height = soc_camera_shift_scale(subrect->height, shift, scale_v);
+
+	dev_dbg(dev, "8: new client sub-window %ux%u\n", *width, *height);
+
+	return 0;
+}
+
+int rcar_vin_client_s_crop(struct v4l2_subdev *sd,
+			struct v4l2_crop *crop, struct v4l2_crop *cam_crop,
+			struct v4l2_rect *target_rect,
+			struct v4l2_rect *subrect)
+{
+	struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
+	struct device *dev = sd->v4l2_dev->dev;
+	struct v4l2_cropcap cap;
+	int ret;
+	unsigned int width, height;
+
+	v4l2_subdev_call(sd, video, s_crop, crop);
+	ret = soc_camera_client_g_rect(sd, cam_rect);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Now cam_crop contains the current camera input rectangle, and it must
+	 * be within camera cropcap bounds
+	 */
+	if (!memcmp(rect, cam_rect, sizeof(*rect))) {
+		/* Even if camera S_CROP failed, but camera rectangle matches */
+		dev_dbg(dev, "Camera S_CROP successful for %dx%d@%d:%d\n",
+			rect->width, rect->height, rect->left, rect->top);
+		*target_rect = *cam_rect;
+		*subrect = *rect;
+		return 0;
+	}
+
+	/* Try to fix cropping, that camera hasn't managed to set */
+	dev_dbg(dev, "Fix camera S_CROP for %dx%d@%d:%d to %dx%d@%d:%d\n",
+		cam_rect->width, cam_rect->height,
+		cam_rect->left, cam_rect->top,
+		rect->width, rect->height, rect->left, rect->top);
+
+	/* We need sensor maximum rectangle */
+	ret = v4l2_subdev_call(sd, video, cropcap, &cap);
+	if (ret < 0)
+		return ret;
+
+	/* Put user requested rectangle within sensor bounds */
+	soc_camera_limit_side(&rect->left, &rect->width, cap.bounds.left, 2,
+			      cap.bounds.width);
+	soc_camera_limit_side(&rect->top, &rect->height, cap.bounds.top, 4,
+			      cap.bounds.height);
+
+	/*
+	 * Popular special case - some cameras can only handle fixed sizes like
+	 * QVGA, VGA,... Take care to avoid infinite loop.
+	 */
+	width = max_t(unsigned int, cam_rect->width, 2);
+	height = max_t(unsigned int, cam_rect->height, 2);
+
+	/*
+	 * Loop as long as sensor is not covering the requested rectangle and
+	 * is still within its bounds
+	 */
+	while (!ret && (rcar_vin_is_smaller(cam_rect, rect) ||
+			rcar_vin_is_inside(cam_rect, rect)) &&
+	       (cap.bounds.width > width || cap.bounds.height > height)) {
+
+		width *= 2;
+		height *= 2;
+
+		cam_rect->width = width;
+		cam_rect->height = height;
+
+		/*
+		 * We do not know what capabilities the camera has to set up
+		 * left and top borders. We could try to be smarter in iterating
+		 * them, e.g., if camera current left is to the right of the
+		 * target left, set it to the middle point between the current
+		 * left and minimum left. But that would add too much
+		 * complexity: we would have to iterate each border separately.
+		 * Instead we just drop to the left and top bounds.
+		 */
+		if (cam_rect->left > rect->left)
+			cam_rect->left = cap.bounds.left;
+
+		if (cam_rect->left + cam_rect->width < rect->left + rect->width)
+			cam_rect->width = rect->left + rect->width -
+				cam_rect->left;
+
+		if (cam_rect->top > rect->top)
+			cam_rect->top = cap.bounds.top;
+
+		if (cam_rect->top + cam_rect->height < rect->top + rect->height)
+			cam_rect->height = rect->top + rect->height -
+				cam_rect->top;
+
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = soc_camera_client_g_rect(sd, cam_rect);
+		dev_dbg(dev, "Camera S_CROP %d for %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	/* S_CROP must not modify the rectangle */
+	if (rcar_vin_is_smaller(cam_rect, rect) ||
+		rcar_vin_is_inside(cam_rect, rect)) {
+		/*
+		 * The camera failed to configure a suitable cropping,
+		 * we cannot use the current rectangle, set to max
+		 */
+		*cam_rect = cap.bounds;
+		v4l2_subdev_call(sd, video, s_crop, cam_crop);
+		ret = soc_camera_client_g_rect(sd, cam_rect);
+		dev_dbg(dev, "Camera S_CROP %d for max %dx%d@%d:%d\n", ret,
+			cam_rect->width, cam_rect->height,
+			cam_rect->left, cam_rect->top);
+	}
+
+	if (!ret) {
+		*target_rect = *cam_rect;
+		*subrect = *rect;
+		rcar_vin_update_subrect(target_rect, subrect);
+	}
+
+	return ret;
+}
+
 static int rcar_vin_set_crop(struct soc_camera_device *icd,
 			     const struct v4l2_crop *a)
 {
@@ -1501,7 +2318,7 @@
 	dev_dbg(dev, "VNMC_REG 0x%x\n", vnmc);
 
 	/* Apply iterative camera S_CROP for new input window. */
-	ret = soc_camera_client_s_crop(sd, &a_writable, &cam_crop,
+	ret = rcar_vin_client_s_crop(sd, &a_writable, &cam_crop,
 				       &cam->rect, &cam->subrect);
 	if (ret < 0)
 		return ret;
@@ -1517,26 +2334,21 @@
 	if (ret < 0)
 		return ret;
 
-	if (mf->width > VIN_MAX_WIDTH || mf->height > VIN_MAX_HEIGHT)
+	if (mf->width > priv->max_width || mf->height > priv->max_height)
 		return -EINVAL;
 
 	/* Cache camera output window */
 	cam->width = mf->width;
 	cam->height = mf->height;
 
-	icd->user_width  = cam->width;
-	icd->user_height = cam->height;
-
-	cam->vin_left = rect->left & ~1;
-	cam->vin_top = rect->top & ~1;
+	cam->vin_left = rect->left;
+	cam->vin_top = rect->top;
 
 	/* Use VIN cropping to crop to the new window. */
 	ret = rcar_vin_set_rect(icd);
 	if (ret < 0)
 		return ret;
 
-	cam->subrect = *rect;
-
 	dev_dbg(dev, "VIN cropped to %ux%u@%u:%u\n",
 		icd->user_width, icd->user_height,
 		cam->vin_left, cam->vin_top);
@@ -1587,6 +2399,20 @@
 	dev_dbg(dev, "S_FMT(pix=0x%x, %ux%u)\n",
 		pixfmt, pix->width, pix->height);
 
+	/* At the time of NV16 capture format, the user has to specify */
+	/* the width of the multiple of 32 for H/W specification. */
+	if (priv->error_flag == false)
+		priv->error_flag = true;
+	else {
+		if (((pixfmt == V4L2_PIX_FMT_NV16) ||
+			(pixfmt == V4L2_PIX_FMT_NV12)) &&
+			(pix->width & 0x1F)) {
+			dev_dbg(icd->parent,
+			 "specify width of 32 multiple in separate format.\n");
+			return -EINVAL;
+		}
+	}
+
 	switch (pix->field) {
 	default:
 		pix->field = V4L2_FIELD_NONE;
@@ -1626,16 +2452,18 @@
 	mf.code	 = xlate->code;
 
 	switch (pixfmt) {
-	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_XBGR32:
 		can_scale = priv->chip != RCAR_E1;
 		break;
-	case V4L2_PIX_FMT_ARGB32:
+	case V4L2_PIX_FMT_ABGR32:
 	case V4L2_PIX_FMT_UYVY:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_RGB565:
-	case V4L2_PIX_FMT_RGB555X:
+	case V4L2_PIX_FMT_ARGB555:
+	case V4L2_PIX_FMT_NV16:
 		can_scale = true;
 		break;
+	case V4L2_PIX_FMT_NV12:
 	default:
 		can_scale = false;
 		break;
@@ -1643,7 +2471,7 @@
 
 	dev_dbg(dev, "request camera output %ux%u\n", mf.width, mf.height);
 
-	ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect,
+	ret = rcar_vin_client_scale(icd, &cam->rect, &cam->subrect,
 				      &mf, &vin_sub_width, &vin_sub_height,
 				      can_scale, 12);
 
@@ -1701,6 +2529,8 @@
 			    struct v4l2_format *f)
 {
 	const struct soc_camera_format_xlate *xlate;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+	struct rcar_vin_priv *priv = ici->priv;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
 	struct v4l2_subdev_pad_config pad_cfg;
@@ -1722,9 +2552,16 @@
 		pix->colorspace = icd->colorspace;
 	}
 
-	/* FIXME: calculate using depth and bus width */
-	v4l_bound_align_image(&pix->width, 2, VIN_MAX_WIDTH, 1,
-			      &pix->height, 4, VIN_MAX_HEIGHT, 2, 0);
+	/* When performing a YCbCr-422 format output, even if it performs */
+	/* odd number clipping by pixel post clip processing, */
+	/* it is outputted to a memory per even pixels. */
+	if ((pixfmt == V4L2_PIX_FMT_NV16) || (pixfmt == V4L2_PIX_FMT_NV12) ||
+		(pixfmt == V4L2_PIX_FMT_YUYV) || (pixfmt == V4L2_PIX_FMT_UYVY))
+		v4l_bound_align_image(&pix->width, 5, priv->max_width, 1,
+				      &pix->height, 2, priv->max_height, 0, 0);
+	else
+		v4l_bound_align_image(&pix->width, 5, priv->max_width, 0,
+				      &pix->height, 2, priv->max_height, 0, 0);
 
 	width = pix->width;
 	height = pix->height;
@@ -1745,11 +2582,19 @@
 	if (ret < 0)
 		return ret;
 
-	/* Adjust only if VIN cannot scale */
-	if (pix->width > mf->width * 2)
-		pix->width = mf->width * 2;
-	if (pix->height > mf->height * 3)
-		pix->height = mf->height * 3;
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		/* Adjust max scaling size for Gen3 */
+		if (pix->width > 4096)
+			pix->width = priv->max_width;
+		if (pix->height > 4096)
+			pix->height = priv->max_height;
+	} else {
+		/* Adjust only if VIN cannot scale */
+		if (pix->width > mf->width * 2)
+			pix->width = mf->width * 2;
+		if (pix->height > mf->height * 3)
+			pix->height = mf->height * 3;
+	}
 
 	pix->field = mf->field;
 	pix->colorspace = mf->colorspace;
@@ -1763,8 +2608,8 @@
 			 * requested a bigger rectangle, it will not return a
 			 * smaller one.
 			 */
-			mf->width = VIN_MAX_WIDTH;
-			mf->height = VIN_MAX_HEIGHT;
+			mf->width = priv->max_width;
+			mf->height = priv->max_height;
 			ret = v4l2_device_call_until_err(sd->v4l2_dev,
 							 soc_camera_grp_id(icd),
 							 pad, set_fmt, &pad_cfg,
@@ -1809,7 +2654,7 @@
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
 	vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	vq->io_modes = VB2_MMAP | VB2_USERPTR;
+	vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
 	vq->drv_priv = icd;
 	vq->ops = &rcar_vin_vb2_ops;
 	vq->mem_ops = &vb2_dma_contig_memops;
@@ -1820,6 +2665,63 @@
 	return vb2_queue_init(vq);
 }
 
+static int rcar_vin_get_selection(struct soc_camera_device *icd,
+				  struct v4l2_selection *sel)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_mbus_framefmt *mf = &fmt.format;
+	int ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+	if (ret < 0)
+		return ret;
+
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		sel->r.left = sel->r.top = 0;
+		sel->r.width = mf->width;
+		sel->r.height = mf->height;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rcar_vin_cropcap(struct soc_camera_device *icd,
+			    struct v4l2_cropcap *crop)
+{
+	struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+	};
+	struct v4l2_mbus_framefmt *mf = &fmt.format;
+	int ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
+	if (ret < 0)
+		return ret;
+
+	crop->bounds.left = 0;
+	crop->bounds.top  = 0;
+	crop->bounds.width = mf->width;
+	crop->bounds.height = mf->height;
+
+	/* default cropping rectangle */
+	crop->defrect = crop->bounds;
+	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	return 0;
+}
+
 static struct soc_camera_host_ops rcar_vin_host_ops = {
 	.owner		= THIS_MODULE,
 	.add		= rcar_vin_add_device,
@@ -1834,11 +2736,14 @@
 	.querycap	= rcar_vin_querycap,
 	.set_bus_param	= rcar_vin_set_bus_param,
 	.init_videobuf2	= rcar_vin_init_videobuf2,
+	.get_selection	= rcar_vin_get_selection,
+	.cropcap	= rcar_vin_cropcap,
 };
 
 #ifdef CONFIG_OF
 static const struct of_device_id rcar_vin_of_table[] = {
-	{ .compatible = "renesas,vin-r8a7795", .data = (void *)RCAR_GEN3 },
+	{ .compatible = "renesas,vin-r8a7796", .data = (void *)RCAR_M3 },
+	{ .compatible = "renesas,vin-r8a7795", .data = (void *)RCAR_H3 },
 	{ .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 },
@@ -1852,6 +2757,184 @@
 MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
 #endif
 
+#define MAP_MAX_NUM 32
+static DECLARE_BITMAP(device_map, MAP_MAX_NUM);
+static DEFINE_MUTEX(list_lock);
+
+static int rcar_vin_dyn_pdev(struct soc_camera_desc *sdesc,
+			       struct rcar_vin_async_client *sasc)
+{
+	struct platform_device *pdev;
+	int ret, i;
+
+	mutex_lock(&list_lock);
+	i = find_first_zero_bit(device_map, MAP_MAX_NUM);
+	if (i < MAP_MAX_NUM)
+		set_bit(i, device_map);
+	mutex_unlock(&list_lock);
+	if (i >= MAP_MAX_NUM)
+		return -ENOMEM;
+
+	pdev = platform_device_alloc("soc-camera-pdrv", ((2 * i) + 1));
+	if (!pdev)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc));
+	if (ret < 0) {
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	sasc->pdev = pdev;
+
+	return 0;
+}
+
+static int rcar_vin_async_bound(struct v4l2_async_notifier *notifier,
+				  struct v4l2_subdev *sd,
+				  struct v4l2_async_subdev *asd)
+{
+	/* None. */
+	return 0;
+}
+
+static void rcar_vin_async_unbind(struct v4l2_async_notifier *notifier,
+				    struct v4l2_subdev *sd,
+				    struct v4l2_async_subdev *asd)
+{
+	/* None. */
+}
+
+static int rcar_vin_async_probe(struct soc_camera_host *ici,
+			    struct soc_camera_device *icd)
+{
+	struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+	struct soc_camera_host_desc *shd = &sdesc->host_desc;
+	struct device *control = NULL;
+	int ret;
+
+	ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
+	if (ret < 0)
+		return ret;
+
+	if (shd->module_name)
+		ret = request_module(shd->module_name);
+
+	ret = shd->add_device(icd);
+
+	control = to_soc_camera_control(icd);
+	if (!control || !control->driver || !dev_get_drvdata(control) ||
+		!try_module_get(control->driver->owner)) {
+		shd->del_device(icd);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int rcar_vin_async_complete(struct v4l2_async_notifier *notifier)
+{
+	struct rcar_vin_async_client *sasc = container_of(notifier,
+					struct rcar_vin_async_client, notifier);
+	struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
+
+	if (to_soc_camera_control(icd)) {
+		struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+		int ret;
+
+		mutex_lock(&list_lock);
+		ret = rcar_vin_async_probe(ici, icd);
+		mutex_unlock(&list_lock);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct soc_camera_device *rcar_vin_add_pdev(
+				struct rcar_vin_async_client *sasc)
+{
+	struct platform_device *pdev = sasc->pdev;
+	int ret;
+
+	ret = platform_device_add(pdev);
+
+	if (ret < 0 || !pdev->dev.driver)
+		return NULL;
+
+	return platform_get_drvdata(pdev);
+}
+
+static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv,
+		       struct soc_camera_host *ici,
+		       struct device_node *ep,
+		       struct device_node *remote)
+{
+	struct soc_camera_device *icd;
+	struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
+	struct rcar_vin_async_client *sasc;
+	struct soc_of_info *info;
+	struct i2c_client *client;
+	char clk_name[V4L2_SUBDEV_NAME_SIZE];
+	int ret;
+
+	/* allocate a new subdev and add match info to it */
+	info = devm_kzalloc(ici->v4l2_dev.dev, sizeof(struct soc_of_info),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->sasd.asd.match.of.node = remote;
+	info->sasd.asd.match_type = V4L2_ASYNC_MATCH_OF;
+	info->subdev = &info->sasd.asd;
+
+	/* Or shall this be managed by the soc-camera device? */
+	sasc = &info->sasc;
+
+	ret = rcar_vin_dyn_pdev(&sdesc, sasc);
+	if (ret < 0)
+		goto eallocpdev;
+
+	sasc->sensor = &info->sasd.asd;
+
+	icd = rcar_vin_add_pdev(sasc);
+	if (!icd) {
+		ret = -ENOMEM;
+		goto eaddpdev;
+	}
+
+	sasc->notifier.subdevs = &info->subdev;
+	sasc->notifier.num_subdevs = 1;
+	sasc->notifier.bound = rcar_vin_async_bound;
+	sasc->notifier.unbind = rcar_vin_async_unbind;
+	sasc->notifier.complete = rcar_vin_async_complete;
+
+	priv->async_client = sasc;
+
+	client = of_find_i2c_device_by_node(remote);
+
+	if (client)
+		snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+			 client->adapter->nr, client->addr);
+	else
+		snprintf(clk_name, sizeof(clk_name), "of-%s",
+			 of_node_full_name(remote));
+
+	ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
+	if (!ret)
+		return 0;
+
+	platform_device_del(sasc->pdev);
+eaddpdev:
+	platform_device_put(sasc->pdev);
+eallocpdev:
+	devm_kfree(ici->v4l2_dev.dev, info);
+	dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
+
+	return ret;
+}
+
 static int rcar_vin_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match = NULL;
@@ -1861,6 +2944,10 @@
 	struct resource *mem;
 	unsigned int pdata_flags;
 	int irq, ret;
+	const char *str;
+	unsigned int i;
+	struct device_node *epn = NULL, *ren = NULL;
+	bool csi_use = false;
 
 	match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
 
@@ -1870,6 +2957,32 @@
 		return -EINVAL;
 	}
 
+	for (i = 0; ; i++) {
+		epn = of_graph_get_next_endpoint(pdev->dev.of_node,
+								epn);
+		if (!epn)
+			break;
+
+		ren = of_graph_get_remote_port(epn);
+		if (!ren) {
+			dev_notice(&pdev->dev, "no remote for %s\n",
+					of_node_full_name(epn));
+			continue;
+		}
+
+		/* so we now have a remote node to connect */
+		dev_dbg(&pdev->dev, "node name:%s\n",
+			of_node_full_name(ren->parent));
+
+		if (strcmp(ren->parent->name, "csi2") == 0)
+			csi_use = true;
+
+		of_node_put(ren);
+
+		if (i)
+			break;
+	}
+
 	ret = v4l2_of_parse_endpoint(np, &ep);
 	if (ret) {
 		dev_err(&pdev->dev, "could not parse endpoint\n");
@@ -1878,6 +2991,8 @@
 
 	if (ep.bus_type == V4L2_MBUS_BT656)
 		pdata_flags = RCAR_VIN_BT656;
+	else if (ep.bus_type == V4L2_MBUS_CSI2)
+		pdata_flags = RCAR_VIN_BT656 | RCAR_VIN_CSI2;
 	else {
 		pdata_flags = 0;
 		if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
@@ -1920,6 +3035,7 @@
 	priv->ici.v4l2_dev.dev = &pdev->dev;
 	priv->ici.drv_name = dev_name(&pdev->dev);
 	priv->ici.ops = &rcar_vin_host_ops;
+	priv->csi_sync = false;
 
 	priv->pdata_flags = pdata_flags;
 	if (!match) {
@@ -1930,6 +3046,163 @@
 		priv->chip = (enum chip_id)match->data;
 	}
 
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		priv->max_width = 4096;
+		priv->max_height = 4096;
+	} else {
+		priv->max_width = 2048;
+		priv->max_height = 2048;
+	}
+
+	if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3) {
+		u32 ifmd = 0;
+		bool match_flag = false;
+		const struct vin_gen3_ifmd *gen3_ifmd_table = NULL;
+		int vc, num;
+
+		num = VNCSI_IFMD_SEL_NUMBER;
+
+		if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef0000.video") == 0)
+			priv->index = RCAR_VIDEO_0;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef1000.video") == 0)
+			priv->index = RCAR_VIDEO_1;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef2000.video") == 0)
+			priv->index = RCAR_VIDEO_2;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef3000.video") == 0)
+			priv->index = RCAR_VIDEO_3;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef4000.video") == 0)
+			priv->index = RCAR_VIDEO_4;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef5000.video") == 0)
+			priv->index = RCAR_VIDEO_5;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef6000.video") == 0)
+			priv->index = RCAR_VIDEO_6;
+		else if (strcmp(dev_name(priv->ici.v4l2_dev.dev),
+						"e6ef7000.video") == 0)
+			priv->index = RCAR_VIDEO_7;
+		else
+			priv->index = RCAR_VIN_CH_NONE;
+
+		ret = of_property_read_string(np, "csi,select", &str);
+		if (ret) {
+			dev_err(&pdev->dev, "could not parse csi,select\n");
+			return ret;
+		}
+
+		if (strcmp(str, "csi40") == 0)
+			priv->csi_ch = RCAR_CSI40;
+		else if (strcmp(str, "csi20") == 0)
+			priv->csi_ch = RCAR_CSI20;
+		else if (strcmp(str, "csi41") == 0)
+			priv->csi_ch = RCAR_CSI41;
+		else if (strcmp(str, "csi21") == 0)
+			priv->csi_ch = RCAR_CSI21;
+		else
+			priv->csi_ch = RCAR_CSI_CH_NONE;
+
+		ret = of_property_read_u32(np, "virtual,channel", &vc);
+		if (ret) {
+			dev_err(&pdev->dev,
+			"could not parse virtual,channel\n");
+			return ret;
+		}
+
+		if (vc == 0)
+			priv->vc = RCAR_VIRTUAL_CH0;
+		else if (vc == 1)
+			priv->vc = RCAR_VIRTUAL_CH1;
+		else if (vc == 2)
+			priv->vc = RCAR_VIRTUAL_CH2;
+		else if (vc == 3)
+			priv->vc = RCAR_VIRTUAL_CH3;
+		else
+			priv->vc = RCAR_VIRTUAL_NONE;
+
+		dev_dbg(&pdev->dev, "csi_ch:%d, vc:%d\n",
+					priv->csi_ch, priv->vc);
+
+		ifmd = VNCSI_IFMD_DES1 | VNCSI_IFMD_DES0;
+
+		if (priv->chip == RCAR_H3)
+			gen3_ifmd_table = vin_h3_vc_ifmd;
+		else if (priv->chip == RCAR_M3)
+			gen3_ifmd_table = vin_m3_vc_ifmd;
+
+		for (i = 0; i < num; i++) {
+			if ((gen3_ifmd_table[i].v_sel[priv->index].csi2_ch
+				== priv->csi_ch) &&
+				(gen3_ifmd_table[i].v_sel[priv->index].vc
+				== priv->vc)) {
+				if (priv->index < RCAR_VIDEO_4) {
+					if (ifmd0_init) {
+						ifmd0_reg_match[i] = true;
+						match_flag = true;
+					} else if (ifmd0_reg_match[i])
+						match_flag = true;
+				} else {
+					if (ifmd4_init) {
+						ifmd4_reg_match[i] = true;
+						match_flag = true;
+					} else if (ifmd4_reg_match[i])
+						match_flag = true;
+				}
+			} else {
+				if (priv->index < RCAR_VIDEO_4)
+					ifmd0_reg_match[i] = false;
+				else
+					ifmd4_reg_match[i] = false;
+			}
+		}
+		if (priv->index < RCAR_VIDEO_4)
+			ifmd0_init = false;
+		else
+			ifmd4_init = false;
+
+		if (!match_flag) {
+			dev_err(&pdev->dev,
+			"Not match, virtual channel pattern error.\n");
+			return -EINVAL;
+		}
+
+		rcar_vin_cpg_enable_for_ifmd(priv->index, true);
+
+		if (priv->index < RCAR_VIDEO_4) {
+			void __iomem *ifmd0_mem;
+
+			for (i = 0; i < num; i++) {
+				if (ifmd0_reg_match[i]) {
+					ifmd |= gen3_ifmd_table[i].set_reg;
+					break;
+				}
+			}
+
+			ifmd0_mem = ioremap(0xe6ef0000 + VNCSI_IFMD_REG, 0x04);
+			iowrite32(ifmd, ifmd0_mem);
+			iounmap(ifmd0_mem);
+		} else {
+			void __iomem *ifmd4_mem;
+
+			for (i = 0; i < num; i++) {
+				if (ifmd4_reg_match[i]) {
+					ifmd |= gen3_ifmd_table[i].set_reg;
+					break;
+				}
+			}
+
+			ifmd4_mem = ioremap(0xe6ef4000 + VNCSI_IFMD_REG, 0x04);
+			iowrite32(ifmd, ifmd4_mem);
+			iounmap(ifmd4_mem);
+		}
+
+		rcar_vin_cpg_enable_for_ifmd(priv->index, false);
+	}
+
 	spin_lock_init(&priv->lock);
 	INIT_LIST_HEAD(&priv->capture);
 
@@ -1942,6 +3215,14 @@
 	if (ret)
 		goto cleanup;
 
+	if (csi_use) {
+		ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ren->parent);
+		if (ret)
+			goto cleanup;
+	}
+
+	vin_debug = 0;
+
 	return 0;
 
 cleanup:
@@ -1957,6 +3238,11 @@
 	struct rcar_vin_priv *priv = container_of(soc_host,
 						  struct rcar_vin_priv, ici);
 
+	platform_device_del(priv->async_client->pdev);
+	platform_device_put(priv->async_client->pdev);
+
+	v4l2_async_notifier_unregister(&priv->async_client->notifier);
+
 	soc_camera_host_unregister(soc_host);
 	pm_runtime_disable(&pdev->dev);
 	vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
@@ -1986,11 +3272,10 @@
 	ifmd4_init = true;
 
 	if (priv->chip == RCAR_H3) {
-		ifmd = VNCSI_IFMD_DES2 | VNCSI_IFMD_DES1 |
-			 VNCSI_IFMD_DES0;
+		ifmd = VNCSI_IFMD_DES1 | VNCSI_IFMD_DES0;
 		gen3_ifmd_table = vin_h3_vc_ifmd;
 	} else if (priv->chip == RCAR_M3) {
-		ifmd = VNCSI_IFMD_DES2 | VNCSI_IFMD_DES1;
+		ifmd = VNCSI_IFMD_DES1;
 		gen3_ifmd_table = vin_m3_vc_ifmd;
 	}
 
@@ -2077,3 +3362,4 @@
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rcar_vin");
 MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
+MODULE_AUTHOR("Koji Matsuoka <koji.matsuoka.xm@renesas.com>");
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index bda29bc..673491a 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -1,6 +1,7 @@
 /*
  * soc-camera generic scaling-cropping manipulation functions
  *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -405,3 +406,5 @@
 	mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
 }
 EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 6bf6d54..a753662 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -1,7 +1,7 @@
 /*
  * vsp1.h  --  R-Car VSP1 Driver
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -58,6 +58,7 @@
 	unsigned int wpf_count;
 	unsigned int num_bru_inputs;
 	bool uapi;
+	bool header_mode;
 };
 
 struct vsp1_device {
@@ -85,11 +86,18 @@
 	struct media_device media_dev;
 	struct media_entity_operations media_ops;
 
+	bool auto_fld_mode;
+
 	struct vsp1_drm *drm;
+	int index;
+
+	dma_addr_t dl_addr;
+	unsigned int dl_body;
 };
 
 int vsp1_device_get(struct vsp1_device *vsp1);
 void vsp1_device_put(struct vsp1_device *vsp1);
+void vsp1_underrun_workaround(struct vsp1_device *vsp1, bool reset);
 
 int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index);
 
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 835593d..b14a6ae 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_bru.c  --  R-Car VSP1 Blend ROP Unit
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -279,6 +279,26 @@
 	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
 					    bru->entity.source_pad);
 
+	if (pipe->vmute_flag) {
+		vsp1_bru_write(bru, dl, VI6_BRU_INCTRL, 0);
+		vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE,
+		  (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
+		  (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
+		vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0);
+		vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, (0xFF << 24));
+
+		for (i = 0; i < bru->entity.source_pad; ++i) {
+			vsp1_bru_write(bru, dl, VI6_BRU_BLD(i),
+			VI6_BRU_BLD_CCMDX_255_SRC_A |
+			VI6_BRU_BLD_CCMDY_SRC_A |
+			VI6_BRU_BLD_ACMDX_255_SRC_A |
+			VI6_BRU_BLD_ACMDY_COEFY |
+			VI6_BRU_BLD_COEFY_MASK);
+		}
+
+		return;
+	}
+
 	/* The hardware is extremely flexible but we have no userspace API to
 	 * expose all the parameters, nor is it clear whether we would have use
 	 * cases for all the supported modes. Let's just harcode the parameters
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index e238d9b..fc68669 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_dl.h  --  R-Car VSP1 Display List
  *
- * Copyright (C) 2015 Renesas Corporation
+ * Copyright (C) 2015-2016 Renesas Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -15,12 +15,18 @@
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/soc/renesas/rcar_prr.h>
+
+#include <media/rcar-fcp.h>
 
 #include "vsp1.h"
 #include "vsp1_dl.h"
+#include "vsp1_pipe.h"
+#include "vsp1_rwpf.h"
 
 #define VSP1_DL_NUM_ENTRIES		256
 #define VSP1_DL_NUM_LISTS		3
+#define VSP1_DL_EXT_OFFSET		0x1000
 
 #define VSP1_DLH_INT_ENABLE		(1 << 1)
 #define VSP1_DLH_AUTO_START		(1 << 0)
@@ -35,6 +41,24 @@
 	struct vsp1_dl_header_list lists[8];
 	u32 next_header;
 	u32 flags;
+	/* if (VI6_DL_EXT_CTRL.EXT) */
+	u32 zero_bits;
+	/* zero_bits:6 + pre_ext_dl_exec:1 + */
+	/* post_ext_dl_exec:1 + zero_bits:8 + pre_ext_dl_num_cmd:16 */
+	u32 pre_post_num;
+	u32 pre_ext_dl_plist;
+	/* zero_bits:16 + post_ext_dl_num_cmd:16 */
+	u32 post_ext_dl_num_cmd;
+	u32 post_ext_dl_p_list;
+} __attribute__((__packed__));
+
+struct vsp1_ext_dl_body {
+	u32 ext_dl_cmd[2];
+	u32 ext_dl_data[2];
+} __attribute__((__packed__));
+
+struct vsp1_ext_addr {
+	u32 addr;
 } __attribute__((__packed__));
 
 struct vsp1_dl_entry {
@@ -68,6 +92,10 @@
  * @dlm: the display list manager
  * @header: display list header, NULL for headerless lists
  * @dma: DMA address for the header
+ * @ext_body: display list extended body
+ * @ext_dma: DMA address for extended body
+ * @src_dst_addr: display list (Auto-FLD) source/destination address
+ * @ext_addr_dma: DMA address for display list (Auto-FLD)
  * @body0: first display list body
  * @fragments: list of extra display list bodies
  */
@@ -78,6 +106,12 @@
 	struct vsp1_dl_header *header;
 	dma_addr_t dma;
 
+	struct vsp1_ext_dl_body *ext_body;
+	dma_addr_t ext_dma;
+
+	struct vsp1_ext_addr *src_dst_addr;
+	dma_addr_t ext_addr_dma;
+
 	struct vsp1_dl_body body0;
 	struct list_head fragments;
 };
@@ -124,12 +158,13 @@
 			     size_t extra_size)
 {
 	size_t size = num_entries * sizeof(*dlb->entries) + extra_size;
+	struct device *fcp = rcar_fcp_device(vsp1->fcp);
 
 	dlb->vsp1 = vsp1;
 	dlb->size = size;
 
-	dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma,
-				    GFP_KERNEL);
+	dlb->entries = dma_alloc_wc(fcp ? fcp : vsp1->dev, dlb->size +
+			 (VSP1_DL_EXT_OFFSET * 2), &dlb->dma, GFP_KERNEL);
 	if (!dlb->entries)
 		return -ENOMEM;
 
@@ -141,7 +176,11 @@
  */
 static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb)
 {
-	dma_free_wc(dlb->vsp1->dev, dlb->size, dlb->entries, dlb->dma);
+	struct device *fcp = rcar_fcp_device(dlb->vsp1->fcp);
+
+	dma_free_wc(fcp ? fcp : dlb->vsp1->dev,
+			 dlb->size + (VSP1_DL_EXT_OFFSET * 2),
+			 dlb->entries, dlb->dma);
 }
 
 /**
@@ -218,6 +257,102 @@
  * Display List Transaction Management
  */
 
+void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf)
+{
+	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
+	const struct v4l2_rect *crop;
+	u32 y_top_index, y_bot_index;
+	u32 u_top_index, u_bot_index;
+	u32 v_top_index, v_bot_index;
+	dma_addr_t y_top_addr, y_bot_addr;
+	dma_addr_t u_top_addr, u_bot_addr;
+	dma_addr_t v_top_addr, v_bot_addr;
+	u32 width, stride;
+
+	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+	width = ALIGN(crop->width, 16);
+	stride = width * fmtinfo->bpp[0] / 8;
+
+	y_top_index = rpf->entity.index * 8;
+	y_bot_index = rpf->entity.index * 8 + 1;
+	u_top_index = rpf->entity.index * 8 + 2;
+	u_bot_index = rpf->entity.index * 8 + 3;
+	v_top_index = rpf->entity.index * 8 + 4;
+	v_bot_index = rpf->entity.index * 8 + 5;
+
+	switch (rpf->fmtinfo->fourcc) {
+	case V4L2_PIX_FMT_YUV420M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride;
+		u_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride / 2;
+		v_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride / 2;
+		break;
+
+	case V4L2_PIX_FMT_YUV422M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride * 2;
+		u_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride;
+		v_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride;
+		break;
+
+	case V4L2_PIX_FMT_YUV444M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride * 3;
+		u_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride * 3;
+		v_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride * 3;
+		break;
+
+	case V4L2_PIX_FMT_YVU420M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride;
+		u_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride / 2;
+		v_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride / 2;
+		break;
+
+	case V4L2_PIX_FMT_YVU422M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride * 2;
+		u_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride;
+		v_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride;
+		break;
+
+	case V4L2_PIX_FMT_YVU444M:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride * 3;
+		u_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride * 3;
+		v_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride * 3;
+		break;
+
+	default:
+		y_top_addr = rpf->mem.addr[0] + rpf->offsets[0];
+		y_bot_addr = rpf->mem.addr[0] + rpf->offsets[0] + stride;
+		u_top_addr = rpf->mem.addr[1] + rpf->offsets[1];
+		u_bot_addr = rpf->mem.addr[1] + rpf->offsets[1] + stride;
+		v_top_addr = rpf->mem.addr[2] + rpf->offsets[1];
+		v_bot_addr = rpf->mem.addr[2] + rpf->offsets[1] + stride;
+		break;
+	}
+
+	dl->src_dst_addr[y_top_index].addr = y_top_addr;
+	dl->src_dst_addr[y_bot_index].addr = y_bot_addr;
+	dl->src_dst_addr[u_top_index].addr = u_top_addr;
+	dl->src_dst_addr[u_bot_index].addr = u_bot_addr;
+	dl->src_dst_addr[v_top_index].addr = v_top_addr;
+	dl->src_dst_addr[v_bot_index].addr = v_bot_addr;
+}
+
 static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
 	struct vsp1_dl_list *dl;
@@ -254,9 +389,43 @@
 		dl->header = ((void *)dl->body0.entries) + header_offset;
 		dl->dma = dl->body0.dma + header_offset;
 
+		dl->ext_body = ((void *)dl->body0.entries) +
+				 header_offset + VSP1_DL_EXT_OFFSET;
+		dl->ext_dma = dl->body0.dma + header_offset +
+				 VSP1_DL_EXT_OFFSET;
+
+		dl->src_dst_addr = ((void *)dl->body0.entries) +
+				 header_offset + (VSP1_DL_EXT_OFFSET * 2);
+		dl->ext_addr_dma = dl->body0.dma + header_offset +
+				 (VSP1_DL_EXT_OFFSET * 2);
+
 		memset(dl->header, 0, sizeof(*dl->header));
 		dl->header->lists[0].addr = dl->body0.dma;
 		dl->header->flags = VSP1_DLH_INT_ENABLE;
+		if (dlm->vsp1->info->header_mode) {
+			dl->header->next_header = dl->dma;
+			dl->header->flags |= VSP1_DLH_AUTO_START;
+		}
+
+		if (dlm->vsp1->auto_fld_mode) {
+			/* Set extended display list header */
+			/* pre_ext_dl_exec = 1, pre_ext_dl_num_cmd = 1 */
+			dl->header->pre_post_num = (1 << 25) | (0x01);
+			dl->header->pre_ext_dl_plist = dl->ext_dma;
+			dl->header->post_ext_dl_num_cmd = 0;
+			dl->header->post_ext_dl_p_list = 0;
+
+			/* Set extended display list (Auto-FLD) */
+			/* Set opecode */
+			dl->ext_body->ext_dl_cmd[0] = 0x00000003;
+			/* RPF[0]-[4] address is updated */
+			dl->ext_body->ext_dl_cmd[1] = 0x001f0001;
+
+			/* Set pointer of source/destination address */
+			dl->ext_body->ext_dl_data[0] = dl->ext_addr_dma;
+			/* Should be set to 0 */
+			dl->ext_body->ext_dl_data[1] = 0;
+		}
 	}
 
 	return dl;
@@ -415,7 +584,13 @@
 		dl->header->num_lists = num_lists;
 		vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
 
+		if (RCAR_PRR_IS_PRODUCT(H3) &&
+			(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+			vsp1->dl_addr = dl->dma;
+
 		dlm->active = dl;
+		__vsp1_dl_list_put(dl);
+
 		goto done;
 	}
 
@@ -439,6 +614,13 @@
 	vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
 		   (dl->body0.num_entries * sizeof(*dl->header->lists)));
 
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+		vsp1->dl_addr = dl->body0.dma;
+		vsp1->dl_body = VI6_DL_BODY_SIZE_UPD |
+			(dl->body0.num_entries * sizeof(*dl->header->lists));
+	}
+
 	__vsp1_dl_list_put(dlm->queued);
 	dlm->queued = dl;
 
@@ -508,6 +690,13 @@
 			   (dl->body0.num_entries *
 			    sizeof(*dl->header->lists)));
 
+		if (RCAR_PRR_IS_PRODUCT(H3) &&
+			(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+			vsp1->dl_addr = dl->body0.dma;
+			vsp1->dl_body = VI6_DL_BODY_SIZE_UPD |
+				(dl->body0.num_entries *
+				 sizeof(*dl->header->lists));
+		}
 		dlm->queued = dl;
 		dlm->pending = NULL;
 	}
@@ -523,10 +712,16 @@
 		 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
 		 | VI6_DL_CTRL_DLE;
 
+	if ((vsp1->info->header_mode) && (vsp1->auto_fld_mode)) {
+		vsp1_write(vsp1, VI6_DL_EXT_CTRL,
+			(0x02 << VI6_DL_EXT_CTRL_POLINT_SHIFT)
+			| VI6_DL_EXT_CTRL_DLPRI | VI6_DL_EXT_CTRL_EXT);
+	}
+
 	/* The DRM pipeline operates with display lists in Continuous Frame
 	 * Mode, all other pipelines use manual start.
 	 */
-	if (vsp1->drm)
+	if ((vsp1->drm) && (!vsp1->info->header_mode))
 		ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
 
 	vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
@@ -556,13 +751,14 @@
 {
 	struct vsp1_dl_manager *dlm;
 	unsigned int i;
+	int ret;
 
 	dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL);
 	if (!dlm)
 		return NULL;
 
 	dlm->index = index;
-	dlm->mode = index == 0 && !vsp1->info->uapi
+	dlm->mode = index == 0 && !vsp1->info->uapi && !vsp1->info->header_mode
 		  ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
 	dlm->vsp1 = vsp1;
 
@@ -579,6 +775,12 @@
 		list_add_tail(&dl->list, &dlm->free);
 	}
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(dlm->vsp1->dev, "product register init fail.\n");
+		return NULL;
+	}
+
 	return dlm;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index de387cd..7b4e522 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -31,6 +31,7 @@
 void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
 
 struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
+void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf);
 void vsp1_dl_list_put(struct vsp1_dl_list *dl);
 void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
 void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index c5ee06b..d74b0bd 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_drm.c  --  R-Car VSP1 DRM API
  *
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -13,6 +13,7 @@
 
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <media/media-entity.h>
 #include <media/v4l2-subdev.h>
@@ -51,6 +52,20 @@
 }
 EXPORT_SYMBOL_GPL(vsp1_du_init);
 
+int vsp1_du_if_set_mute(struct device *dev, bool on)
+{
+	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+	struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+
+	if (on)
+		pipe->vmute_flag = true;
+	else
+		pipe->vmute_flag = false;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_if_set_mute);
+
 /**
  * vsp1_du_setup_lif - Setup the output part of the VSP pipeline
  * @dev: the VSP device
@@ -296,12 +311,26 @@
 	rpf->fmtinfo = fmtinfo;
 	rpf->format.num_planes = fmtinfo->planes;
 	rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
-	rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
+	if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUV420M) ||
+		(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU420M) ||
+		(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUV422M) ||
+		(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU422M))
+		rpf->format.plane_fmt[1].bytesperline = cfg->pitch / 2;
+	else
+		rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
 	rpf->alpha = cfg->alpha;
+	rpf->interlaced = cfg->interlaced;
+
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0) && rpf->interlaced) {
+		dev_err(vsp1->dev,
+			"Interlaced mode is not supported.\n");
+		return -EINVAL;
+	}
 
 	rpf->mem.addr[0] = cfg->mem[0];
 	rpf->mem.addr[1] = cfg->mem[1];
-	rpf->mem.addr[2] = 0;
+	rpf->mem.addr[2] = cfg->mem[2];
 
 	vsp1->drm->inputs[rpf_index].crop = cfg->src;
 	vsp1->drm->inputs[rpf_index].compose = cfg->dst;
@@ -383,12 +412,6 @@
 
 	/* BRU sink, propagate the format from the RPF source. */
 	format.pad = bru_input;
-	format.format.code = rpf->fmtinfo->mbus;
-
-	ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
-			       &format);
-	if (ret < 0)
-		return ret;
 
 	ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL,
 			       &format);
@@ -525,6 +548,58 @@
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
 
+int vsp1_du_setup_wb(struct device *dev, u32 pixelformat, unsigned int pitch,
+		      dma_addr_t mem[2])
+{
+	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+	struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+	struct vsp1_rwpf *wpf = pipe->output;
+	const struct vsp1_format_info *fmtinfo;
+	struct vsp1_rwpf *rpf = pipe->inputs[0];
+	unsigned long flags;
+	int i;
+
+	fmtinfo = vsp1_get_format_info(pixelformat);
+	if (!fmtinfo) {
+		dev_err(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
+			pixelformat);
+		return -EINVAL;
+	}
+
+	if (rpf->interlaced) {
+		dev_err(vsp1->dev, "Prohibited in interlaced mode\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&pipe->irqlock, flags);
+
+	wpf->fmtinfo = fmtinfo;
+	wpf->format.num_planes = fmtinfo->planes;
+	wpf->format.plane_fmt[0].bytesperline = pitch;
+	wpf->format.plane_fmt[1].bytesperline = pitch;
+
+	for (i = 0; i < wpf->format.num_planes; ++i)
+		wpf->buf_addr[i] = mem[i];
+
+	pipe->output->write_back = 3;
+
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vsp1_du_setup_wb);
+
+void vsp1_du_wait_wb(struct device *dev, u32 count)
+{
+	int ret;
+	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
+	struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
+
+	ret = wait_event_interruptible(pipe->event_wait,
+				       (pipe->output->write_back == count));
+}
+EXPORT_SYMBOL_GPL(vsp1_du_wait_wb);
+
 /* -----------------------------------------------------------------------------
  * Initialization
  */
@@ -579,6 +654,7 @@
 {
 	struct vsp1_pipeline *pipe;
 	unsigned int i;
+	int ret;
 
 	vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 	if (!vsp1->drm)
@@ -602,6 +678,14 @@
 	pipe->bru = &vsp1->bru->entity;
 	pipe->lif = &vsp1->lif->entity;
 	pipe->output = vsp1->wpf[0];
+	pipe->output->write_back = 0;
+	init_waitqueue_head(&pipe->event_wait);
+
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(vsp1->dev, "product register init fail.\n");
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index c626955..08a2ca4 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_drv.c  --  R-Car VSP1 Driver
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -11,6 +11,10 @@
  * (at your option) any later version.
  */
 
+#ifdef CONFIG_VIDEO_RENESAS_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -21,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/videodev2.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <media/rcar-fcp.h>
 #include <media/v4l2-subdev.h>
@@ -39,31 +44,152 @@
 #include "vsp1_uds.h"
 #include "vsp1_video.h"
 
+#define VSP1_UT_IRQ	0x01
+
+static unsigned int vsp1_debug;	/* 1 to enable debug output */
+module_param_named(debug, vsp1_debug, int, 0600);
+static int underrun_vspd[4];
+module_param_array(underrun_vspd, int, NULL, 0600);
+
+#ifdef CONFIG_VIDEO_RENESAS_DEBUG
+#define VSP1_IRQ_DEBUG(fmt, args...)					\
+	do {								\
+		if (unlikely(vsp1_debug & VSP1_UT_IRQ))			\
+			vsp1_ut_debug_printk(__func__, fmt, ##args);	\
+	} while (0)
+#else
+#define VSP1_IRQ_DEBUG(fmt, args...)
+#endif
+
+void vsp1_ut_debug_printk(const char *function_name, const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	pr_debug("[vsp1 :%s] %pV", function_name, &vaf);
+
+	va_end(args);
+}
+
+#define SRCR7_REG		0xe61501cc
+#define	FCPVD0_REG		0xfea27000
+#define	FCPVD1_REG		0xfea2f000
+#define	FCPVD2_REG		0xfea37000
+#define	FCPVD3_REG		0xfea3f000
+
+#define FCP_RST_REG		0x0010
+#define FCP_RST_SOFTRST		0x00000001
+#define FCP_RST_WORKAROUND	0x00000010
+
+#define FCP_STA_REG		0x0018
+#define FCP_STA_ACT		0x00000001
+
+static void __iomem *fcpv_reg[4];
+static const unsigned int fcpvd_offset[] = {
+	FCPVD0_REG, FCPVD1_REG, FCPVD2_REG, FCPVD3_REG
+};
+
+void vsp1_underrun_workaround(struct vsp1_device *vsp1, bool reset)
+{
+	unsigned int timeout = 0;
+
+	/* 1. Disable clock stop of VSP */
+	vsp1_write(vsp1, VI6_CLK_CTRL0, VI6_CLK_CTRL0_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_CTRL1, VI6_CLK_CTRL1_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_DCSWT, VI6_CLK_DCSWT_WORKAROUND1);
+	vsp1_write(vsp1, VI6_CLK_DCSM0, VI6_CLK_DCSM0_WORKAROUND);
+	vsp1_write(vsp1, VI6_CLK_DCSM1, VI6_CLK_DCSM1_WORKAROUND);
+
+	/* 2. Stop operation of VSP except bus access with module reset */
+	vsp1_write(vsp1, VI6_MRESET_ENB0, VI6_MRESET_ENB0_WORKAROUND1);
+	vsp1_write(vsp1, VI6_MRESET_ENB1, VI6_MRESET_ENB1_WORKAROUND);
+	vsp1_write(vsp1, VI6_MRESET, VI6_MRESET_WORKAROUND);
+
+	/* 3. Stop operation of FCPV with software reset */
+	iowrite32(FCP_RST_SOFTRST, fcpv_reg[vsp1->index] + FCP_RST_REG);
+
+	/* 4. Wait until FCP_STA.ACT become 0. */
+	while (1) {
+		if ((ioread32(fcpv_reg[vsp1->index] + FCP_STA_REG) &
+			FCP_STA_ACT) != FCP_STA_ACT)
+			break;
+
+		if (timeout == 100)
+			break;
+
+		timeout++;
+		udelay(1);
+	}
+
+	/* 5. Initialize the whole FCPV with module reset */
+	iowrite32(FCP_RST_WORKAROUND, fcpv_reg[vsp1->index] + FCP_RST_REG);
+
+	/* 6. Stop the whole operation of VSP with module reset */
+	/*    (note that register setting is not cleared) */
+	vsp1_write(vsp1, VI6_MRESET_ENB0, VI6_MRESET_ENB0_WORKAROUND2);
+	vsp1_write(vsp1, VI6_MRESET_ENB1, VI6_MRESET_ENB1_WORKAROUND);
+	vsp1_write(vsp1, VI6_MRESET, VI6_MRESET_WORKAROUND);
+
+	/* 7. Enable clock stop of VSP */
+	vsp1_write(vsp1, VI6_CLK_CTRL0, 0);
+	vsp1_write(vsp1, VI6_CLK_CTRL1, 0);
+	vsp1_write(vsp1, VI6_CLK_DCSWT, VI6_CLK_DCSWT_WORKAROUND2);
+	vsp1_write(vsp1, VI6_CLK_DCSM0, 0);
+	vsp1_write(vsp1, VI6_CLK_DCSM1, 0);
+
+	/* 8. Restart VSPD */
+	if (!reset) {
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), vsp1->dl_addr);
+		/* Necessary when headerless display list */
+		if (!vsp1->info->header_mode)
+			vsp1_write(vsp1, VI6_DL_BODY_SIZE, vsp1->dl_body);
+		vsp1_write(vsp1, VI6_CMD(0), VI6_CMD_STRCMD);
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * Interrupt Handling
  */
-
 static irqreturn_t vsp1_irq_handler(int irq, void *data)
 {
-	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
+	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE
+				       | VI6_WFP_IRQ_STA_UND;
 	struct vsp1_device *vsp1 = data;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned int i;
 	u32 status;
+	unsigned int vsp_und_cnt = 0;
+	bool underrun = false;
 
 	for (i = 0; i < vsp1->info->wpf_count; ++i) {
 		struct vsp1_rwpf *wpf = vsp1->wpf[i];
+		struct vsp1_pipeline *pipe;
 
 		if (wpf == NULL)
 			continue;
 
+		pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
 		status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
 		vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
 
+		if (vsp1_debug && (status & VI6_WFP_IRQ_STA_UND)) {
+			vsp_und_cnt = ++underrun_vspd[vsp1->index];
+
+			VSP1_IRQ_DEBUG(
+				"Underrun occurred num[%d] at VSPD (%s)\n",
+				vsp_und_cnt, dev_name(vsp1->dev));
+		}
+
 		if (status & VI6_WFP_IRQ_STA_FRE) {
-			vsp1_pipeline_frame_end(wpf->pipe);
+			vsp1_pipeline_frame_end(pipe);
 			ret = IRQ_HANDLED;
 		}
+		if (status & VI6_WFP_IRQ_STA_UND)
+			underrun = true;
 	}
 
 	status = vsp1_read(vsp1, VI6_DISP_IRQ_STA);
@@ -74,6 +200,10 @@
 		ret = IRQ_HANDLED;
 	}
 
+	if ((RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) && underrun)
+		vsp1_underrun_workaround(vsp1, false);
+
 	return ret;
 }
 
@@ -430,7 +560,12 @@
 	if (!(status & VI6_STATUS_SYS_ACT(index)))
 		return 0;
 
-	vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		vsp1_underrun_workaround(vsp1, true);
+	else
+		vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
+
 	for (timeout = 10; timeout > 0; --timeout) {
 		status = vsp1_read(vsp1, VI6_STATUS);
 		if (!(status & VI6_STATUS_SYS_ACT(index)))
@@ -583,7 +718,7 @@
 		.gen = 2,
 		.features = VSP1_HAS_BRU | VSP1_HAS_SRU,
 		.rpf_count = 5,
-		.uds_count = 1,
+		.uds_count = 3,
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
@@ -594,7 +729,7 @@
 			  | VSP1_HAS_LUT,
 		.rpf_count = 4,
 		.uds_count = 1,
-		.wpf_count = 4,
+		.wpf_count = 1,
 		.num_bru_inputs = 4,
 		.uapi = true,
 	}, {
@@ -603,7 +738,7 @@
 		.features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT
 			  | VSP1_HAS_SRU,
 		.rpf_count = 5,
-		.uds_count = 3,
+		.uds_count = 1,
 		.wpf_count = 4,
 		.num_bru_inputs = 4,
 		.uapi = true,
@@ -638,6 +773,7 @@
 		.rpf_count = 5,
 		.wpf_count = 2,
 		.num_bru_inputs = 5,
+		.header_mode = true,
 	},
 };
 
@@ -718,6 +854,18 @@
 
 	dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
 
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_dbg(vsp1->dev, "product register init fail.\n");
+		return ret;
+	}
+
+	if (vsp1->info->header_mode && !(RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0)))
+		vsp1->auto_fld_mode = true;
+	else
+		vsp1->auto_fld_mode = false;
+
 	/* Instanciate entities */
 	ret = vsp1_create_entities(vsp1);
 	if (ret < 0) {
@@ -725,6 +873,20 @@
 		goto done;
 	}
 
+	if (strcmp(dev_name(vsp1->dev), "fea20000.vsp") == 0)
+		vsp1->index = 0;
+	else if (strcmp(dev_name(vsp1->dev), "fea28000.vsp") == 0)
+		vsp1->index = 1;
+	else if (strcmp(dev_name(vsp1->dev), "fea30000.vsp") == 0)
+		vsp1->index = 2;
+	else if (strcmp(dev_name(vsp1->dev), "fea38000.vsp") == 0)
+		vsp1->index = 3;
+
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		fcpv_reg[vsp1->index] =
+			ioremap(fcpvd_offset[vsp1->index], 0x20);
+
 done:
 	if (ret)
 		pm_runtime_disable(&pdev->dev);
@@ -736,11 +898,16 @@
 {
 	struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
 
+	vsp1_device_put(vsp1);
 	vsp1_destroy_entities(vsp1);
 	rcar_fcp_put(vsp1->fcp);
 
 	pm_runtime_disable(&pdev->dev);
 
+	if (RCAR_PRR_IS_PRODUCT(H3) &&
+		(RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		iounmap(fcpv_reg[vsp1->index]);
+
 	return 0;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index aadeb7d..a6414b9 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -118,7 +118,7 @@
 	{ V4L2_PIX_FMT_YVU420M, MEDIA_BUS_FMT_AYUV8_1X32,
 	  VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-	  3, { 8, 8, 8 }, false, true, 2, 2, false },
+	  3, { 8, 8, 8 }, false, false, 2, 2, false },
 	{ V4L2_PIX_FMT_YUV422M, MEDIA_BUS_FMT_AYUV8_1X32,
 	  VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
@@ -126,7 +126,7 @@
 	{ V4L2_PIX_FMT_YVU422M, MEDIA_BUS_FMT_AYUV8_1X32,
 	  VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-	  3, { 8, 8, 8 }, false, true, 2, 1, false },
+	  3, { 8, 8, 8 }, false, false, 2, 1, false },
 	{ V4L2_PIX_FMT_YUV444M, MEDIA_BUS_FMT_AYUV8_1X32,
 	  VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
@@ -134,7 +134,7 @@
 	{ V4L2_PIX_FMT_YVU444M, MEDIA_BUS_FMT_AYUV8_1X32,
 	  VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
 	  VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-	  3, { 8, 8, 8 }, false, true, 1, 1, false },
+	  3, { 8, 8, 8 }, false, false, 1, 1, false },
 };
 
 /*
@@ -173,13 +173,17 @@
 			bru->inputs[i].rpf = NULL;
 	}
 
-	for (i = 0; i < pipe->num_inputs; ++i) {
-		pipe->inputs[i]->pipe = NULL;
-		pipe->inputs[i] = NULL;
+	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+		if (pipe->inputs[i]) {
+			pipe->inputs[i]->pipe = NULL;
+			pipe->inputs[i] = NULL;
+		}
 	}
 
-	pipe->output->pipe = NULL;
-	pipe->output = NULL;
+	if (pipe->output) {
+		pipe->output->pipe = NULL;
+		pipe->output = NULL;
+	}
 
 	if (pipe->hgo) {
 		struct vsp1_hgo *hgo = to_hgo(&pipe->hgo->subdev);
@@ -206,6 +210,7 @@
 
 	INIT_LIST_HEAD(&pipe->entities);
 	pipe->state = VSP1_PIPELINE_STOPPED;
+	pipe->vmute_flag = false;
 }
 
 /* Must be called with the pipe irqlock held. */
@@ -292,9 +297,18 @@
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
+	unsigned long flags;
+
 	if (pipe == NULL)
 		return;
 
+	spin_lock_irqsave(&pipe->irqlock, flags);
+	if (pipe->output->write_back != 0) {
+		pipe->output->write_back--;
+		wake_up_interruptible(&pipe->event_wait);
+	}
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
+
 	vsp1_dlm_irq_frame_end(pipe->output->dlm);
 
 	if (pipe->hgo)
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index 3ecd3c1..d541b23 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -1,7 +1,7 @@
 /*
  * vsp1_pipe.h  --  R-Car VSP1 Pipeline
  *
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -104,10 +104,20 @@
 	struct vsp1_entity *uds_input;
 
 	struct list_head entities;
+	wait_queue_head_t event_wait;
 
 	struct vsp1_dl_list *dl;
+	bool vmute_flag;
 };
 
+static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
+{
+	if (likely(e->pipe))
+		return container_of(e->pipe, struct vsp1_pipeline, pipe);
+	else
+		return NULL;
+}
+
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
 
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 684a3ef..f9b1ed1 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -1,7 +1,7 @@
 /*
  * vsp1_regs.h  --  R-Car VSP1 Registers Definitions
  *
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -20,23 +20,49 @@
 #define VI6_CMD(n)			(0x0000 + (n) * 4)
 #define VI6_CMD_STRCMD			(1 << 0)
 
+#define VI6_CLK_CTRL0			0x0010
+#define VI6_CLK_CTRL0_WORKAROUND	0x10010F1F
+
+#define VI6_CLK_CTRL1			0x0014
+#define VI6_CLK_CTRL1_WORKAROUND	0xFF00FFFF
+
 #define VI6_CLK_DCSWT			0x0018
 #define VI6_CLK_DCSWT_CSTPW_MASK	(0xff << 8)
 #define VI6_CLK_DCSWT_CSTPW_SHIFT	8
 #define VI6_CLK_DCSWT_CSTRW_MASK	(0xff << 0)
 #define VI6_CLK_DCSWT_CSTRW_SHIFT	0
+#define VI6_CLK_DCSWT_WORKAROUND1	0x00130808
+#define VI6_CLK_DCSWT_WORKAROUND2	0x00000808
+
+#define VI6_CLK_DCSM0			0x001C
+#define VI6_CLK_DCSM0_WORKAROUND	0x1FFF0F1F
+
+#define VI6_CLK_DCSM1			0x0020
+#define VI6_CLK_DCSM1_WORKAROUND	0xFF00FFFF
 
 #define VI6_SRESET			0x0028
 #define VI6_SRESET_SRTS(n)		(1 << (n))
 
+#define VI6_MRESET_ENB0			0x002C
+#define VI6_MRESET_ENB0_WORKAROUND1	0x0000001F
+#define VI6_MRESET_ENB0_WORKAROUND2	0x30000F1F
+
+#define VI6_MRESET_ENB1			0x0030
+#define VI6_MRESET_ENB1_WORKAROUND	0xFF00FFFF
+
+#define VI6_MRESET			0x0034
+#define VI6_MRESET_WORKAROUND		0x00000001
+
 #define VI6_STATUS			0x0038
 #define VI6_STATUS_SYS_ACT(n)		(1 << ((n) + 8))
 
 #define VI6_WPF_IRQ_ENB(n)		(0x0048 + (n) * 12)
+#define VI6_WFP_IRQ_ENB_UNDE		(1 << 16)
 #define VI6_WFP_IRQ_ENB_DFEE		(1 << 1)
 #define VI6_WFP_IRQ_ENB_FREE		(1 << 0)
 
 #define VI6_WPF_IRQ_STA(n)		(0x004c + (n) * 12)
+#define VI6_WFP_IRQ_STA_UND		(1 << 16)
 #define VI6_WFP_IRQ_STA_DFE		(1 << 1)
 #define VI6_WFP_IRQ_STA_FRE		(1 << 0)
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 4895038..a41e42c 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -49,19 +49,34 @@
 static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
 	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+	struct vsp1_device *vsp1 = entity->vsp1;
 
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->mem.addr[0] + rpf->offsets[0]);
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
-		       rpf->mem.addr[1] + rpf->offsets[1]);
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
-		       rpf->mem.addr[2] + rpf->offsets[1]);
+	if (vsp1->auto_fld_mode)
+		vsp1_dl_set_addr_auto_fld(dl, rpf);
+	else {
+		vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
+				rpf->mem.addr[0] + rpf->offsets[0]);
+		if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU420M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU422M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU444M)) {
+			vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
+					rpf->mem.addr[2] + rpf->offsets[1]);
+			vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
+					rpf->mem.addr[1] + rpf->offsets[1]);
+		} else {
+			vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
+					rpf->mem.addr[1] + rpf->offsets[1]);
+			vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
+					rpf->mem.addr[2] + rpf->offsets[1]);
+		}
+	}
 }
 
 static void rpf_configure(struct vsp1_entity *entity,
 			  struct vsp1_pipeline *pipe,
 			  struct vsp1_dl_list *dl)
 {
+	struct vsp1_device *vsp1 = entity->vsp1;
 	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
@@ -72,6 +87,16 @@
 	unsigned int top = 0;
 	u32 pstride;
 	u32 infmt;
+	u32 alph_sel = 0, laya = 0;
+	u32 i;
+	u32 crop_width, crop_height, crop_x, crop_y;
+
+	if (pipe->vmute_flag) {
+		for (i = 0; i < vsp1->info->rpf_count; ++i)
+			vsp1_rpf_write(rpf, dl, VI6_DPR_RPF_ROUTE(i),
+						VI6_DPR_NODE_UNUSED);
+		return;
+	}
 
 	/* Source size, stride and crop offsets.
 	 *
@@ -81,28 +106,72 @@
 	 */
 	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
 
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
-		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
-		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
-		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
-		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
+	crop_width = crop->width;
+	crop_x = crop->left;
 
-	rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
-			+ crop->left * fmtinfo->bpp[0] / 8;
+	if (rpf->interlaced) {
+		crop_height = crop->height / 2;
+		crop_y = crop->top / 2;
+
+		if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_UYVY) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_VYUY) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUYV) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVYU)) {
+			crop_width = round_down(crop_width, 2);
+			crop_x = round_down(crop_x, 2);
+		} else if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_NV12M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_NV21M)) {
+			crop_width = round_down(crop_width, 2);
+			crop_height = round_down(crop_height, 2);
+			crop_x = round_down(crop_x, 2);
+			crop_y = round_down(crop_y, 2);
+		} else if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_NV16M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_NV61M)) {
+			crop_width = round_down(crop_width, 2);
+			crop_x = round_down(crop_x, 2);
+		} else if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUV420M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUV444M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU420M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU444M)) {
+			crop_width = round_down(crop_width, 2);
+			crop_height = round_down(crop_height, 2);
+		} else if ((rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YUV422M) ||
+			(rpf->fmtinfo->fourcc == V4L2_PIX_FMT_YVU422M)) {
+			crop_width = round_down(crop_width, 2);
+			crop_height = round_down(crop_height, 2);
+			crop_x = round_down(crop_x, 2);
+			crop_y = round_down(crop_y, 2);
+		}
+	} else {
+		crop_height = crop->height;
+		crop_y = crop->top;
+	}
+
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
+		       (crop_width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
+		       (crop_height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
+		       (crop_width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
+		       (crop_height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
+
+	rpf->offsets[0] = crop_y * format->plane_fmt[0].bytesperline
+			+ crop_x * fmtinfo->bpp[0] / 8;
 	pstride = format->plane_fmt[0].bytesperline
 		<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
 
 	if (format->num_planes > 1) {
-		rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
-				+ crop->left * fmtinfo->bpp[1] / 8;
+		rpf->offsets[1] = crop_y * format->plane_fmt[1].bytesperline
+				+ crop_x * fmtinfo->bpp[1] / 8;
 		pstride |= format->plane_fmt[1].bytesperline
 			<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
 	} else {
 		rpf->offsets[1] = 0;
 	}
 
-	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
+	if (rpf->interlaced)
+		vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride * 2);
+	else
+		vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
 	sink_format = vsp1_entity_get_pad_format(&rpf->entity,
@@ -138,7 +207,12 @@
 		top = compose->top;
 	}
 
-	vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
+	if (rpf->interlaced)
+		vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
+		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
+		       ((top / 2) << VI6_RPF_LOC_VCOORD_SHIFT));
+	else
+		vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
 		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
 		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
 
@@ -164,23 +238,51 @@
 	 *
 	 * In all cases, disable color keying.
 	 */
-	vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
-		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
-				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
+	switch (fmtinfo->fourcc) {
+	case V4L2_PIX_FMT_ARGB555:
+		if (CONFIG_VIDEO_RENESAS_VSP_ALPHA_BIT_ARGB1555 == 1)
+			alph_sel = VI6_RPF_ALPH_SEL_ASEL_SELECT |
+				   VI6_RPF_ALPH_SEL_AEXT_EXT |
+				   VI6_RPF_ALPH_SEL_ALPHA1_MASK |
+				   (rpf->alpha &
+				   VI6_RPF_ALPH_SEL_ALPHA0_MASK);
+		else
+			alph_sel = VI6_RPF_ALPH_SEL_ASEL_SELECT |
+				   VI6_RPF_ALPH_SEL_AEXT_EXT |
+				   ((rpf->alpha & 0xff) << 8) |
+				   VI6_RPF_ALPH_SEL_ALPHA0_MASK;
+		laya = 0;
+		break;
+	case V4L2_PIX_FMT_ARGB444:
+		alph_sel = VI6_RPF_ALPH_SEL_AEXT_ONE;
+		laya = 0;
+		break;
+	case V4L2_PIX_FMT_ABGR32:
+	case V4L2_PIX_FMT_ARGB32:
+		laya = 0;
+		break;
+	default:
+		alph_sel = VI6_RPF_ALPH_SEL_AEXT_EXT |
+			   (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
+			   : VI6_RPF_ALPH_SEL_ASEL_FIXED);
+		laya = rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT;
+		break;
+	}
 
-	vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
-		       rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, alph_sel);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, laya);
 
 	if (entity->vsp1->info->gen == 3) {
 		u32 mult;
 
-		if (fmtinfo->alpha) {
+		if ((fmtinfo->alpha) &&
+			(fmtinfo->fourcc != V4L2_PIX_FMT_ARGB555)) {
 			/* When the input contains an alpha channel enable the
 			 * alpha multiplier. If the input is premultiplied we
 			 * need to multiply both the alpha channel and the pixel
 			 * components by the global alpha value to keep them
 			 * premultiplied. Otherwise multiply the alpha channel
-			 * only.
+			 * only. The alpha multiplier is disabled in ARGB1555.
 			 */
 			bool premultiplied = format->flags
 					   & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 9ff7c78..e95f23a 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -53,6 +53,11 @@
 	struct vsp1_rwpf_memory mem;
 
 	struct vsp1_dl_manager *dlm;
+
+	bool interlaced;
+
+	int write_back;
+	dma_addr_t buf_addr[3];
 };
 
 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index bcf47e7..be0fab7 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -27,6 +27,8 @@
 #include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
 
+#include <media/rcar-fcp.h>
+
 #include "vsp1.h"
 #include "vsp1_bru.h"
 #include "vsp1_dl.h"
@@ -937,6 +939,7 @@
 {
 	struct vsp1_video *video;
 	const char *direction;
+	struct device *fcp;
 	int ret;
 
 	video = devm_kzalloc(vsp1->dev, sizeof(*video), GFP_KERNEL);
@@ -987,7 +990,8 @@
 	video_set_drvdata(&video->video, video);
 
 	/* ... and the buffers queue... */
-	video->alloc_ctx = vb2_dma_contig_init_ctx(video->vsp1->dev);
+	fcp = rcar_fcp_device(vsp1->fcp);
+	video->alloc_ctx = vb2_dma_contig_init_ctx(fcp ? fcp : vsp1->dev);
 	if (IS_ERR(video->alloc_ctx)) {
 		ret = PTR_ERR(video->alloc_ctx);
 		goto error;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 4e391cc..2ffb221 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -1,7 +1,7 @@
 /*
  * vsp1_wpf.c  --  R-Car VSP1 Write Pixel Formatter
  *
- * Copyright (C) 2013-2014 Renesas Electronics Corporation
+ * Copyright (C) 2013-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -104,6 +104,20 @@
 	u32 outfmt = 0;
 	u32 srcrpf = 0;
 
+	if (pipe->vmute_flag) {
+		vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF +
+			(0x100 * wpf->entity.index),
+			 VI6_WPF_SRCRPF_VIRACT_MST);
+		vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP +
+			(0x100 * wpf->entity.index), 0);
+		vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP +
+			(0x100 * wpf->entity.index), 0);
+		vsp1_wpf_write(wpf, dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+			VI6_DPR_WPF_FPORCH_FP_WPFN);
+
+		return;
+	}
+
 	/* Cropping */
 	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
 
@@ -122,10 +136,21 @@
 						   wpf->entity.config,
 						   RWPF_PAD_SOURCE);
 
-	if (!pipe->lif) {
+	if (!pipe->lif || (wpf->write_back == 2)) {
 		const struct v4l2_pix_format_mplane *format = &wpf->format;
 		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 
+		if (pipe->lif) {
+			vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y,
+						wpf->buf_addr[0]);
+			if (format->num_planes > 1)
+				vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0,
+						wpf->buf_addr[1]);
+			if (format->num_planes > 2)
+				vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1,
+						wpf->buf_addr[2]);
+		}
+
 		outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
 
 		if (fmtinfo->alpha)
@@ -154,7 +179,11 @@
 	vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
 			   VI6_DPR_WPF_FPORCH_FP_WPFN);
 
-	vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);
+	if (pipe->lif && (pipe->output->write_back == 2))
+		vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL,
+					VI6_WPF_WRBCK_CTRL_WBMD);
+	else
+		vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);
 
 	/* Sources. If the pipeline has a single input and BRU is not used,
 	 * configure it as the master layer. Otherwise configure all
@@ -180,7 +209,7 @@
 	/* Enable interrupts */
 	vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
 	vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
-			   VI6_WFP_IRQ_ENB_FREE);
+			   VI6_WFP_IRQ_ENB_FREE | VI6_WFP_IRQ_ENB_UNDE);
 }
 
 static const struct vsp1_entity_operations wpf_entity_ops = {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 99275e4..9dae222 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1130,6 +1130,7 @@
 
 	mmc_set_ios(host);
 }
+EXPORT_SYMBOL(mmc_set_initial_state);
 
 /**
  * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 0aa484c..f0bb76d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -568,6 +568,16 @@
 	  This provides support for the SDHI SD/SDIO controller found in
 	  SuperH and ARM SH-Mobile SoCs
 
+config MMC_SDHI_PIO
+	bool "SH-Mobile SDHI PIO transfer mode setting"
+	depends on MMC_SDHI
+	help
+	  This setting switches the transfer mode of the PIO and DMA.
+
+	  Select Yes or No according to the following.
+	  When switching the transfer mode from DMA to PIO, say Y here.
+	  When switching the transfer mode from PIO to DMA, say N here.
+
 config MMC_CB710
 	tristate "ENE CB710 MMC/SD Interface support"
 	depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index af918d2..dc3e932 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -37,7 +37,13 @@
 obj-$(CONFIG_MMC_TMIO)		+= tmio_mmc.o
 obj-$(CONFIG_MMC_TMIO_CORE)	+= tmio_mmc_core.o
 tmio_mmc_core-y			:= tmio_mmc_pio.o
+ifeq ($(CONFIG_ARM64),y)
+# if CONFIG_ARM64, we assume it is gen3
+tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI))	+= tmio_mmc_dma_gen3.o
+else
+# if no, We assume it is gen2 or older
 tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI))	+= tmio_mmc_dma.o
+endif
 obj-$(CONFIG_MMC_SDHI)		+= sh_mobile_sdhi.o
 obj-$(CONFIG_MMC_CB710)		+= cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 7f9c5e2..c707dbc 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -1,8 +1,8 @@
 /*
  * SuperH Mobile SDHI
  *
+ * Copyright (C) 2016 Renesas Electronics Corporation
  * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
  * Copyright (C) 2009 Magnus Damm
  *
  * This program is free software; you can redistribute it and/or modify
@@ -37,10 +37,15 @@
 
 #include "tmio_mmc.h"
 
-#define EXT_ACC           0xe4
+#define HOST_MODE           0xe4
 
 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
 
+struct sh_mobile_sdhi_scc {
+	unsigned long clk;	/* clock for SDR104 */
+	u32 tap;		/* sampling clock position for SDR104 */
+};
+
 struct sh_mobile_sdhi_of_data {
 	unsigned long tmio_flags;
 	unsigned long capabilities;
@@ -48,6 +53,12 @@
 	enum dma_slave_buswidth dma_buswidth;
 	dma_addr_t dma_rx_offset;
 	unsigned bus_shift;
+	unsigned int max_blk_count;
+	unsigned short max_segs;
+	bool sdbuf_64bit;
+	int scc_offset;
+	struct sh_mobile_sdhi_scc *taps;
+	int taps_num;
 };
 
 static const struct sh_mobile_sdhi_of_data of_default_cfg = {
@@ -60,19 +71,51 @@
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
 };
 
+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = {
+	{
+		.clk = 156000000,
+		.tap = 0x00000703,
+	},
+	{
+		.clk = 0,
+		.tap = 0x00000300,
+	},
+};
+
 static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
 	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
 			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
 	.dma_buswidth	= DMA_SLAVE_BUSWIDTH_4_BYTES,
 	.dma_rx_offset	= 0x2000,
+	.scc_offset = 0x0300,
+	.taps = rcar_gen2_scc_taps,
+	.taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = {
+	{
+		.clk = 0,
+		.tap = 0x00000300,
+	},
 };
 
 static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
 	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
-			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
-	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+			  TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2 |
+			  TMIO_MMC_CLK_NO_SLEEP,
+	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
+			  MMC_CAP_CMD23,
 	.bus_shift	= 2,
+	/* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
+	.max_blk_count	= 0xffffffff,
+	.max_segs = 1,
+	.sdbuf_64bit = true,
+	.scc_offset = 0x1000,
+	.taps = rcar_gen3_scc_taps,
+	.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
 };
 
 static const struct of_device_id sh_mobile_sdhi_of_match[] = {
@@ -88,6 +131,9 @@
 	{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
 	{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
 	{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
+	{ .compatible = "renesas,mmc-r8a7795", .data = &of_rcar_gen3_compatible, },
+	{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
+	{ .compatible = "renesas,mmc-r8a7796", .data = &of_rcar_gen3_compatible, },
 	{},
 };
 MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@@ -129,7 +175,7 @@
 		return;
 	}
 
-	sd_ctrl_write16(host, EXT_ACC, val);
+	sd_ctrl_write16(host, HOST_MODE, val);
 }
 
 static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
@@ -207,6 +253,51 @@
 	clk_disable_unprepare(priv->clk);
 }
 
+static void sh_mobile_sdhi_set_clk_div(struct platform_device *pdev,
+				       int state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+
+	if (state) {
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+				sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x00ff);
+	}
+}
+
+#define SH_MOBILE_SDHI_SIGNAL_180V	0
+#define SH_MOBILE_SDHI_SIGNAL_330V	1
+
+static int sh_mobile_sdhi_set_ioctrl(struct tmio_mmc_host *host, int state)
+{
+	struct platform_device *pdev = host->pdev;
+	struct sh_mobile_sdhi *priv =
+		container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+	struct pinctrl_state *pstate;
+	int ret;
+
+	if (state == SH_MOBILE_SDHI_SIGNAL_330V) {
+		pstate = priv->pins_default;
+	} else if (state == SH_MOBILE_SDHI_SIGNAL_180V) {
+		pstate = priv->pins_uhs;
+	} else {
+		dev_err(&pdev->dev, "update_ioctrl: unknown state\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (!pstate) {
+		ret = -EIO;
+		goto err;
+	}
+
+	return pinctrl_select_state(priv->pinctrl, pstate);
+
+err:
+	return ret;
+}
+
 static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
 						      struct mmc_ios *ios)
 {
@@ -217,9 +308,53 @@
 
 	switch (ios->signal_voltage) {
 	case MMC_SIGNAL_VOLTAGE_330:
+		/* Enable 3.3V Signal */
+		if (!IS_ERR(mmc->supply.vqmmc)) {
+			/* ioctrl */
+			ret = sh_mobile_sdhi_set_ioctrl(host,
+						SH_MOBILE_SDHI_SIGNAL_330V);
+			if (ret) {
+				dev_err(&host->pdev->dev,
+					"3.3V pin function control failed\n");
+				return -EIO;
+			}
+
+			ret = regulator_set_voltage(mmc->supply.vqmmc,
+						    3300000, 3300000);
+			if (ret) {
+				dev_warn(&host->pdev->dev,
+					 "3.3V signalling voltage failed\n");
+				return -EIO;
+			}
+		} else {
+			return -EIO;
+		}
+		usleep_range(5000, 10000);
 		pin_state = priv->pins_default;
 		break;
 	case MMC_SIGNAL_VOLTAGE_180:
+		/* Enable 1.8V Signal */
+		if (!IS_ERR(mmc->supply.vqmmc)) {
+			ret = regulator_set_voltage(mmc->supply.vqmmc,
+						    1800000, 1800000);
+			if (ret) {
+				dev_warn(&host->pdev->dev,
+					 "1.8V signalling voltage failed\n");
+				return -EIO;
+			}
+			/* ioctrl */
+			ret = sh_mobile_sdhi_set_ioctrl(host,
+						SH_MOBILE_SDHI_SIGNAL_180V);
+			if (ret) {
+				dev_err(&host->pdev->dev,
+					"1.8V pin function control failed\n");
+				return -EIO;
+			}
+		} else {
+			return -EIO;
+		}
+		/* Wait for 5ms */
+		usleep_range(5000, 10000);
 		pin_state = priv->pins_uhs;
 		break;
 	default:
@@ -241,6 +376,237 @@
 	return pinctrl_select_state(priv->pinctrl, pin_state);
 }
 
+static int sh_mobile_sdhi_card_busy(struct tmio_mmc_host *host)
+{
+	u32 dat0;
+
+	/* check to see DAT[3:0] */
+	dat0 = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
+	return !(dat0 & TMIO_STAT_DAT0);
+}
+
+/* SCC registers */
+#define SH_MOBILE_SDHI_SCC_DTCNTL	0x000
+#define SH_MOBILE_SDHI_SCC_TAPSET	0x002
+#define SH_MOBILE_SDHI_SCC_DT2FF	0x004
+#define SH_MOBILE_SDHI_SCC_CKSEL	0x006
+#define SH_MOBILE_SDHI_SCC_RVSCNTL	0x008
+#define SH_MOBILE_SDHI_SCC_RVSREQ	0x00A
+#define SH_MOBILE_SDHI_SCC_TMPPORT2	0x00E
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN		(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */
+#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL		(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */
+#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN	(1 << 0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
+#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR	(1 << 2)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */
+#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN	(1 << 31)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */
+#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL	(1 << 4)
+
+static inline u32 sd_scc_read32(struct tmio_mmc_host *host, int addr)
+{
+	struct platform_device *pdev = host->pdev;
+	const struct of_device_id *of_id =
+		of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+	const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+
+	return readl(host->ctl + of_data->scc_offset +
+		     (addr << host->bus_shift));
+}
+
+static inline void sd_scc_write32(struct tmio_mmc_host *host, int addr,
+				  u32 val)
+{
+	struct platform_device *pdev = host->pdev;
+	const struct of_device_id *of_id =
+		of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+	const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+
+	writel(val, host->ctl + of_data->scc_offset +
+	       (addr << host->bus_shift));
+}
+
+static bool sh_mobile_sdhi_inquiry_tuning(struct tmio_mmc_host *host)
+{
+	/* SDHI should be tuning only SDR104 and HS200 */
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 ||
+	    host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
+		return true;
+
+	return false;
+}
+
+static void sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host,
+							unsigned long *num)
+{
+	/* set sampling clock selection range */
+	if (host->scc_tapnum)
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DTCNTL,
+				host->scc_tapnum << 16);
+
+	/* Initialize SCC */
+	sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x00000000);
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DTCNTL,
+		SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_DTCNTL));
+
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_CKSEL,
+		SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_CKSEL));
+
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+		~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
+
+	/* Read TAPNUM */
+	*num = (sd_scc_read32(host, SH_MOBILE_SDHI_SCC_DTCNTL) >> 16) & 0xff;
+}
+
+static int sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
+							unsigned long tap)
+{
+	/* Set sampling clock position */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TAPSET, tap);
+
+	return 0;
+}
+
+static void sh_mobile_sdhi_prepare_hs400_tuning(struct tmio_mmc_host *host)
+{
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+	/* Set HS400 mode */
+	sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 |
+		sd_ctrl_read16(host, CTL_SDIF_MODE));
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TMPPORT2,
+		(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
+		SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_TMPPORT2));
+
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+}
+
+#define SH_MOBILE_SDHI_MAX_TAP	3
+static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host,
+							unsigned long *tap)
+{
+	unsigned long tap_num;	/* total number of taps */
+	unsigned long tap_cnt;	/* counter of tuning success */
+	unsigned long tap_set;	/* tap position */
+	unsigned long tap_start;	/* start position of tuning success */
+	unsigned long tap_end;	/* end position of tuning success */
+	unsigned long ntap;	/* temporary counter of tuning success */
+	unsigned long i;
+
+	/* Clear SCC_RVSREQ */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+
+	/* Select SCC */
+	tap_num = (sd_scc_read32(host,
+				 SH_MOBILE_SDHI_SCC_DTCNTL) >> 16) & 0xff;
+
+	tap_cnt = 0;
+	ntap = 0;
+	tap_start = 0;
+	tap_end = 0;
+	for (i = 0; i < tap_num * 2; i++) {
+		if (tap[i] == 0)
+			ntap++;
+		else {
+			if (ntap > tap_cnt) {
+				tap_start = i - ntap;
+				tap_end = i - 1;
+				tap_cnt = ntap;
+			}
+			ntap = 0;
+		}
+	}
+
+	if (ntap > tap_cnt) {
+		tap_start = i - ntap;
+		tap_end = i - 1;
+		tap_cnt = ntap;
+	}
+
+	if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP)
+		tap_set = (tap_start + tap_end) / 2 % tap_num;
+	else
+		return -EIO;
+
+	/* Set SCC */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
+
+	/* Enable auto re-tuning */
+	sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+		SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN |
+		sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+	return 0;
+}
+
+static bool sh_mobile_sdhi_retuning(struct tmio_mmc_host *host)
+{
+	/* Check SCC error */
+	if (sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL) &
+	    SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
+	    sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSREQ) &
+	    SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
+		/* Clear SCC error */
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+		return true;
+	}
+	return false;
+}
+
+static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
+{
+	struct tmio_mmc_data *pdata = host->pdata;
+
+	if (pdata->flags & TMIO_MMC_HAS_UHS_SCC) {
+		/* Reset SCC */
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_CKSEL,
+			~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_CKSEL));
+
+		/* Reset HS400 mode */
+		sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 &
+			sd_ctrl_read16(host, CTL_SDIF_MODE));
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_TMPPORT2,
+			~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
+			SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_TMPPORT2));
+
+		sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+			sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+			~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+		sd_scc_write32(host, SH_MOBILE_SDHI_SCC_RVSCNTL,
+			~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+			sd_scc_read32(host, SH_MOBILE_SDHI_SCC_RVSCNTL));
+	}
+}
+
 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
 {
 	int timeout = 1000;
@@ -269,7 +635,7 @@
 	case CTL_SD_MEM_CARD_OPT:
 	case CTL_TRANSACTION_CTL:
 	case CTL_DMA_ENABLE:
-	case EXT_ACC:
+	case HOST_MODE:
 		return sh_mobile_sdhi_wait_idle(host);
 	}
 
@@ -296,10 +662,12 @@
 
 static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
 {
+	int dma_width = host->dma->sdbuf_64bit ? 64 : 32;
+
 	sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
 
 	/* enable 32bit access if DMA mode if possibile */
-	sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
+	sh_mobile_sdhi_sdbuf_width(host, enable ? dma_width : 16);
 }
 
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
@@ -312,7 +680,10 @@
 	struct tmio_mmc_host *host;
 	struct resource *res;
 	int irq, ret, i = 0;
+	struct device_node *np = pdev->dev.of_node;
 	struct tmio_mmc_dma *dma_priv;
+	int clk_rate;
+	u32 num, tapnum = 0, tappos;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -332,6 +703,21 @@
 		goto eprobe;
 	}
 
+	if (np && !of_property_read_u32(np, "renesas,clk-rate", &clk_rate)) {
+		if (clk_rate) {
+			clk_prepare_enable(priv->clk);
+			ret = clk_set_rate(priv->clk, clk_rate);
+			if (ret < 0)
+				dev_err(&pdev->dev,
+					"cannot set clock rate: %d\n", ret);
+
+			clk_disable_unprepare(priv->clk);
+		}
+	}
+
+	if (np && !of_property_read_u32(np, "renesas,mmc-scc-tapnum", &num))
+		tapnum = num;
+
 	priv->pinctrl = devm_pinctrl_get(&pdev->dev);
 	if (!IS_ERR(priv->pinctrl)) {
 		priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
@@ -348,13 +734,49 @@
 
 	if (of_id && of_id->data) {
 		const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
+		const struct sh_mobile_sdhi_scc *taps = of_data->taps;
 
 		mmc_data->flags |= of_data->tmio_flags;
 		mmc_data->capabilities |= of_data->capabilities;
 		mmc_data->capabilities2 |= of_data->capabilities2;
 		mmc_data->dma_rx_offset = of_data->dma_rx_offset;
+		mmc_data->max_blk_count	= of_data->max_blk_count;
+		mmc_data->max_segs = of_data->max_segs;
 		dma_priv->dma_buswidth = of_data->dma_buswidth;
+		dma_priv->sdbuf_64bit = of_data->sdbuf_64bit;
 		host->bus_shift = of_data->bus_shift;
+		if (np && !of_property_read_u32(np, "renesas,mmc-scc-tappos",
+						&tappos)) {
+			host->scc_tappos = tappos;
+		} else {
+			for (i = 0, taps = of_data->taps;
+			     i < of_data->taps_num; i++, taps++) {
+				if (taps->clk == 0 || taps->clk == clk_rate) {
+					host->scc_tappos = taps->tap;
+					break;
+				}
+			}
+			if (taps->clk != 0 && taps->clk != clk_rate)
+				dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104 and HS200\n");
+		}
+	}
+
+	if (of_find_property(np, "sd-uhs-sdr50", NULL))
+		mmc_data->capabilities |= MMC_CAP_UHS_SDR50;
+	if (of_find_property(np, "sd-uhs-sdr104", NULL))
+		mmc_data->capabilities |= MMC_CAP_UHS_SDR104;
+	if (of_find_property(np, "mmc-hs200-1_8v", NULL))
+		mmc_data->capabilities2 |= MMC_CAP2_HS200_1_8V_SDR;
+	if (of_find_property(np, "mmc-hs400-1_8v", NULL))
+		mmc_data->capabilities2 |= MMC_CAP2_HS400_1_8V |
+					   MMC_CAP2_HS200_1_8V_SDR;
+
+	if ((mmc_data->capabilities & MMC_CAP_UHS_SDR104) ||
+	    (mmc_data->capabilities2 & MMC_CAP2_HS200_1_8V_SDR) ||
+	    (mmc_data->capabilities2 & (MMC_CAP2_HS400_1_8V |
+					MMC_CAP2_HS200_1_8V_SDR))) {
+		mmc_data->capabilities |= MMC_CAP_HW_RESET;
+		mmc_data->flags |= TMIO_MMC_HAS_UHS_SCC;
 	}
 
 	host->dma		= dma_priv;
@@ -362,11 +784,25 @@
 	host->clk_enable	= sh_mobile_sdhi_clk_enable;
 	host->clk_update	= sh_mobile_sdhi_clk_update;
 	host->clk_disable	= sh_mobile_sdhi_clk_disable;
+	host->card_busy		= sh_mobile_sdhi_card_busy;
 	host->multi_io_quirk	= sh_mobile_sdhi_multi_io_quirk;
-	host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch;
+	host->set_clk_div	= sh_mobile_sdhi_set_clk_div;
+	host->start_signal_voltage_switch =
+			sh_mobile_sdhi_start_signal_voltage_switch;
+	host->inquiry_tuning = sh_mobile_sdhi_inquiry_tuning;
+	host->init_tuning = sh_mobile_sdhi_init_tuning;
+	host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+	host->select_tuning = sh_mobile_sdhi_select_tuning;
+	host->retuning = sh_mobile_sdhi_retuning;
+	host->hw_reset = sh_mobile_sdhi_hw_reset;
+	host->scc_tapnum = tapnum;
+	host->prepare_hs400_tuning = sh_mobile_sdhi_prepare_hs400_tuning;
 
 	/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
-	if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */
+	if (resource_size(res) > 0x400)
+		host->bus_shift = 2;
+	else if (!host->bus_shift &&
+	    resource_size(res) > 0x100) /* old way to determine the shift */
 		host->bus_shift = 1;
 
 	if (mmd)
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index c14fa22..5ec0f90 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -1,8 +1,8 @@
 /*
  * linux/drivers/mmc/host/tmio_mmc.h
  *
+ * Copyright (C) 2016 Renesas Electronics Corporation
  * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
  * Copyright (C) 2007 Ian Molton
  * Copyright (C) 2004 Ian Molton
  *
@@ -19,6 +19,7 @@
 #define TMIO_MMC_H
 
 #include <linux/dmaengine.h>
+#include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/mutex.h>
 #include <linux/pagemap.h>
@@ -45,6 +46,7 @@
 #define CTL_DMA_ENABLE 0xd8
 #define CTL_RESET_SD 0xe0
 #define CTL_VERSION 0xe2
+#define CTL_SDIF_MODE 0xe6
 #define CTL_SDIO_REGS 0x100
 #define CTL_CLK_AND_WAIT_CTL 0x138
 #define CTL_RESET_SDIO 0x1e0
@@ -101,6 +103,7 @@
 
 struct tmio_mmc_dma {
 	enum dma_slave_buswidth dma_buswidth;
+	bool sdbuf_64bit;
 	bool (*filter)(struct dma_chan *chan, void *arg);
 	void (*enable)(struct tmio_mmc_host *host, bool enable);
 };
@@ -150,6 +153,10 @@
 	struct mutex		ios_lock;	/* protect set_ios() context */
 	bool			native_hotplug;
 	bool			sdio_irq_enabled;
+	u32			scc_tapnum;
+	u32			scc_tappos;
+	bool			done_tuning;
+	struct completion	completion;
 
 	int (*write16_hook)(struct tmio_mmc_host *host, int addr);
 	int (*clk_enable)(struct tmio_mmc_host *host);
@@ -160,6 +167,14 @@
 			      unsigned int direction, int blk_size);
 	int (*start_signal_voltage_switch)(struct mmc_host *mmc,
 					   struct mmc_ios *ios);
+	int (*card_busy)(struct tmio_mmc_host *host);
+	bool (*inquiry_tuning)(struct tmio_mmc_host *host);
+	void (*init_tuning)(struct tmio_mmc_host *host, unsigned long *num);
+	int (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
+	int (*select_tuning)(struct tmio_mmc_host *host, unsigned long *tap);
+	bool (*retuning)(struct tmio_mmc_host *host);
+	void (*hw_reset)(struct tmio_mmc_host *host);
+	void (*prepare_hs400_tuning)(struct tmio_mmc_host *host);
 };
 
 struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
@@ -268,4 +283,6 @@
 	writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
 }
 
+extern void mmc_set_initial_state(struct mmc_host *host);
+
 #endif
diff --git a/drivers/mmc/host/tmio_mmc_dma_gen3.c b/drivers/mmc/host/tmio_mmc_dma_gen3.c
new file mode 100644
index 0000000..b289dfa
--- /dev/null
+++ b/drivers/mmc/host/tmio_mmc_dma_gen3.c
@@ -0,0 +1,196 @@
+/*
+ * linux/drivers/mmc/tmio_mmc_dma_gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * 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.
+ *
+ * R-Car Gen3 DMA function for TMIO MMC implementations
+ */
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+
+#include "tmio_mmc.h"
+
+#define DM_CM_DTRAN_MODE	0x820
+#define DM_CM_DTRAN_CTRL	0x828
+#define DM_CM_RST		0x830
+#define DM_CM_INFO1		0x840
+#define DM_CM_INFO1_MASK	0x848
+#define DM_CM_INFO2		0x850
+#define DM_CM_INFO2_MASK	0x858
+#define DM_DTRAN_ADDR		0x880
+
+/* DM_CM_DTRAN_MODE */
+#define DTRAN_MODE_CH_NUM_CH0	0	/* "downstream" = for write commands */
+#define DTRAN_MODE_CH_NUM_CH1	BIT(16)	/* "uptream" = for read commands */
+#define DTRAN_MODE_BUS_WID_TH	(BIT(5) | BIT(4))
+#define DTRAN_MODE_ADDR_MODE	BIT(0)	/* 1 = Increment address */
+
+/* DM_CM_DTRAN_CTRL */
+#define DTRAN_CTRL_DM_START	BIT(0)
+
+/* DM_CM_RST */
+#define RST_DTRANRST1		BIT(9)
+#define RST_DTRANRST0		BIT(8)
+#define RST_RESERVED_BITS	GENMASK_ULL(32, 0)
+
+/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
+#define INFO1_CLEAR		0
+#define INFO1_DTRANEND1		BIT(17)
+#define INFO1_DTRANEND0		BIT(16)
+
+/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
+#define INFO2_DTRANERR1		BIT(17)
+#define INFO2_DTRANERR0		BIT(16)
+
+/*
+ * Specification of this driver:
+ * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
+ * - Since this SDHI DMAC register set has actual 32-bit and "bus_shift" is 2,
+ *   this driver cannot use original sd_ctrl_{write,read}32 functions.
+ */
+
+static void tmio_dm_write(struct tmio_mmc_host *host, int addr, u64 val)
+{
+	writeq(val, host->ctl + addr);
+}
+
+void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+	if (!host->chan_tx || !host->chan_rx)
+		return;
+
+	if (!enable)
+		tmio_dm_write(host, DM_CM_INFO1, INFO1_CLEAR);
+
+	if (host->dma->enable)
+		host->dma->enable(host, enable);
+}
+
+void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+{
+	u64 val = RST_DTRANRST1 | RST_DTRANRST0;
+
+	dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+	tmio_mmc_enable_dma(host, false);
+
+	tmio_dm_write(host, DM_CM_RST, RST_RESERVED_BITS & ~val);
+	tmio_dm_write(host, DM_CM_RST, RST_RESERVED_BITS | val);
+
+	tmio_mmc_enable_dma(host, true);
+}
+
+void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data)
+{
+	struct scatterlist *sg = host->sg_ptr;
+	u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
+	enum dma_data_direction dir;
+	int ret;
+	u32 irq_mask;
+
+	if (!host->chan_rx || !host->chan_tx)
+		return;
+
+	/* This DMAC cannot handle if sg_len is not 1 */
+	WARN_ON(host->sg_len > 1);
+
+	dev_dbg(&host->pdev->dev, "%s: %d, %x\n", __func__, host->sg_len,
+		data->flags);
+
+	/* This DMAC cannot handle if buffer is not 8-bytes alignment */
+	if (!IS_ALIGNED(sg->offset, 8)) {
+		host->force_pio = true;
+		tmio_mmc_enable_dma(host, false);
+		return;
+	}
+
+	if (data->flags & MMC_DATA_READ) {
+		dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
+		dir = DMA_FROM_DEVICE;
+		irq_mask = TMIO_STAT_RXRDY;
+	} else {
+		dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
+		dir = DMA_TO_DEVICE;
+		irq_mask = TMIO_STAT_TXRQ;
+	}
+
+	ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
+	if (ret < 0) {
+		dev_err(&host->pdev->dev, "%s: dma_map_sg failed\n", __func__);
+		return;
+	}
+
+	tmio_mmc_enable_dma(host, true);
+
+	/* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */
+	tmio_mmc_disable_mmc_irqs(host, irq_mask);
+
+	/* set dma parameters */
+	tmio_dm_write(host, DM_CM_DTRAN_MODE, dtran_mode);
+	tmio_dm_write(host, DM_DTRAN_ADDR, sg->dma_address);
+}
+
+#ifndef CONFIG_MMC_SDHI_PIO
+static void tmio_mmc_issue_tasklet_fn(unsigned long arg)
+{
+	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+
+	dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+	tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+
+	/* start the DMAC */
+	tmio_dm_write(host, DM_CM_DTRAN_CTRL, DTRAN_CTRL_DM_START);
+}
+
+static void tmio_mmc_complete_tasklet_fn(unsigned long arg)
+{
+	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
+	enum dma_data_direction dir;
+
+	dev_dbg(&host->pdev->dev, "%s: %p\n", __func__, host->data);
+
+	if (!host->data)
+		return;
+
+	if (host->data->flags & MMC_DATA_READ)
+		dir = DMA_FROM_DEVICE;
+	else
+		dir = DMA_TO_DEVICE;
+
+	tmio_mmc_enable_dma(host, false);
+	dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
+	tmio_mmc_do_data_irq(host);
+}
+#endif
+
+void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+			  struct tmio_mmc_data *pdata)
+{
+#ifndef CONFIG_MMC_SDHI_PIO
+	/* Each value is set to non-zero to assume "enabling" each DMA */
+	host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
+
+	tasklet_init(&host->dma_complete, tmio_mmc_complete_tasklet_fn,
+		     (unsigned long)host);
+	tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn,
+		     (unsigned long)host);
+#endif
+}
+
+void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+	/* Each value is set to zero to assume "disabling" each DMA */
+	host->chan_rx = host->chan_tx = NULL;
+}
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 438b823..add0f6e 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1,8 +1,8 @@
 /*
  * linux/drivers/mmc/host/tmio_mmc_pio.c
  *
+ * Copyright (C) 2016 Renesas Electronics Corporation
  * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
  * Copyright (C) 2011 Guennadi Liakhovetski
  * Copyright (C) 2007 Ian Molton
  * Copyright (C) 2004 Ian Molton
@@ -36,6 +36,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/mfd/tmio.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/slot-gpio.h>
@@ -52,6 +53,13 @@
 
 #include "tmio_mmc.h"
 
+static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode);
+static int tmio_mmc_start_data(struct tmio_mmc_host *host,
+	struct mmc_data *data);
+static int tmio_mmc_start_command(struct tmio_mmc_host *host,
+	struct mmc_command *cmd);
+static void tmio_mmc_hw_reset(struct mmc_host *mmc);
+
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
 {
 	host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
@@ -160,8 +168,9 @@
 	msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 1 : 10);
 
 	if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
-		sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
-		msleep(10);
+		sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, CLK_CTL_SCLKEN);
+		if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+			msleep(10);
 	}
 }
 
@@ -169,7 +178,8 @@
 {
 	if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
 		sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
-		msleep(10);
+		if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+			msleep(10);
 	}
 
 	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
@@ -196,8 +206,13 @@
 		clock <<= 1;
 
 	/* 1/1 clock is option */
-	if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1))
-		clk |= 0xff;
+	if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) &&
+	    ((clk >> 22) & 0x1)) {
+		if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
+			clk |= 0xff;
+		else
+			clk &= ~0xff;
+	}
 
 	if (host->set_clk_div)
 		host->set_clk_div(host->pdev, (clk >> 22) & 1);
@@ -230,6 +245,7 @@
 						  delayed_reset_work.work);
 	struct mmc_request *mrq;
 	unsigned long flags;
+	u16 clk;
 
 	spin_lock_irqsave(&host->lock, flags);
 	mrq = host->mrq;
@@ -263,7 +279,9 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	clk = sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL) & 0x0ff;
 	tmio_mmc_reset(host);
+	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk | 0x100);
 
 	/* Ready for new calls */
 	host->mrq = NULL;
@@ -277,6 +295,8 @@
 {
 	struct mmc_request *mrq;
 	unsigned long flags;
+	bool result;
+	struct mmc_command *cmd = host->cmd;
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -290,7 +310,9 @@
 	host->data = NULL;
 	host->force_pio = false;
 
-	cancel_delayed_work(&host->delayed_reset_work);
+	if (!(host->inquiry_tuning && host->inquiry_tuning(host) &&
+	      !host->done_tuning) || cmd != mrq->sbc)
+		cancel_delayed_work(&host->delayed_reset_work);
 
 	host->mrq = NULL;
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -298,6 +320,29 @@
 	if (mrq->cmd->error || (mrq->data && mrq->data->error))
 		tmio_mmc_abort_dma(host);
 
+	if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+	     !host->done_tuning) {
+		/* call retuning() to clear SCC error bit */
+		if (host->retuning)
+			host->retuning(host);
+		/* finish processing tuning request */
+		complete(&host->completion);
+		return;
+	}
+
+	/* Check retuning */
+	if (host->retuning && host->done_tuning) {
+		result = host->retuning(host);
+		if (result || (mrq->cmd->error == -EILSEQ))
+			host->done_tuning = false;
+	}
+
+	if (cmd == mrq->sbc) {
+		/* finish SET_BLOCK_COUNT request */
+		complete(&host->completion);
+		return;
+	}
+
 	mmc_request_done(host->mmc, mrq);
 }
 
@@ -308,6 +353,165 @@
 	tmio_mmc_finish_request(host);
 }
 
+#define TMIO_MMC_MAX_TUNING_LOOP 40
+
+static int _tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	struct mmc_ios *ios = &mmc->ios;
+
+	unsigned long timeout, val, num;
+	unsigned long *tap;
+	int tuning_loop_counter = TMIO_MMC_MAX_TUNING_LOOP;
+	int ret, timeleft;
+
+	struct mmc_request mrq = {NULL};
+	struct mmc_command cmd = {0};
+	struct mmc_data data = {0};
+	struct scatterlist sg;
+	u8 *data_buf;
+	unsigned int tm = CMDREQ_TIMEOUT;
+	unsigned long flags;
+	u8 data_size = 64;
+
+	if (ios->timing != MMC_TIMING_UHS_SDR50 &&
+	    ios->timing != MMC_TIMING_UHS_SDR104 &&
+	    ios->timing != MMC_TIMING_MMC_HS200 &&
+	    ios->timing != MMC_TIMING_MMC_HS400)
+		return 0;
+
+	if ((host->inquiry_tuning && !host->inquiry_tuning(host)) ||
+	    host->done_tuning)
+		return 0;
+
+	host->init_tuning(host, &num);
+
+	tap = kmalloc(num * 2, GFP_KERNEL);
+	if (tap == NULL) {
+		ret = -ENOMEM;
+		goto err_tap;
+	}
+
+	if (ios->timing == MMC_TIMING_MMC_HS200)
+		data_size = 128;
+
+	data_buf = kmalloc(data_size, GFP_KERNEL);
+	if (data_buf == NULL) {
+		ret = -ENOMEM;
+		goto err_data;
+	}
+
+	val = 0;
+
+	/*
+	 * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+	 * of loops reaches 40 times or a timeout of 150ms occurs.
+	 */
+	timeout = 150;
+	do {
+		if (host->prepare_tuning)
+			host->prepare_tuning(host, val % num);
+
+		if (!tuning_loop_counter && !timeout)
+			break;
+
+		/*
+		 * In response to CMD19, the card sends 64 bytes of tuning
+		 * block to the Host Controller. So we set the block size
+		 * to 64 here.
+		 */
+
+		spin_lock_irqsave(&host->lock, flags);
+		init_completion(&host->completion);
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+
+		cmd.opcode = opcode;
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		cmd.retries = 0;
+		cmd.error = 0;
+
+		data.blksz = data_size;
+		data.blocks = 1;
+		data.flags = MMC_DATA_READ;
+		data.sg = &sg;
+		data.sg_len = 1;
+		data.error = 0;
+
+		sg_init_one(&sg, data_buf, data_size);
+
+		host->mrq = &mrq;
+
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		ret = tmio_mmc_start_data(host, mrq.data);
+		if (ret)
+			goto out;
+
+		ret = tmio_mmc_start_command(host, mrq.cmd);
+		if (ret)
+			goto out;
+
+		timeleft = wait_for_completion_timeout(&host->completion,
+						       msecs_to_jiffies(tm));
+		if (timeleft < 0) {
+			ret = timeleft;
+			goto out;
+		}
+
+		if (!timeleft) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+
+		/* Check CRC error */
+		if (cmd.error && cmd.error != -EILSEQ) {
+			ret = cmd.error;
+			goto out;
+		}
+		if (data.error && data.error != -EILSEQ) {
+			ret = data.error;
+			goto out;
+		}
+
+		tap[val] = (cmd.error | data.error);
+
+		val++;
+		tuning_loop_counter--;
+		timeout--;
+		mdelay(1);
+	} while ((val < (num * 2)) && (tuning_loop_counter || timeout));
+
+	/*
+	 * The Host Driver has exhausted the maximum number of loops allowed,
+	 * so use fixed sampling frequency.
+	 */
+	if (tuning_loop_counter || timeout) {
+		if (host->select_tuning) {
+			ret = host->select_tuning(host, tap);
+			if (ret < 0)
+				goto out;
+		}
+		host->done_tuning = true;
+	} else {
+		dev_warn(&host->pdev->dev, ": Tuning procedure failed\n");
+		ret = -EIO;
+		goto out;
+	}
+
+out:
+	kfree(data_buf);
+err_data:
+	kfree(tap);
+err_tap:
+	if (ret < 0)
+		tmio_mmc_hw_reset(mmc);
+
+	return ret;
+
+}
+
 /* These are the bitmasks the tmio chip requires to implement the MMC response
  * types. Note that R1 and R6 are the same in this scheme. */
 #define APP_CMD        0x0040
@@ -337,6 +541,8 @@
 	switch (mmc_resp_type(cmd)) {
 	case MMC_RSP_NONE: c |= RESP_NONE; break;
 	case MMC_RSP_R1:   c |= RESP_R1;   break;
+	case MMC_RSP_R1 & ~MMC_RSP_CRC:
+			   c |= RESP_R1;   break;
 	case MMC_RSP_R1B:  c |= RESP_R1B;  break;
 	case MMC_RSP_R2:   c |= RESP_R2;   break;
 	case MMC_RSP_R3:   c |= RESP_R3;   break;
@@ -363,7 +569,8 @@
 			 * multiple block transfer
 			 */
 			if ((host->pdata->flags & TMIO_MMC_HAVE_CMD12_CTRL) &&
-			    (cmd->opcode == SD_IO_RW_EXTENDED))
+			    ((cmd->opcode == SD_IO_RW_EXTENDED) ||
+			     host->mrq->sbc))
 				c |= NO_CMD12_ISSUE;
 		}
 		if (data->flags & MMC_DATA_READ)
@@ -520,7 +727,7 @@
 	schedule_work(&host->done);
 }
 
-static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
+static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
 {
 	struct mmc_data *data;
 	spin_lock(&host->lock);
@@ -529,6 +736,9 @@
 	if (!data)
 		goto out;
 
+	if (stat & TMIO_STAT_CRCFAIL || stat & TMIO_STAT_STOPBIT_ERR ||
+	    stat & TMIO_STAT_TXUNDERRUN)
+		data->error = -EILSEQ;
 	if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
 		u32 status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
 		bool done = false;
@@ -577,8 +787,6 @@
 		goto out;
 	}
 
-	host->cmd = NULL;
-
 	/* This controller is sicker than the PXA one. Not only do we need to
 	 * drop the top 8 bits of the first response word, we also need to
 	 * modify the order of the response for short response command types.
@@ -598,14 +806,16 @@
 
 	if (stat & TMIO_STAT_CMDTIMEOUT)
 		cmd->error = -ETIMEDOUT;
-	else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
+	else if ((stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) ||
+		 stat & TMIO_STAT_STOPBIT_ERR ||
+		 stat & TMIO_STAT_CMD_IDX_ERR)
 		cmd->error = -EILSEQ;
 
 	/* If there is data to handle we enable data IRQs here, and
 	 * we will ultimatley finish the request in the data_end handler.
 	 * If theres no data or we encountered an error, finish now.
 	 */
-	if (host->data && !cmd->error) {
+	if (host->data && (!cmd->error || cmd->error == -EILSEQ)) {
 		if (host->data->flags & MMC_DATA_READ) {
 			if (host->force_pio || !host->chan_rx)
 				tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
@@ -666,7 +876,7 @@
 	/* Data transfer completion */
 	if (ireg & TMIO_STAT_DATAEND) {
 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
-		tmio_mmc_data_irq(host);
+		tmio_mmc_data_irq(host, status);
 		return true;
 	}
 
@@ -759,6 +969,7 @@
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 	unsigned long flags;
 	int ret;
+	u32 opcode;
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -778,6 +989,50 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+	    !host->done_tuning && host->mmc->card) {
+		if (mmc_card_mmc(host->mmc->card))
+			opcode = MMC_SEND_TUNING_BLOCK_HS200;
+		else
+			opcode = MMC_SEND_TUNING_BLOCK;
+		/* Start retuning */
+		ret = tmio_mmc_execute_tuning(mmc, opcode);
+		if (ret)
+			goto fail;
+		/* Restore request */
+		host->mrq = mrq;
+	}
+
+	if (mrq->sbc) {
+		init_completion(&host->completion);
+		ret = tmio_mmc_start_command(host, mrq->sbc);
+		if (ret)
+			goto fail;
+		ret = wait_for_completion_timeout(&host->completion,
+					msecs_to_jiffies(CMDREQ_TIMEOUT));
+		if (ret < 0)
+			goto fail;
+		if (!ret) {
+			ret = -ETIMEDOUT;
+			goto fail;
+		}
+		host->last_req_ts = jiffies;
+		host->mrq = mrq;
+		if (host->inquiry_tuning && host->inquiry_tuning(host) &&
+		    !host->done_tuning && host->mmc->card) {
+			if (mmc_card_mmc(host->mmc->card))
+				opcode = MMC_SEND_TUNING_BLOCK_HS200;
+			else
+				opcode = MMC_SEND_TUNING_BLOCK;
+			/* Start retuning */
+			ret = tmio_mmc_execute_tuning(mmc, opcode);
+			if (ret)
+				goto fail;
+			/* Restore request */
+			host->mrq = mrq;
+		}
+	}
+
 	if (mrq->data) {
 		ret = tmio_mmc_start_data(host, mrq->data);
 		if (ret)
@@ -857,12 +1112,21 @@
 static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
 				unsigned char bus_width)
 {
+	sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, ~0xa000 &
+		sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
+
 	switch (bus_width) {
 	case MMC_BUS_WIDTH_1:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x8000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
 		break;
 	case MMC_BUS_WIDTH_4:
-		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x0000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
+		break;
+	case MMC_BUS_WIDTH_8:
+		sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x2000 |
+			sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT));
 		break;
 	}
 }
@@ -879,6 +1143,11 @@
 	struct device *dev = &host->pdev->dev;
 	unsigned long flags;
 
+	/* HS400 Register setting */
+	if (ios->timing == MMC_TIMING_MMC_HS400)
+		if (host->prepare_hs400_tuning)
+			host->prepare_hs400_tuning(host);
+
 	mutex_lock(&host->ios_lock);
 
 	spin_lock_irqsave(&host->lock, flags);
@@ -967,6 +1236,45 @@
 	return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
 }
 
+static int tmio_mmc_start_signal_voltage_switch(struct mmc_host *mmc,
+	struct mmc_ios *ios)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	int ret;
+
+	if (host->start_signal_voltage_switch) {
+		ret = host->start_signal_voltage_switch(mmc, ios);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	int ret;
+
+	ret = _tmio_mmc_execute_tuning(mmc, opcode);
+
+	if (ret)
+		mmc_set_initial_state(mmc);
+
+	return ret;
+}
+
+static void tmio_mmc_hw_reset(struct mmc_host *mmc)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+
+	tmio_mmc_reset(host);
+
+	if (host->hw_reset)
+		host->hw_reset(host);
+
+	host->done_tuning = false;
+}
+
 static struct mmc_host_ops tmio_mmc_ops = {
 	.request	= tmio_mmc_request,
 	.set_ios	= tmio_mmc_set_ios,
@@ -975,6 +1283,10 @@
 	.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 	.card_busy	= tmio_mmc_card_busy,
 	.multi_io_quirk	= tmio_multi_io_quirk,
+	.start_signal_voltage_switch
+		= tmio_mmc_start_signal_voltage_switch,
+	.execute_tuning = tmio_mmc_execute_tuning,
+	.hw_reset	= tmio_mmc_hw_reset,
 };
 
 static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
@@ -1077,13 +1389,14 @@
 
 	mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
 	mmc->caps2 |= pdata->capabilities2;
-	mmc->max_segs = 32;
+	mmc->max_segs = pdata->max_segs ? pdata->max_segs : 32;
 	mmc->max_blk_size = 512;
-	mmc->max_blk_count = (PAGE_SIZE / mmc->max_blk_size) *
-		mmc->max_segs;
+	mmc->max_blk_count = pdata->max_blk_count ? :
+		(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_req_size;
 
+	_host->done_tuning = false;
 	_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
 				  mmc->caps & MMC_CAP_NEEDS_POLL ||
 				  mmc->caps & MMC_CAP_NONREMOVABLE ||
@@ -1235,6 +1548,8 @@
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct tmio_mmc_host *host = mmc_priv(mmc);
 
+	tmio_mmc_hw_reset(mmc);
+
 	if (host->clk_disable)
 		host->clk_disable(host);
 
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 4e5d5e9..ed90a93 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -76,6 +76,7 @@
 	CDAR20	= 0x0060,
 	CDAR21	= 0x0064,
 	ESR	= 0x0088,
+	APSR	= 0x008C,	/* R-Car Gen3 only */
 	RCR	= 0x0090,
 	RQC0	= 0x0094,
 	RQC1	= 0x0098,
@@ -83,6 +84,7 @@
 	RQC3	= 0x00A0,
 	RQC4	= 0x00A4,
 	RPC	= 0x00B0,
+	RTC	= 0x00B4,	/* R-Car Gen3 only */
 	UFCW	= 0x00BC,
 	UFCS	= 0x00C0,
 	UFCV0	= 0x00C4,
@@ -128,11 +130,52 @@
 	SFP29	= 0x0174,
 	SFP30	= 0x0178,
 	SFP31	= 0x017C,
+	SFV0	= 0x01B8,	/* R-Car Gen3 only */
+	SFV1	= 0x01BC,	/* R-Car Gen3 only */
 	SFM0	= 0x01C0,
 	SFM1	= 0x01C4,
+	SFL	= 0x01C8,	/* R-Car Gen3 only */
+	PCRC	= 0x01CC,	/* R-Car Gen3 only */
+	CIAR0	= 0x0200,	/* R-Car Gen3 only */
+	CIAR1	= 0x0204,	/* R-Car Gen3 only */
+	CIAR2	= 0x0208,	/* R-Car Gen3 only */
+	CIAR3	= 0x020C,	/* R-Car Gen3 only */
+	CIAR4	= 0x0210,	/* R-Car Gen3 only */
+	CIAR5	= 0x0214,	/* R-Car Gen3 only */
+	CIAR6	= 0x0218,	/* R-Car Gen3 only */
+	CIAR7	= 0x021C,	/* R-Car Gen3 only */
+	CIAR8	= 0x0220,	/* R-Car Gen3 only */
+	CIAR9	= 0x0224,	/* R-Car Gen3 only */
+	CIAR10	= 0x0228,	/* R-Car Gen3 only */
+	CIAR11	= 0x022C,	/* R-Car Gen3 only */
+	CIAR12	= 0x0230,	/* R-Car Gen3 only */
+	CIAR13	= 0x0234,	/* R-Car Gen3 only */
+	CIAR14	= 0x0238,	/* R-Car Gen3 only */
+	CIAR15	= 0x023C,	/* R-Car Gen3 only */
+	CIAR16	= 0x0240,	/* R-Car Gen3 only */
+	CIAR17	= 0x0244,	/* R-Car Gen3 only */
+	LIAR0	= 0x0280,	/* R-Car Gen3 only */
+	LIAR1	= 0x0284,	/* R-Car Gen3 only */
+	LIAR2	= 0x0288,	/* R-Car Gen3 only */
+	LIAR3	= 0x028C,	/* R-Car Gen3 only */
+	LIAR4	= 0x0290,	/* R-Car Gen3 only */
+	LIAR5	= 0x0294,	/* R-Car Gen3 only */
+	LIAR6	= 0x0298,	/* R-Car Gen3 only */
+	LIAR7	= 0x029C,	/* R-Car Gen3 only */
+	LIAR8	= 0x02A0,	/* R-Car Gen3 only */
+	LIAR9	= 0x02A4,	/* R-Car Gen3 only */
+	LIAR10	= 0x02A8,	/* R-Car Gen3 only */
+	LIAR11	= 0x02AC,	/* R-Car Gen3 only */
+	LIAR12	= 0x02B0,	/* R-Car Gen3 only */
+	LIAR13	= 0x02B4,	/* R-Car Gen3 only */
+	LIAR14	= 0x02B8,	/* R-Car Gen3 only */
+	LIAR15	= 0x02BC,	/* R-Car Gen3 only */
+	LIAR16	= 0x02C0,	/* R-Car Gen3 only */
+	LIAR17	= 0x02C4,	/* R-Car Gen3 only */
 	TGC	= 0x0300,
 	TCCR	= 0x0304,
 	TSR	= 0x0308,
+	MFA	= 0x030C,
 	TFA0	= 0x0310,
 	TFA1	= 0x0314,
 	TFA2	= 0x0318,
@@ -158,6 +201,8 @@
 	TIS	= 0x037C,
 	ISS	= 0x0380,
 	CIE	= 0x0384,	/* R-Car Gen3 only */
+	RIC3	= 0x0388,	/* R-Car Gen3 only */
+	RIS3	= 0x038C,	/* R-Car Gen3 only */
 	GCCR	= 0x0390,
 	GMTT	= 0x0394,
 	GPTC	= 0x0398,
@@ -171,15 +216,46 @@
 	GCT0	= 0x03B8,
 	GCT1	= 0x03BC,
 	GCT2	= 0x03C0,
+	GSR	= 0x03C4,	/* R-Car Gen3 only */
 	GIE	= 0x03CC,	/* R-Car Gen3 only */
 	GID	= 0x03D0,	/* R-Car Gen3 only */
+	GIL	= 0x03D4,	/* R-Car Gen3 only */
+	GACP	= 0x03DC,	/* R-Car Gen3 only */
+	GPTF0	= 0x03E0,	/* R-Car Gen3 only */
+	GPTF1	= 0x03E4,	/* R-Car Gen3 only */
+	GPTF2	= 0x03E8,	/* R-Car Gen3 only */
+	GPTF3	= 0x03EC,	/* R-Car Gen3 only */
+	GCAT0	= 0x0400,	/* R-Car Gen3 only */
+	GCAT1	= 0x0404,	/* R-Car Gen3 only */
+	GCAT2	= 0x0408,	/* R-Car Gen3 only */
+	GCAT3	= 0x040C,	/* R-Car Gen3 only */
+	GCAT4	= 0x0410,	/* R-Car Gen3 only */
+	GCAT5	= 0x0414,	/* R-Car Gen3 only */
+	GCAT6	= 0x0418,	/* R-Car Gen3 only */
+	GCAT7	= 0x041C,	/* R-Car Gen3 only */
+	GCAT8	= 0x0420,	/* R-Car Gen3 only */
+	GCAT9	= 0x0424,	/* R-Car Gen3 only */
+	GCAT10	= 0x0428,	/* R-Car Gen3 only */
+	GCAT11	= 0x042C,	/* R-Car Gen3 only */
+	GCAT12	= 0x0430,	/* R-Car Gen3 only */
+	GCAT13	= 0x0434,	/* R-Car Gen3 only */
+	GCAT14	= 0x0438,	/* R-Car Gen3 only */
+	GCAT15	= 0x043C,	/* R-Car Gen3 only */
 	DIL	= 0x0440,	/* R-Car Gen3 only */
+	EIL	= 0x0444,	/* R-Car Gen3 only */
+	TIL	= 0x0448,	/* R-Car Gen3 only */
+	DIE	= 0x0450,	/* R-Car Gen3 only */
+	DID	= 0x0454,	/* R-Car Gen3 only */
+	EIE	= 0x0458,	/* R-Car Gen3 only */
+	EID	= 0x045C,	/* R-Car Gen3 only */
 	RIE0	= 0x0460,	/* R-Car Gen3 only */
 	RID0	= 0x0464,	/* R-Car Gen3 only */
 	RIE2	= 0x0470,	/* R-Car Gen3 only */
 	RID2	= 0x0474,	/* R-Car Gen3 only */
 	TIE	= 0x0478,	/* R-Car Gen3 only */
 	TID	= 0x047c,	/* R-Car Gen3 only */
+	RIE3	= 0x0488,	/* R-Car Gen3 only */
+	RID3	= 0x048C,	/* R-Car Gen3 only */
 
 	/* E-MAC registers */
 	ECMR	= 0x0500,
@@ -189,9 +265,12 @@
 	PIR	= 0x0520,
 	PSR	= 0x0528,
 	PIPR	= 0x052c,
+	APR	= 0x0554,	/* R-Car Gen3 only */
 	MPR	= 0x0558,
 	PFTCR	= 0x055c,
 	PFRCR	= 0x0560,
+	PFTTLR	= 0x0564,	/* R-Car Gen3 only */
+	PFTTCR	= 0x0568,	/* R-Car Gen3 only */
 	GECMR	= 0x05b0,
 	MAHR	= 0x05c0,
 	MALR	= 0x05c8,
@@ -248,6 +327,15 @@
 	ESR_EIL		= 0x00001000,
 };
 
+/* APSR */
+enum APSR_BIT {
+	APSR_MEMS		= 0x00000002,
+	APSR_CMSW		= 0x00000010,
+	APSR_DM			= 0x0000A000,
+	APSR_DM_RDM		= 0x00004000,
+	APSR_DM_TDM		= 0x00006000,
+};
+
 /* RCR */
 enum RCR_BIT {
 	RCR_EFFS	= 0x00000001,
@@ -319,6 +407,14 @@
 	RTC_MFL1	= 0x0FFF0000,
 };
 
+/* SFL */
+enum SFL_BIT {
+	SFL_LC		= 0x0000001F,
+	SFL_LC_SFM	= 0x0000001D,
+	SFL_LC_SFO	= 0x0000001E,
+	SFL_LC_LOADABLE	= 0x0000001F,
+};
+
 /* TGC */
 enum TGC_BIT {
 	TGC_TSM0	= 0x00000001,
@@ -947,7 +1043,6 @@
 #define RX_QUEUE_OFFSET	4
 #define NUM_RX_QUEUE	2
 #define NUM_TX_QUEUE	2
-#define NUM_TX_DESC	2	/* TX descriptors per packet */
 
 struct ravb_tstamp_skb {
 	struct list_head list;
@@ -1024,6 +1119,7 @@
 
 	unsigned no_avb_link:1;
 	unsigned avb_link_active_low:1;
+	int num_tx_desc;	/* TX descriptors per packet */
 };
 
 static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 15fd342..d25e6b8 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -31,6 +31,9 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/soc/renesas/rcar_prr.h>
 
 #include <asm/div64.h>
 
@@ -185,6 +188,7 @@
 	struct ravb_private *priv = netdev_priv(ndev);
 	int ring_size;
 	int i;
+	int num_tx_desc = priv->num_tx_desc;
 
 	/* Free RX skb ringbuffer */
 	if (priv->rx_skb[q]) {
@@ -216,7 +220,7 @@
 
 	if (priv->tx_ring[q]) {
 		ring_size = sizeof(struct ravb_tx_desc) *
-			    (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+			    (priv->num_tx_ring[q] * num_tx_desc + 1);
 		dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q],
 				  priv->tx_desc_dma[q]);
 		priv->tx_ring[q] = NULL;
@@ -230,9 +234,10 @@
 	struct ravb_ex_rx_desc *rx_desc;
 	struct ravb_tx_desc *tx_desc;
 	struct ravb_desc *desc;
+	int num_tx_desc = priv->num_tx_desc;
 	int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
 	int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] *
-			   NUM_TX_DESC;
+			   num_tx_desc;
 	dma_addr_t dma_addr;
 	int i;
 
@@ -267,8 +272,10 @@
 	for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q];
 	     i++, tx_desc++) {
 		tx_desc->die_dt = DT_EEMPTY;
-		tx_desc++;
-		tx_desc->die_dt = DT_EEMPTY;
+		if (num_tx_desc >= 2) {
+			tx_desc++;
+			tx_desc->die_dt = DT_EEMPTY;
+		}
 	}
 	tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
 	tx_desc->die_dt = DT_LINKFIX; /* type */
@@ -291,6 +298,7 @@
 	struct sk_buff *skb;
 	int ring_size;
 	int i;
+	int num_tx_desc = priv->num_tx_desc;
 
 	/* Allocate RX and TX skb rings */
 	priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
@@ -326,7 +334,7 @@
 
 	/* Allocate all TX descriptors. */
 	ring_size = sizeof(struct ravb_tx_desc) *
-		    (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+		    (priv->num_tx_ring[q] * num_tx_desc + 1);
 	priv->tx_ring[q] = dma_alloc_coherent(ndev->dev.parent, ring_size,
 					      &priv->tx_desc_dma[q],
 					      GFP_KERNEL);
@@ -362,8 +370,6 @@
 	ravb_write(ndev,
 		   (ndev->dev_addr[4] << 8)  | (ndev->dev_addr[5]), MALR);
 
-	ravb_write(ndev, 1, MPR);
-
 	/* E-MAC status register clear */
 	ravb_write(ndev, ECSR_ICD | ECSR_MPD, ECSR);
 
@@ -402,7 +408,8 @@
 #endif
 
 	/* Set AVB RX */
-	ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
+	ravb_write(ndev,
+		   RCR_EFFS | RCR_ENCF | RCR_ETS0 | RCR_ESF | 0x18000000, RCR);
 
 	/* Set FIFO size */
 	ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
@@ -441,10 +448,11 @@
 	int free_num = 0;
 	int entry;
 	u32 size;
+	int num_tx_desc = priv->num_tx_desc;
 
 	for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
 		entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
-					     NUM_TX_DESC);
+					     num_tx_desc);
 		desc = &priv->tx_ring[q][entry];
 		if (desc->die_dt != DT_FEMPTY)
 			break;
@@ -452,12 +460,12 @@
 		dma_rmb();
 		size = le16_to_cpu(desc->ds_tagl) & TX_DS;
 		/* Free the original skb. */
-		if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
+		if (priv->tx_skb[q][entry / num_tx_desc]) {
 			dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
 					 size, DMA_TO_DEVICE);
 			/* Last packet descriptor? */
-			if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
-				entry /= NUM_TX_DESC;
+			if (entry % num_tx_desc == num_tx_desc - 1) {
+				entry /= num_tx_desc;
 				dev_kfree_skb_any(priv->tx_skb[q][entry]);
 				priv->tx_skb[q][entry] = NULL;
 				stats->tx_packets++;
@@ -1015,16 +1023,40 @@
 	 * at this time.
 	 */
 	if (priv->chip_id == RCAR_GEN3) {
-		int err;
+		struct platform_device *pdev = priv->pdev;
+		struct device *dev = &pdev->dev;
+		enum of_gpio_flags flags;
+		int err, gpio;
 
-		err = phy_set_max_speed(phydev, SPEED_100);
-		if (err) {
-			netdev_err(ndev, "failed to limit PHY to 100Mbit/s\n");
-			phy_disconnect(phydev);
+		err = RCAR_PRR_INIT();
+		if (err)
 			return err;
+
+		if (RCAR_PRR_IS_PRODUCT(H3) &&
+		    (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+			err = phy_set_max_speed(phydev, SPEED_100);
+			if (err) {
+				netdev_err(ndev, "failed to limit PHY to 100Mbit/s\n");
+				phy_disconnect(phydev);
+				return err;
+			}
+			netdev_info(ndev, "limited PHY to 100Mbit/s\n");
 		}
 
-		netdev_info(ndev, "limited PHY to 100Mbit/s\n");
+		gpio = of_get_named_gpio_flags(np, "phy-int-gpio", 0, &flags);
+		if (gpio_is_valid(gpio)) {
+			err = devm_gpio_request_one(dev, gpio, GPIOF_DIR_IN,
+						    "phy-int-gpio");
+			if (err == 0 && (phydev->irq == gpio_to_irq(gpio))) {
+				if (flags & OF_GPIO_ACTIVE_LOW)
+					irq_set_irq_type(phydev->irq,
+							 IRQ_TYPE_LEVEL_LOW);
+				else
+					irq_set_irq_type(phydev->irq,
+							 IRQ_TYPE_LEVEL_HIGH);
+			}
+		}
+
 	}
 
 	/* 10BASE is not supported */
@@ -1484,41 +1516,56 @@
 	void *buffer;
 	u32 entry;
 	u32 len;
+	int num_tx_desc = priv->num_tx_desc;
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) *
-	    NUM_TX_DESC) {
+	    num_tx_desc) {
 		netif_err(priv, tx_queued, ndev,
 			  "still transmitting with the full ring!\n");
 		netif_stop_subqueue(ndev, q);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return NETDEV_TX_BUSY;
 	}
-	entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC);
-	priv->tx_skb[q][entry / NUM_TX_DESC] = skb;
+	entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * num_tx_desc);
+	priv->tx_skb[q][entry / num_tx_desc] = skb;
 
 	if (skb_put_padto(skb, ETH_ZLEN))
 		goto drop;
 
-	buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
-		 entry / NUM_TX_DESC * DPTR_ALIGN;
-	len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
-	memcpy(buffer, skb->data, len);
-	dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(ndev->dev.parent, dma_addr))
-		goto drop;
+	if (num_tx_desc >= 2) {
+		buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
+			 entry / num_tx_desc * DPTR_ALIGN;
+		len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
+		/* quick fix */
+		if (len == 0)
+			len = 4;
+		memcpy(buffer, skb->data, len);
+		dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto drop;
 
-	desc = &priv->tx_ring[q][entry];
-	desc->ds_tagl = cpu_to_le16(len);
-	desc->dptr = cpu_to_le32(dma_addr);
+		desc = &priv->tx_ring[q][entry];
+		desc->ds_tagl = cpu_to_le16(len);
+		desc->dptr = cpu_to_le32(dma_addr);
 
-	buffer = skb->data + len;
-	len = skb->len - len;
-	dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(ndev->dev.parent, dma_addr))
-		goto unmap;
+		buffer = skb->data + len;
+		len = skb->len - len;
+		dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto unmap;
 
-	desc++;
+		desc++;
+	} else {
+		desc = &priv->tx_ring[q][entry];
+		len = skb->len;
+		dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len,
+					  DMA_TO_DEVICE);
+		if (dma_mapping_error(ndev->dev.parent, dma_addr))
+			goto drop;
+	}
 	desc->ds_tagl = cpu_to_le16(len);
 	desc->dptr = cpu_to_le32(dma_addr);
 
@@ -1526,9 +1573,11 @@
 	if (q == RAVB_NC) {
 		ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC);
 		if (!ts_skb) {
-			desc--;
-			dma_unmap_single(ndev->dev.parent, dma_addr, len,
-					 DMA_TO_DEVICE);
+			if (num_tx_desc >= 2) {
+				desc--;
+				dma_unmap_single(ndev->dev.parent, dma_addr,
+						 len, DMA_TO_DEVICE);
+			}
 			goto unmap;
 		}
 		ts_skb->skb = skb;
@@ -1545,15 +1594,19 @@
 	skb_tx_timestamp(skb);
 	/* Descriptor type must be set after all the above writes */
 	dma_wmb();
-	desc->die_dt = DT_FEND;
-	desc--;
-	desc->die_dt = DT_FSTART;
+	if (num_tx_desc >= 2) {
+		desc->die_dt = DT_FEND;
+		desc--;
+		desc->die_dt = DT_FSTART;
+	} else {
+		desc->die_dt = DT_FSINGLE;
+	}
 
 	ravb_modify(ndev, TCCR, TCCR_TSRQ0 << q, TCCR_TSRQ0 << q);
 
-	priv->cur_tx[q] += NUM_TX_DESC;
+	priv->cur_tx[q] += num_tx_desc;
 	if (priv->cur_tx[q] - priv->dirty_tx[q] >
-	    (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q))
+	    (priv->num_tx_ring[q] - 1) * num_tx_desc && !ravb_tx_free(ndev, q))
 		netif_stop_subqueue(ndev, q);
 
 exit:
@@ -1566,7 +1619,7 @@
 			 le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE);
 drop:
 	dev_kfree_skb_any(skb);
-	priv->tx_skb[q][entry / NUM_TX_DESC] = NULL;
+	priv->tx_skb[q][entry / num_tx_desc] = NULL;
 	goto exit;
 }
 
@@ -1667,8 +1720,13 @@
 		priv->phydev = NULL;
 	}
 
-	if (priv->chip_id == RCAR_GEN3)
+	if (priv->chip_id != RCAR_GEN2) {
+		free_irq(priv->tx_irqs[RAVB_NC], ndev);
+		free_irq(priv->rx_irqs[RAVB_NC], ndev);
+		free_irq(priv->tx_irqs[RAVB_BE], ndev);
+		free_irq(priv->rx_irqs[RAVB_BE], ndev);
 		free_irq(priv->emac_irq, ndev);
+	}
 	free_irq(ndev->irq, ndev);
 
 	napi_disable(&priv->napi[RAVB_NC]);
@@ -1831,6 +1889,7 @@
 	{ .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,etheravb-rcar-gen2", .data = (void *)RCAR_GEN2 },
 	{ .compatible = "renesas,etheravb-r8a7795", .data = (void *)RCAR_GEN3 },
+	{ .compatible = "renesas,etheravb-r8a7796", .data = (void *)RCAR_GEN3 },
 	{ .compatible = "renesas,etheravb-rcar-gen3", .data = (void *)RCAR_GEN3 },
 	{ }
 };
@@ -1969,6 +2028,11 @@
 
 	priv->chip_id = chip_id;
 
+	if (chip_id == RCAR_GEN2)
+		priv->num_tx_desc = 2;
+	else
+		priv->num_tx_desc = 1;
+
 	/* Set function */
 	ndev->netdev_ops = &ravb_netdev_ops;
 	ndev->ethtool_ops = &ravb_ethtool_ops;
@@ -1991,6 +2055,10 @@
 	/* Request GTI loading */
 	ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI);
 
+	/* Set APSR */
+	if (priv->phy_interface == PHY_INTERFACE_MODE_RGMII_ID)
+		ravb_modify(ndev, APSR, APSR_DM, APSR_DM_TDM);
+
 	/* Allocate descriptor base address table */
 	priv->desc_bat_size = sizeof(struct ravb_desc) * DBAT_ENTRY_NUM;
 	priv->desc_bat = dma_alloc_coherent(ndev->dev.parent, priv->desc_bat_size,
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 3929d93..8c0f882 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -28,6 +28,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/soc/renesas/s2ram_ddr_backup.h>
 
 #define DRV_NAME "rcar-pcie"
 
@@ -43,6 +44,7 @@
 
 /* Transfer control */
 #define PCIETCTLR		0x02000
+#define  DL_DOWN		(1 << 3)
 #define  CFINIT			1
 #define PCIETSTR		0x02004
 #define  DATA_LINK_ACTIVE	1
@@ -84,6 +86,14 @@
 #define MACSR			0x011054
 #define MACCTLR			0x011058
 #define  SCRAMBLE_DISABLE	(1 << 27)
+#define PMSR			0x01105c
+#define  L1FAEG			(1 << 31)
+#define  PM_ENTER_L1RX		(1 << 23)
+#define  PMSTATE		(7 << 16)
+#define  PMSTATE_L1		(3 << 16)
+#define PMCTLR			0x011060
+#define  L1_INIT		(1 << 31)
+
 
 /* R-Car H1 PHY */
 #define H1_PCIEPHYADRR		0x04000c
@@ -129,6 +139,7 @@
 	return container_of(chip, struct rcar_msi, chip);
 }
 
+
 /* Structure representing the PCIe interface */
 struct rcar_pcie {
 	struct device		*dev;
@@ -140,6 +151,147 @@
 	struct			rcar_msi msi;
 };
 
+static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie);
+
+#ifdef CONFIG_RCAR_DDR_BACKUP
+
+#define PCIE_BACKUP_REGS(pcie_ip_regs)	\
+struct hw_register (pcie_ip_regs)[] = {	\
+/* PCIEC transfer control registers */	\
+	{"PCIETCTLR",	0x2000,	32, 0}, \
+	{"PCIEINTER",	0x200C,	32, 0},	\
+	{"PCIEERRFER",	0x2024,	32, 0},	\
+	{"PCIETIER",	0x2030,	32, 0},	\
+	{"PCIEPMSCIER",	0x2038,	32, 0}, \
+	{"PCIEMSIALR",	0x2048,	32, 0},	\
+	{"PCIEMSIAUR",	0x204C,	32, 0},	\
+	{"PCIEMSIIER",	0x2050,	32, 0},	\
+	{"PCIEPRAR0",	0x2080,	32, 0},	\
+	{"PCIEPRAR1",	0x2084,	32, 0},	\
+	{"PCIEPRAR2",	0x2088,	32, 0},	\
+	{"PCIEPRAR3",	0x208C,	32, 0},	\
+	{"PCIEPRAR4",	0x2090,	32, 0},	\
+	{"PCIEPRAR5",	0x2094,	32, 0},	\
+	\
+	/* Local address registers */	\
+	{"PCIELAR0",	0x2200,	32, 0},	\
+	{"PCIELAMR0",	0x2208,	32, 0},	\
+	{"PCIELAR1",	0x2220,	32, 0},	\
+	{"PCIELAMR1",	0x2228,	32, 0},	\
+	{"PCIELAR2",	0x2240,	32, 0},	\
+	{"PCIELAMR2",	0x2248,	32, 0},	\
+	{"PCIELAR3",	0x2260,	32, 0},	\
+	{"PCIELAMR3",	0x2268,	32, 0},	\
+	{"PCIELAR4",	0x2280,	32, 0},	\
+	{"PCIELAMR4",	0x2288,	32, 0},	\
+	{"PCIELAR5",	0x22A0,	32, 0},	\
+	{"PCIELAMR5",	0x22A8,	32, 0},	\
+	\
+	/* PCIEC address registers */	\
+	{"PCIEPALR0",	0x3400,	32, 0},	\
+	{"PCIEPAUR0",	0x3404,	32, 0},	\
+	{"PCIEPAMR0",	0x3408,	32, 0},	\
+	{"PCIEPTCTLR0",	0x340C,	32, 0},	\
+	{"PCIEPALR1",	0x3420,	32, 0},	\
+	{"PCIEPAUR1",	0x3424,	32, 0},	\
+	{"PCIEPAMR1",	0x3428,	32, 0},	\
+	{"PCIEPTCTLR1",	0x342C,	32, 0},	\
+	{"PCIEPALR2",	0x3440,	32, 0},	\
+	{"PCIEPAUR2",	0x3444,	32, 0},	\
+	{"PCIEPAMR2",	0x3448,	32, 0},	\
+	{"PCIEPTCTLR2",	0x344C,	32, 0},	\
+	{"PCIEPALR3",	0x3460,	32, 0},	\
+	{"PCIEPAUR3",	0x3464,	32, 0},	\
+	{"PCIEPAMR3",	0x3468,	32, 0},	\
+	{"PCIEPTCTLR3",	0x346C,	32, 0},	\
+}
+
+static PCIE_BACKUP_REGS(pcie0_ip_regs);
+static PCIE_BACKUP_REGS(pcie1_ip_regs);
+
+static struct rcar_ip pcie0_ip = {
+	.ip_name = "pcie0",
+	.base_addr = 0xFE000000,
+	.size = 0x3470,
+	.reg_count = ARRAY_SIZE(pcie0_ip_regs),
+	.ip_reg = pcie0_ip_regs,
+};
+
+static struct rcar_ip pcie1_ip = {
+	.ip_name = "pcie1",
+	.base_addr = 0xEE800000,
+	.size = 0x3470,
+	.reg_count = ARRAY_SIZE(pcie1_ip_regs),
+	.ip_reg = pcie1_ip_regs,
+};
+
+struct ip_info {
+	const char *name;
+	struct rcar_ip *ip;
+};
+
+static struct ip_info ip_info_tbl[] = {
+	{"fe000000.pcie", &pcie0_ip },
+	{"ee800000.pcie", &pcie1_ip },
+	{NULL, NULL},
+};
+
+static struct rcar_ip *get_ip(const char *name)
+{
+	struct ip_info *ip_info = ip_info_tbl;
+	struct rcar_ip *ip = NULL;
+
+	while (ip_info->name) {
+		if (!strcmp(ip_info->name, name)) {
+			ip = ip_info->ip;
+			break;
+		}
+		ip_info++;
+	}
+
+	return ip;
+}
+
+static int rcar_pcie_save_regs(struct device *dev)
+{
+	struct rcar_ip *ip = get_ip(dev_name(dev));
+	int ret;
+
+	if (ip) {
+		if (!ip->virt_addr)
+			handle_registers(ip, DO_IOREMAP);
+
+		ret = handle_registers(ip, DO_BACKUP);
+		if (ret)
+			pr_err("%s: %s: BACKUP failed, ret=%d\n",
+				__func__, dev_name(dev), ret);
+	} else
+		pr_err("%s: Failed to find backup of dev: %s\n\n",
+				__func__, dev_name(dev));
+
+	return 0;
+}
+
+static int rcar_pcie_restore_regs(struct device *dev)
+{
+	struct rcar_ip *ip = get_ip(dev_name(dev));
+	int ret = -ENODEV;
+
+	if (ip) {
+		ret = handle_registers(ip, DO_RESTORE);
+		if (ret)
+			pr_err("%s: %s: RESTORE failed, ret=%d\n",
+				__func__, dev_name(dev), ret);
+
+	} else
+		pr_err("%s: Failed to find backup of dev: %s\n\n",
+				__func__, dev_name(dev));
+
+	return 0;
+}
+
+#endif /* CONFIG_RCAR_DDR_BACKUP */
+
 static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
 			       unsigned long reg)
 {
@@ -181,6 +333,7 @@
 		unsigned int devfn, int where, u32 *data)
 {
 	int dev, func, reg, index;
+	u32 val;
 
 	dev = PCI_SLOT(devfn);
 	func = PCI_FUNC(devfn);
@@ -222,6 +375,29 @@
 	if (pcie->root_bus_nr < 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
+	/*
+	 * If we are not in L1 link state and we have received PM_ENTER_L1 DLLP,
+	 * transition to L1 link state. The HW will handle coming of of L1.
+	 */
+	val = rcar_pci_read_reg(pcie, PMSR);
+
+	if ((val == 0) || (rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN)) {
+		/* Wait PCI Express link is re-initialized */
+		rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
+		rcar_pcie_wait_for_dl(pcie);
+	}
+
+	if ((val & PM_ENTER_L1RX) && ((val & PMSTATE) != PMSTATE_L1)) {
+		rcar_pci_write_reg(pcie, L1_INIT, PMCTLR);
+
+		/* Wait until we are in L1 */
+		while (!(val & L1FAEG))
+			val = rcar_pci_read_reg(pcie, PMSR);
+
+		/* Clear flags indicating link has transitioned to L1 */
+		rcar_pci_write_reg(pcie, L1FAEG | PM_ENTER_L1RX, PMSR);
+	}
+
 	/* Clear errors */
 	rcar_pci_write_reg(pcie, rcar_pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
 
@@ -404,7 +580,7 @@
 		return -ENODEV;
 	}
 
-	pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+	pci_fixup_irqs_local(bus, pci_common_swizzle, of_irq_parse_and_map_pci);
 
 	pci_bus_size_bridges(bus);
 	pci_bus_assign_resources(bus);
@@ -467,7 +643,7 @@
 		if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
 			return 0;
 
-		msleep(5);
+		mdelay(5);
 	}
 
 	return -ETIMEDOUT;
@@ -773,15 +949,6 @@
 	if (err)
 		return err;
 
-	pcie->clk = devm_clk_get(&pdev->dev, "pcie");
-	if (IS_ERR(pcie->clk)) {
-		dev_err(pcie->dev, "cannot get platform clock\n");
-		return PTR_ERR(pcie->clk);
-	}
-	err = clk_prepare_enable(pcie->clk);
-	if (err)
-		goto fail_clk;
-
 	pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
 	if (IS_ERR(pcie->bus_clk)) {
 		dev_err(pcie->dev, "cannot get pcie bus clock\n");
@@ -819,7 +986,6 @@
 err_map_reg:
 	clk_disable_unprepare(pcie->bus_clk);
 fail_clk:
-	clk_disable_unprepare(pcie->clk);
 
 	return err;
 }
@@ -934,6 +1100,7 @@
 	{ .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init_gen2 },
 	{ .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init_gen2 },
 	{ .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init },
+	{ .compatible = "renesas,pcie-r8a7796", .data = rcar_pcie_hw_init },
 	{},
 };
 MODULE_DEVICE_TABLE(of, rcar_pcie_of_match);
@@ -1008,6 +1175,13 @@
 
 	rcar_pcie_parse_request_of_pci_ranges(pcie);
 
+	pm_runtime_enable(pcie->dev);
+	err = pm_runtime_get_sync(pcie->dev);
+	if (err < 0) {
+		dev_err(pcie->dev, "pm_runtime_get_sync failed\n");
+		goto err_pm_disable;
+	}
+
 	err = rcar_pcie_get_resources(pdev, pcie);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to request resources: %d\n", err);
@@ -1023,18 +1197,11 @@
 		return -EINVAL;
 	hw_init_fn = of_id->data;
 
-	pm_runtime_enable(pcie->dev);
-	err = pm_runtime_get_sync(pcie->dev);
-	if (err < 0) {
-		dev_err(pcie->dev, "pm_runtime_get_sync failed\n");
-		goto err_pm_disable;
-	}
-
 	/* Failure to get a link might just be that no cards are inserted */
 	err = hw_init_fn(pcie);
 	if (err) {
 		dev_info(&pdev->dev, "PCIe link down\n");
-		err = 0;
+		err = -ENODEV;
 		goto err_pm_put;
 	}
 
@@ -1068,22 +1235,39 @@
 #ifdef CONFIG_PM_SLEEP
 static int rcar_pcie_suspend(struct device *dev)
 {
-	/* Empty functino for now */
-	return 0;
+	int ret = 0;
+#ifdef CONFIG_RCAR_DDR_BACKUP
+	ret = rcar_pcie_save_regs(dev);
+#endif /* CONFIG_RCAR_DDR_BACKUP */
+
+	return ret;
 }
 
 static int rcar_pcie_resume(struct device *dev)
 {
-	/* Empty function for now */
+	struct rcar_pcie *pcie = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (pcie) {
+#ifdef CONFIG_RCAR_DDR_BACKUP
+		rcar_pcie_restore_regs(dev);
+#endif /* CONFIG_RCAR_DDR_BACKUP */
+		ret = rcar_pcie_hw_init(pcie);
+		if (ret)
+			pr_debug("%s: %s: re-init hw fail, ret=%d\n",
+			__func__, dev_name(dev), ret);
+	} else
+		pr_warn("%s: %s: pcie NULL\n", __func__, dev_name(dev));
+
 	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(rcar_pcie_pm_ops,
-			rcar_pcie_suspend,
-			rcar_pcie_resume);
-
+static const struct dev_pm_ops rcar_pcie_pm_ops = {
+	.suspend	= rcar_pcie_suspend,
+	.resume		= rcar_pcie_resume,
+};
 #define DEV_PM_OPS (&rcar_pcie_pm_ops)
-#else
+#else /* CONFIG_PM_SLEEP */
 #define DEV_PM_OPS NULL
 #endif /* CONFIG_PM_SLEEP */
 
@@ -1098,6 +1282,34 @@
 };
 module_platform_driver(rcar_pcie_driver);
 
+static int rcar_pcie_pci_notifier(struct notifier_block *nb,
+			    unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	switch (action) {
+	case BUS_NOTIFY_BOUND_DRIVER:
+		/* Force the DMA mask to lower 32-bits */
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block device_nb = {
+	.notifier_call = rcar_pcie_pci_notifier,
+};
+
+static int __init register_rcar_pcie_pci_notifier(void)
+{
+	return bus_register_notifier(&pci_bus_type, &device_nb);
+}
+
+arch_initcall(register_rcar_pcie_pci_notifier);
+
 MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
 MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 95c225b..90ea8fa 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -22,7 +22,8 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-static void pdev_fixup_irq(struct pci_dev *dev,
+static void pdev_fixup_irq(int domain_nr,
+			   struct pci_dev *dev,
 			   u8 (*swizzle)(struct pci_dev *, u8 *),
 			   int (*map_irq)(const struct pci_dev *, u8, u8))
 {
@@ -48,8 +49,15 @@
 		if (irq == -1)
 			irq = 0;
 	}
-	dev->irq = irq;
+	/* Since pci_fixup_irqs() can be called more than once due to multiple
+	 * host controllers, and we scan all PCI devices, not just those
+	 * attached to this controller, make sure we don't clobber dev->irq
+	 * that has nothing to do with this domain.
+	 */
+	if (domain_nr >= 0 && dev->bus->domain_nr != domain_nr)
+		return;
 
+	dev->irq = irq;
 	dev_dbg(&dev->dev, "fixup irq: got %d\n", dev->irq);
 
 	/* Always tell the device, so the driver knows what is
@@ -63,6 +71,17 @@
 	struct pci_dev *dev = NULL;
 
 	for_each_pci_dev(dev)
-		pdev_fixup_irq(dev, swizzle, map_irq);
+		pdev_fixup_irq(-1, dev, swizzle, map_irq);
 }
 EXPORT_SYMBOL_GPL(pci_fixup_irqs);
+
+void pci_fixup_irqs_local(struct pci_bus *bus,
+		    u8 (*swizzle)(struct pci_dev *, u8 *),
+		    int (*map_irq)(const struct pci_dev *, u8, u8))
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev)
+		pdev_fixup_irq(bus->domain_nr, dev, swizzle, map_irq);
+}
+EXPORT_SYMBOL_GPL(pci_fixup_irqs_local);
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index 6fd0cc0..1925f37 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -22,6 +22,9 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy_companion.h>
 
 /******* USB2.0 Host registers (original offset is +0x200) *******/
 #define USB2_INT_ENABLE		0x000
@@ -70,6 +73,7 @@
 #define USB2_LINECTRL1_DP_RPD		BIT(18)
 #define USB2_LINECTRL1_DMRPD_EN		BIT(17)
 #define USB2_LINECTRL1_DM_RPD		BIT(16)
+#define USB2_LINECTRL1_OPMODE_NODRV	BIT(6)
 
 /* ADPCTRL */
 #define USB2_ADPCTRL_OTGSESSVLD		BIT(20)
@@ -82,6 +86,7 @@
 	struct extcon_dev *extcon;
 	struct phy *phy;
 	struct regulator *vbus;
+	struct usb_phy usb_phy;
 	bool has_otg;
 };
 
@@ -125,6 +130,12 @@
 	writel(val, usb2_base + USB2_ADPCTRL);
 }
 
+static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
+{
+	return !!(readl(ch->base + USB2_ADPCTRL) &
+		  USB2_ADPCTRL_OTGSESSVLD);
+}
+
 static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
 {
 	rcar_gen3_set_linectrl(ch, 1, 1);
@@ -133,6 +144,9 @@
 
 	extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
 	extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
+
+	if (ch->has_otg && ch->usb_phy.otg)
+		ch->usb_phy.otg->state = OTG_STATE_A_HOST;
 }
 
 static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
@@ -141,14 +155,65 @@
 	rcar_gen3_set_host_mode(ch, 0);
 	rcar_gen3_enable_vbus_ctrl(ch, 0);
 
+	if (ch->has_otg && ch->usb_phy.otg->gadget) {
+		if (rcar_gen3_check_vbus(ch))
+			usb_gadget_vbus_connect(ch->usb_phy.otg->gadget);
+		else
+			usb_gadget_vbus_disconnect(ch->usb_phy.otg->gadget);
+		ch->usb_phy.otg->state = OTG_STATE_B_PERIPHERAL;
+	}
+
 	extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
 	extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
 }
 
-static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
+static void rcar_gen3_init_for_b_host(struct rcar_gen3_chan *ch)
 {
-	return !!(readl(ch->base + USB2_ADPCTRL) &
-		  USB2_ADPCTRL_OTGSESSVLD);
+	void __iomem *usb2_base = ch->base;
+	u32 val;
+
+	val = readl(usb2_base + USB2_LINECTRL1);
+	writel(val | USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
+
+	if (ch->has_otg && ch->usb_phy.otg->gadget)
+		usb_gadget_vbus_disconnect(ch->usb_phy.otg->gadget);
+
+	rcar_gen3_set_linectrl(ch, 1, 1);
+	rcar_gen3_set_host_mode(ch, 1);
+	rcar_gen3_enable_vbus_ctrl(ch, 0);
+
+	val = readl(usb2_base + USB2_LINECTRL1);
+	writel(val & ~USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1);
+
+	if (ch->has_otg && ch->usb_phy.otg)
+		ch->usb_phy.otg->state = OTG_STATE_B_HOST;
+}
+
+static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch)
+{
+	rcar_gen3_set_linectrl(ch, 0, 1);
+	rcar_gen3_set_host_mode(ch, 0);
+	rcar_gen3_enable_vbus_ctrl(ch, 1);
+
+	if (ch->has_otg && ch->usb_phy.otg->gadget) {
+		usb_gadget_vbus_connect(ch->usb_phy.otg->gadget);
+		ch->usb_phy.otg->state = OTG_STATE_A_PERIPHERAL;
+	}
+}
+
+static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
+{
+	void __iomem *usb2_base = ch->base;
+	u32 val;
+
+	val = readl(usb2_base + USB2_OBINTEN);
+	writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
+
+	rcar_gen3_enable_vbus_ctrl(ch, 0);
+	msleep(1000);
+	rcar_gen3_init_for_host(ch);
+
+	writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
 }
 
 static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
@@ -156,20 +221,81 @@
 	return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
 }
 
+static int rcar_gen3_phy_usb2_set_host(struct usb_otg *otg,
+				       struct usb_bus *host)
+{
+	if (!otg)
+		return -ENODEV;
+
+	otg->host = host;
+	if (!host)
+		otg->state = OTG_STATE_UNDEFINED;
+
+	return 0;
+}
+
+static int rcar_gen3_phy_usb2_set_peripheral(struct usb_otg *otg,
+					     struct usb_gadget *gadget)
+{
+	if (!otg)
+		return -ENODEV;
+
+	otg->gadget = gadget;
+	if (!gadget)
+		otg->state = OTG_STATE_UNDEFINED;
+
+	return 0;
+}
+
 static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
 {
-	bool is_host = true;
-
-	/* B-device? */
-	if (rcar_gen3_check_id(ch) && rcar_gen3_check_vbus(ch))
-		is_host = false;
-
-	if (is_host)
+	if (!rcar_gen3_check_id(ch))
 		rcar_gen3_init_for_host(ch);
 	else
 		rcar_gen3_init_for_peri(ch);
 }
 
+static ssize_t otg_inputs_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
+	const char *otg_str[] = {
+		"a_bus_req/", "a_bus_drop", "b_bus_req/", "b_bus_req",
+	};
+	bool is_host;
+
+	if (!ch->has_otg)
+		return -EIO;
+
+	is_host = !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI);
+
+	if (!strncmp(buf, otg_str[0], strlen(otg_str[0]))) {
+		/* fail if B-device */
+		if (rcar_gen3_check_id(ch))
+			return -EIO;
+		rcar_gen3_init_for_a_peri(ch);
+	} else if (!strncmp(buf, otg_str[1], strlen(otg_str[1]))) {
+		/* fail if B-device or A-host */
+		if (rcar_gen3_check_id(ch) || is_host)
+			return -EIO;
+		rcar_gen3_init_from_a_peri_to_a_host(ch);
+	} else if (!strncmp(buf, otg_str[2], strlen(otg_str[2]))) {
+		/* fail if A-device or B-peripheral */
+		if (!rcar_gen3_check_id(ch) || !is_host)
+			return -EIO;
+		rcar_gen3_init_for_peri(ch);
+	} else if (!strncmp(buf, otg_str[3], strlen(otg_str[3]))) {
+		/* fail if A-device */
+		if (!rcar_gen3_check_id(ch))
+			return -EIO;
+		rcar_gen3_init_for_b_host(ch);
+	}
+
+	return count;
+}
+static DEVICE_ATTR_WO(otg_inputs);
+
 static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
 {
 	void __iomem *usb2_base = ch->base;
@@ -276,6 +402,7 @@
 
 static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
 	{ .compatible = "renesas,usb2-phy-r8a7795" },
+	{ .compatible = "renesas,usb2-phy-r8a7796" },
 	{ .compatible = "renesas,rcar-gen3-usb2-phy" },
 	{ }
 };
@@ -293,7 +420,7 @@
 	struct rcar_gen3_chan *channel;
 	struct phy_provider *provider;
 	struct resource *res;
-	int irq;
+	int irq, ret;
 
 	if (!dev->of_node) {
 		dev_err(dev, "This driver needs device tree\n");
@@ -313,7 +440,7 @@
 	/* call request_irq for OTG */
 	irq = platform_get_irq(pdev, 0);
 	if (irq >= 0) {
-		int ret;
+		struct usb_otg *otg;
 
 		irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
 				       IRQF_SHARED, dev_name(dev), channel);
@@ -330,6 +457,19 @@
 			dev_err(dev, "Failed to register extcon\n");
 			return ret;
 		}
+
+		otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
+		if (!otg)
+			return -ENOMEM;
+
+		channel->usb_phy.dev = dev;
+		channel->usb_phy.label = "rcar_gen3_usb2_phy";
+		channel->usb_phy.otg = otg;
+		channel->usb_phy.type = USB_PHY_TYPE_USB2;
+		otg->set_host = rcar_gen3_phy_usb2_set_host;
+		otg->set_peripheral = rcar_gen3_phy_usb2_set_peripheral;
+		otg->usb_phy = &channel->usb_phy;
+
 	}
 
 	/* devm_phy_create() will call pm_runtime_enable(dev); */
@@ -350,15 +490,35 @@
 	phy_set_drvdata(channel->phy, channel);
 
 	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-	if (IS_ERR(provider))
+	if (IS_ERR(provider)) {
 		dev_err(dev, "Failed to register PHY provider\n");
+	} else if (channel->has_otg) {
+		ret = usb_add_phy_dev(&channel->usb_phy);
+		if (ret < 0) {
+			dev_err(dev, "Failed to register usb PHY provider\n");
+			return ret;
+		}
+
+		ret = device_create_file(dev, &dev_attr_otg_inputs);
+		if (ret < 0) {
+			usb_remove_phy(&channel->usb_phy);
+			return ret;
+		}
+	}
 
 	return PTR_ERR_OR_ZERO(provider);
 }
 
 static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
 {
+	struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
+
+	if (channel->has_otg) {
+		device_remove_file(&pdev->dev, &dev_attr_otg_inputs);
+		usb_remove_phy(&channel->usb_phy);
+	}
 	pm_runtime_disable(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index c182efc..c84dff4 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -305,7 +305,7 @@
 
 config PWM_RCAR
 	tristate "Renesas R-Car PWM support"
-	depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST
+	depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || ARCH_RENESAS  || COMPILE_TEST
 	depends on HAS_IOMEM
 	help
 	  This driver exposes the PWM Timer controller found in Renesas
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 427142d..0f7b7db 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -457,7 +457,8 @@
 {
 	int err;
 
-	if (!pwm)
+	if (!pwm || !state || !state->period ||
+	    state->duty_cycle > state->period)
 		return -EINVAL;
 
 	if (!memcmp(state, &pwm->state, sizeof(*state)))
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 7ac95b4..3d194df 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -20,6 +20,7 @@
 #include <linux/soc/renesas/s2ram_ddr_backup.h>
 
 #define RCAR_PWM_MAX_DIVISION	24
+#define RCAR_PWM_MIN_CYCLE	2
 #define RCAR_PWM_MAX_CYCLE	1023
 
 #define RCAR_PWMCR		0x00
@@ -204,12 +205,17 @@
 static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
 {
 	unsigned long clk_rate = clk_get_rate(rp->clk);
-	unsigned long long max; /* max cycle / nanoseconds */
+	unsigned long long min, max; /* min, max cycle / nanoseconds */
 	unsigned int div;
 
 	if (clk_rate == 0)
 		return -EINVAL;
 
+	min = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MIN_CYCLE;
+	do_div(min, clk_rate);
+	if (period_ns < min)
+		return -ERANGE;
+
 	for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
 		max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
 			(1 << div);
@@ -286,7 +292,7 @@
 		return div;
 
 	/* Let the core driver set pwm->period if disabled and duty_ns == 0 */
-	if (!pwm_is_enabled(pwm) && !duty_ns)
+	if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
 		return 0;
 
 	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index d985992..01695d4 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -152,7 +152,7 @@
 		goto unlock;
 	}
 
-	pwm_apply_state(pwm, &state);
+	ret = pwm_apply_state(pwm, &state);
 
 unlock:
 	mutex_unlock(&export->lock);
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 5cdea92..f24b8e1 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -9,3 +9,10 @@
 	  This enables DDR backup function for R-Car Gen3.
 	  It supports to backup/restore module register during suspend/resume
 	  sequence respectively when system enters S2RAM.
+
+config RCAR_THERMAL_EMS_ENABLED
+	tristate "Renesas R-Car Gen3 Enable Emergency Shutdown"
+	depends on RCAR_GEN3_THERMAL
+	help
+	  Enable this option if you want to have support for Emergency Shutdown
+	  in R-Car Gen3.
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 4b16dab..a5aa4c5 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -11,3 +11,6 @@
 obj-$(CONFIG_ARCH_R8A7796)	+= rcar-avs.o
 
 obj-$(CONFIG_RCAR_DDR_BACKUP)	+= s2ram_ddr_backup.o
+# EMS for R-Car Gen3
+obj-$(CONFIG_ARCH_R8A7795)	+= rcar_ems_ctrl.o
+obj-$(CONFIG_ARCH_R8A7796)	+= rcar_ems_ctrl.o
diff --git a/drivers/soc/renesas/rcar_ems_ctrl.c b/drivers/soc/renesas/rcar_ems_ctrl.c
new file mode 100644
index 0000000..8295365
--- /dev/null
+++ b/drivers/soc/renesas/rcar_ems_ctrl.c
@@ -0,0 +1,308 @@
+/*
+ *  R-Car Gen3 Emergency shutdown for thermal management
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ */
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+#include <linux/soc/renesas/rcar_ems_ctrl.h>
+
+#define EMS_THERMAL_ZONE_MAX	10
+
+static void rcar_ems_monitor(struct work_struct *ws);
+static DECLARE_DELAYED_WORK(rcar_ems_monitor_work, rcar_ems_monitor);
+
+static RAW_NOTIFIER_HEAD(rcar_ems_chain);
+
+static int ems_mode = RCAR_EMS_MODE_OFF;
+static int ems_mode_on_temp;
+static int ems_mode_off_temp;
+static int ems_poll;
+
+static int thermal_zone_num;
+static struct thermal_zone_device *thermal_zone[EMS_THERMAL_ZONE_MAX];
+
+static int rcar_ems_notify(unsigned long state, void *p)
+{
+	return raw_notifier_call_chain(&rcar_ems_chain, state, p);
+}
+
+int register_rcar_ems_notifier(struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&rcar_ems_chain, nb);
+}
+EXPORT_SYMBOL(register_rcar_ems_notifier);
+
+void unregister_rcar_ems_notifier(struct notifier_block *nb)
+{
+	raw_notifier_chain_unregister(&rcar_ems_chain, nb);
+}
+EXPORT_SYMBOL(unregister_rcar_ems_notifier);
+
+static void rcar_ems_monitor(struct work_struct *ws)
+{
+	int i, ret;
+	int temp, max_temp;
+
+	max_temp = INT_MIN;
+	for (i = 0; i < thermal_zone_num; i++) {
+		if (thermal_zone[i]) {
+			ret = thermal_zone_get_temp(
+					thermal_zone[i], &temp);
+			if (!ret) {
+				if (max_temp < temp)
+					max_temp = temp;
+			}
+		}
+	}
+
+	if (max_temp == INT_MIN)
+		goto skip;
+
+	if (ems_mode == RCAR_EMS_MODE_OFF) {
+		if (max_temp >= ems_mode_on_temp) {
+			ems_mode  = RCAR_EMS_MODE_ON;
+			rcar_ems_notify(RCAR_EMS_MODE_ON,
+					(void *)(long)max_temp);
+		}
+	} else {
+		if (max_temp <= ems_mode_off_temp) {
+			ems_mode = RCAR_EMS_MODE_OFF;
+			rcar_ems_notify(RCAR_EMS_MODE_OFF,
+					(void *)(long)max_temp);
+		}
+	}
+
+skip:
+	schedule_delayed_work(&rcar_ems_monitor_work, ems_poll);
+
+}
+
+
+int rcar_ems_get_mode(void)
+{
+	return ems_mode;
+}
+EXPORT_SYMBOL(rcar_ems_get_mode);
+
+static int __init rcar_ems_ctrl_init(void)
+{
+	struct device_node *np, *c;
+	struct thermal_zone_device *zone;
+	u32 value;
+
+	if (!IS_ENABLED(CONFIG_RCAR_THERMAL_EMS_ENABLED)) {
+		pr_err("thermal emergency: disabled\n");
+		return 0;
+	}
+
+	np = of_find_node_by_name(NULL, "thermal-zones");
+	if (!np)
+		return 0;
+
+	for_each_child_of_node(np, c) {
+		if (!strcmp(c->name, "emergency")) {
+			if (!of_property_read_u32(c,
+				"polling-delay", &value))
+				ems_poll = msecs_to_jiffies(value);
+
+			if (!of_property_read_u32(c,
+				"on-temperature", &value))
+				ems_mode_on_temp = value;
+
+			if (!of_property_read_u32(c,
+				"off-temperature", &value))
+				ems_mode_off_temp = value;
+		} else {
+			zone = thermal_zone_get_zone_by_name(c->name);
+			if (IS_ERR(zone))
+				continue;
+
+			if (thermal_zone_num < EMS_THERMAL_ZONE_MAX) {
+				thermal_zone[thermal_zone_num] = zone;
+				thermal_zone_num++;
+			}
+		}
+	}
+	of_node_put(np);
+
+	if (thermal_zone_num == 0) {
+		pr_err("thermal emergency: not find thermal_zone\n");
+		return 0;
+	}
+
+	if (ems_poll == 0 ||
+	    ems_mode_on_temp == 0 || ems_mode_off_temp == 0) {
+		pr_err("thermal emergency: not set value\n");
+		return 0;
+	}
+
+	schedule_delayed_work(&rcar_ems_monitor_work, ems_poll);
+
+	pr_info("thermal emergency: set temperature to %d celsius\n",
+		ems_mode_on_temp / 1000);
+
+	return 0;
+}
+
+static void __exit rcar_ems_ctrl_exit(void)
+{
+	cancel_delayed_work_sync(&rcar_ems_monitor_work);
+}
+
+late_initcall(rcar_ems_ctrl_init)
+module_exit(rcar_ems_ctrl_exit)
+
+
+/* emergency cpu shutdown function */
+static struct cpumask target_cpus;
+static struct cpumask freq_scaled_cpus;
+
+static int rcar_ems_cpufreq_notifier_call(struct notifier_block *nb,
+	unsigned long event, void *data)
+{
+	struct cpufreq_policy *policy = data;
+	int mode;
+
+	if (!cpumask_test_cpu(policy->cpu, &freq_scaled_cpus))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case CPUFREQ_ADJUST:
+		mode = rcar_ems_get_mode();
+		if (mode == RCAR_EMS_MODE_ON) {
+			cpufreq_verify_within_limits(policy,
+					    policy->cpuinfo.min_freq,
+					    policy->cpuinfo.min_freq);
+		}
+		break;
+
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int rcar_ems_thermal_notifier_call(struct notifier_block *nb,
+	unsigned long state, void *val)
+{
+	long temp = (long)val;
+	int cpu;
+
+	pr_info("thermal emergency notifier: state=%ld (temp=%ld)\n",
+		state, temp);
+
+	switch (state) {
+	case RCAR_EMS_MODE_ON:
+		for_each_cpu(cpu, &target_cpus) {
+			if (cpu_online(cpu))
+				cpu_down(cpu);
+		}
+		break;
+
+	case RCAR_EMS_MODE_OFF:
+		for_each_cpu(cpu, &target_cpus) {
+			if  (!cpu_online(cpu))
+				cpu_up(cpu);
+		}
+		break;
+
+	default:
+		return NOTIFY_DONE;
+	}
+
+	cpufreq_update_policy(cpumask_any(&freq_scaled_cpus));
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ems_thermal_notifier_block = {
+	.notifier_call = rcar_ems_thermal_notifier_call,
+};
+static struct notifier_block ems_cpufreq_notifier_block = {
+	.notifier_call = rcar_ems_cpufreq_notifier_call,
+};
+
+static int __init rcar_ems_cpu_shutdown_init(void)
+{
+	int cpu;
+	struct device_node *cpu_node, *ems_node, *tmp_node;
+	int total_target_cpu, i;
+
+	if (!IS_ENABLED(CONFIG_RCAR_THERMAL_EMS_ENABLED))
+		return 0;
+
+	cpumask_clear(&target_cpus);
+	cpumask_clear(&freq_scaled_cpus);
+
+	ems_node = of_find_node_by_name(NULL, "emergency");
+
+	if (!ems_node)
+		return 0;
+
+	total_target_cpu = of_count_phandle_with_args(ems_node,
+						"target_cpus", 0);
+
+	for_each_online_cpu(cpu) {
+		tmp_node  = of_get_cpu_node(cpu, NULL);
+		if (!of_device_is_compatible(tmp_node, "arm,cortex-a57"))
+			continue;
+		for (i = 0; i < total_target_cpu; i++) {
+			cpu_node = of_parse_phandle(ems_node, "target_cpus", i);
+			if (tmp_node == cpu_node) {
+				cpumask_set_cpu(cpu, &target_cpus);
+				break;
+			}
+		}
+
+		if (i == total_target_cpu)
+			cpumask_set_cpu(cpu, &freq_scaled_cpus);
+	}
+
+	if (cpumask_weight(&target_cpus) == 0) {
+		pr_err("thermal emergency: shutdown cpu none\n");
+		return 0;
+	}
+
+	register_rcar_ems_notifier(&ems_thermal_notifier_block);
+	cpufreq_register_notifier(&ems_cpufreq_notifier_block,
+				  CPUFREQ_POLICY_NOTIFIER);
+
+	pr_info("thermal emergency: shutdown target cpus %*pbl\n",
+		cpumask_pr_args(&target_cpus));
+	pr_info("thermal emergency: freq scaled target cpus %*pbl\n",
+		cpumask_pr_args(&freq_scaled_cpus));
+
+	return 0;
+}
+
+static void __exit rcar_ems_cpu_shutdown_exit(void)
+{
+	unregister_rcar_ems_notifier(&ems_thermal_notifier_block);
+	cpufreq_unregister_notifier(&ems_cpufreq_notifier_block,
+				    CPUFREQ_POLICY_NOTIFIER);
+}
+
+late_initcall(rcar_ems_cpu_shutdown_init);
+module_exit(rcar_ems_cpu_shutdown_exit);
diff --git a/drivers/soc/renesas/s2ram_ddr_backup.c b/drivers/soc/renesas/s2ram_ddr_backup.c
index de12b3c..9e6e14f6 100644
--- a/drivers/soc/renesas/s2ram_ddr_backup.c
+++ b/drivers/soc/renesas/s2ram_ddr_backup.c
@@ -237,6 +237,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(handle_registers);
 
 /*
  * Handle backup/restore of IPs
@@ -260,6 +261,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(handle_ips);
 
 #ifdef CONFIG_PM_SLEEP
 static int ddr_bck_suspend(void)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec..567b4a7 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -552,6 +552,26 @@
 	help
 	  SPI driver for SuperH and SH Mobile MSIOF blocks.
 
+config SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+	bool "Transfer Synchronization Debug support for MSIOF"
+	depends on SPI_SH_MSIOF
+	default n
+	help
+	  In data transfer, the slave needs to have completed
+	  a transfer preparation before the master.
+	  As a test environment, it was to be able to put a sleep wait
+	  before the data transfer of the master.
+
+config SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG_MSLEEP
+	int "Master of sleep latency (msec time)"
+	default 1
+	depends on SPI_SH_MSIOF && SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+	help
+	  Select Sleep latency of the previous data transfer
+	  at the time of master mode.
+	  Examples:
+	    N => N msec
+
 config SPI_SH
 	tristate "SuperH SPI controller"
 	depends on SUPERH || COMPILE_TEST
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index aa71fe9..c1c632b 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1,6 +1,7 @@
 /*
  * SuperH MSIOF SPI Master Interface
  *
+ * Copyright (C) 2016 Renesas Electronics Corporation
  * Copyright (c) 2009 Magnus Damm
  * Copyright (C) 2014 Glider bvba
  *
@@ -29,6 +30,7 @@
 #include <linux/sh_dma.h>
 
 #include <linux/soc/renesas/s2ram_ddr_backup.h>
+#include <linux/soc/renesas/rcar_prr.h>
 #include <linux/spi/sh_msiof.h>
 #include <linux/spi/spi.h>
 
@@ -40,6 +42,10 @@
 	u16 master_flags;
 };
 
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+#define TRANSFAR_SYNC_DELAY (CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG_MSLEEP)
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
+
 struct sh_msiof_spi_priv {
 	struct spi_master *master;
 	void __iomem *mapbase;
@@ -48,8 +54,10 @@
 	const struct sh_msiof_chipdata *chipdata;
 	struct sh_msiof_spi_info *info;
 	struct completion done;
+	struct completion done_dma_tx, done_dma_rx;
 	unsigned int tx_fifo_size;
 	unsigned int rx_fifo_size;
+	int mode;
 	void *tx_dma_page;
 	void *rx_dma_page;
 	dma_addr_t tx_dma_addr;
@@ -82,6 +90,7 @@
 #define MDR1_SYNCMD_LR	 0x30000000 /*   L/R mode */
 #define MDR1_SYNCAC_SHIFT	 25 /* Sync Polarity (1 = Active-low) */
 #define MDR1_BITLSB_SHIFT	 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_DTDL_MASK  0x00700000 /* Data Pin Bit Delay Mask */
 #define MDR1_DTDL_SHIFT		 20 /* Data Pin Bit Delay for MSIOF_SYNC */
 #define MDR1_SYNCDL_SHIFT	 16 /* Frame Sync Signal Timing Delay */
 #define MDR1_FLD_MASK	 0x0000000c /* Frame Sync Signal Interval (0-3) */
@@ -328,6 +337,24 @@
 }
 #endif /* CONFIG_RCAR_DDR_BACKUP*/
 
+static int msiof_rcar_is_gen2(struct device *dev)
+{
+	struct device_node *node = dev->of_node;
+
+	return of_device_is_compatible(node, "renesas,msiof-r8a7790") ||
+		of_device_is_compatible(node, "renesas,msiof-r8a7791") ||
+		of_device_is_compatible(node, "renesas,msiof-r8a7793") ||
+		of_device_is_compatible(node, "renesas,msiof-r8a7794");
+}
+
+static int msiof_rcar_is_gen3(struct device *dev)
+{
+	struct device_node *node = dev->of_node;
+
+	return of_device_is_compatible(node, "renesas,msiof-r8a7795") ||
+		of_device_is_compatible(node, "renesas,msiof-r8a7796");
+}
+
 static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
 {
 	switch (reg_offs) {
@@ -416,6 +443,18 @@
 
 	k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1);
 
+	/*
+	 * In case of Gen2 / Gen3, BRDV[2:0]=B'111 is valid only
+	 * when the BRPS[4:0] bits are set to B'00000 or B'00001.
+	 */
+	if ((msiof_rcar_is_gen3(&p->pdev->dev) ||
+		msiof_rcar_is_gen2(&p->pdev->dev)) &&
+		sh_msiof_spi_div_table[k].brdv == SCR_BRDV_DIV_1 &&
+		!(brps == 1 || brps == 2)) {
+		k = 1; /* SCR_BRDV_DIV_1 -> SCR_BRDV_DIV_2 */
+		brps = DIV_ROUND_UP(brps, 2);
+	}
+
 	scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps);
 	sh_msiof_write(p, TSCR, scr);
 	if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
@@ -482,7 +521,34 @@
 	tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
 	tmp |= lsb_first << MDR1_BITLSB_SHIFT;
 	tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
-	sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 0 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 1 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (p->mode == SPI_MSIOF_MASTER)
+		sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+	else
+		sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS10) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 2 << MDR1_DTDL_SHIFT;
+		}
+	}
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) == 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp &= ~MDR1_DTDL_MASK;
+			tmp |= 1 << MDR1_DTDL_SHIFT;
+		}
+	}
 	if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
 		/* These bits are reserved if RX needs TX */
 		tmp &= ~0x0000ffff;
@@ -490,8 +556,18 @@
 	sh_msiof_write(p, RMDR1, tmp);
 
 	tmp = 0;
-	tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
-	tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+	if (RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) <= 0)) {
+		if (p->mode == SPI_MSIOF_MASTER) {
+			tmp |= 0 << CTR_TSCKIZ_POL_SHIFT;
+			tmp |= 0 << CTR_RSCKIZ_POL_SHIFT;
+		} else {
+			tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+			tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+		}
+	} else {
+		tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+		tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
+	}
 
 	edge = cpol ^ !cpha;
 
@@ -709,17 +785,18 @@
 
 static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
 {
-	int ret;
+	int ret = 0;
 
 	/* setup clock and rx/tx signals */
-	ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
+	if (p->mode == SPI_MSIOF_MASTER)
+		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
 	if (rx_buf && !ret)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE);
 	if (!ret)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE);
 
 	/* start by setting frame bit */
-	if (!ret)
+	if (!ret && p->mode == SPI_MSIOF_MASTER)
 		ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE);
 
 	return ret;
@@ -727,15 +804,16 @@
 
 static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf)
 {
-	int ret;
+	int ret = 0;
 
 	/* shut down frame, rx/tx and clock signals */
-	ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
+	if (p->mode == SPI_MSIOF_MASTER)
+		ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
 	if (!ret)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
 	if (rx_buf && !ret)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0);
-	if (!ret)
+	if (!ret && p->mode == SPI_MSIOF_MASTER)
 		ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0);
 
 	return ret;
@@ -751,6 +829,9 @@
 {
 	int fifo_shift;
 	int ret;
+	unsigned long timeout;
+
+	timeout = (p->mode == SPI_MSIOF_MASTER) ? HZ : MAX_SCHEDULE_TIMEOUT;
 
 	/* limit maximum word transfer to rx/tx fifo size */
 	if (tx_buf)
@@ -781,7 +862,7 @@
 	}
 
 	/* wait for tx fifo to be emptied / rx fifo to be filled */
-	if (!wait_for_completion_timeout(&p->done, HZ)) {
+	if (!wait_for_completion_timeout(&p->done, timeout)) {
 		dev_err(&p->pdev->dev, "PIO timeout\n");
 		ret = -ETIMEDOUT;
 		goto stop_reset;
@@ -810,12 +891,18 @@
 	return ret;
 }
 
-static void sh_msiof_dma_complete(void *arg)
+static void sh_msiof_tx_dma_complete(void *arg)
 {
 	struct sh_msiof_spi_priv *p = arg;
 
-	sh_msiof_write(p, IER, 0);
-	complete(&p->done);
+	complete(&p->done_dma_tx);
+}
+
+static void sh_msiof_rx_dma_complete(void *arg)
+{
+	struct sh_msiof_spi_priv *p = arg;
+
+	complete(&p->done_dma_rx);
 }
 
 static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
@@ -825,6 +912,9 @@
 	struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
 	dma_cookie_t cookie;
 	int ret;
+	unsigned long timeout;
+
+	timeout = (p->mode == SPI_MSIOF_MASTER) ? HZ : MAX_SCHEDULE_TIMEOUT;
 
 	/* First prepare and submit the DMA request(s), as this may fail */
 	if (rx) {
@@ -835,7 +925,7 @@
 		if (!desc_rx)
 			return -EAGAIN;
 
-		desc_rx->callback = sh_msiof_dma_complete;
+		desc_rx->callback = sh_msiof_rx_dma_complete;
 		desc_rx->callback_param = p;
 		cookie = dmaengine_submit(desc_rx);
 		if (dma_submit_error(cookie))
@@ -854,13 +944,8 @@
 			goto no_dma_tx;
 		}
 
-		if (rx) {
-			/* No callback */
-			desc_tx->callback = NULL;
-		} else {
-			desc_tx->callback = sh_msiof_dma_complete;
-			desc_tx->callback_param = p;
-		}
+		desc_tx->callback = sh_msiof_tx_dma_complete;
+		desc_tx->callback_param = p;
 		cookie = dmaengine_submit(desc_tx);
 		if (dma_submit_error(cookie)) {
 			ret = cookie;
@@ -877,6 +962,8 @@
 	sh_msiof_write(p, IER, ier_bits);
 
 	reinit_completion(&p->done);
+	reinit_completion(&p->done_dma_tx);
+	reinit_completion(&p->done_dma_rx);
 
 	/* Now start DMA */
 	if (rx)
@@ -890,12 +977,37 @@
 		goto stop_dma;
 	}
 
-	/* wait for tx fifo to be emptied / rx fifo to be filled */
-	if (!wait_for_completion_timeout(&p->done, HZ)) {
-		dev_err(&p->pdev->dev, "DMA timeout\n");
-		ret = -ETIMEDOUT;
-		goto stop_reset;
+	/* wait for Tx/Rx DMA completion */
+	if (tx) {
+		ret = wait_for_completion_timeout(&p->done_dma_tx, timeout);
+		if (!ret) {
+			dev_err(&p->pdev->dev, "Tx DMA timeout\n");
+			ret = -ETIMEDOUT;
+			goto stop_reset;
+		}
+		if (!rx) {
+			ier_bits = IER_TEOFE;
+			sh_msiof_write(p, IER, ier_bits);
+
+			/* wait for tx fifo to be emptied */
+			if (!wait_for_completion_timeout(&p->done, timeout)) {
+				dev_err(&p->pdev->dev,
+					"Tx fifo to be emptied timeout\n");
+				ret = -ETIMEDOUT;
+				goto stop_reset;
+			}
+		}
 	}
+	if (rx) {
+		ret = wait_for_completion_timeout(&p->done_dma_rx, timeout);
+		if (!ret) {
+			dev_err(&p->pdev->dev, "Rx DMA timeout\n");
+			ret = -ETIMEDOUT;
+			goto stop_reset;
+		}
+	}
+
+	sh_msiof_write(p, IER, 0);
 
 	/* clear status bits */
 	sh_msiof_reset_str(p);
@@ -988,7 +1100,8 @@
 	int ret;
 
 	/* setup clocks (clock already enabled in chipselect()) */
-	sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
+	if (p->mode == SPI_MSIOF_MASTER)
+		sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
 
 	while (master->dma_tx && len > 15) {
 		/*
@@ -1007,7 +1120,7 @@
 				break;
 			copy32 = copy_bswap32;
 		} else if (bits <= 16) {
-			if (l & 1)
+			if (l & 3)
 				break;
 			copy32 = copy_wswap32;
 		} else {
@@ -1017,6 +1130,11 @@
 		if (tx_buf)
 			copy32(p->tx_dma_page, tx_buf, l / 4);
 
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+		if (p->mode == SPI_MSIOF_MASTER)
+			msleep(TRANSFAR_SYNC_DELAY);
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
+
 		ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
 		if (ret == -EAGAIN) {
 			pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
@@ -1090,6 +1208,12 @@
 	words = len / bytes_per_word;
 
 	while (words > 0) {
+
+#ifdef CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG
+		if (p->mode == SPI_MSIOF_MASTER)
+			msleep(TRANSFAR_SYNC_DELAY);
+#endif /* CONFIG_SPI_SH_MSIOF_TRANSFER_SYNC_DEBUG */
+
 		n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf,
 					   words, bits);
 		if (n < 0)
@@ -1125,6 +1249,8 @@
 	{ .compatible = "renesas,msiof-r8a7792",   .data = &r8a779x_data },
 	{ .compatible = "renesas,msiof-r8a7793",   .data = &r8a779x_data },
 	{ .compatible = "renesas,msiof-r8a7794",   .data = &r8a779x_data },
+	{ .compatible = "renesas,msiof-r8a7795",   .data = &r8a779x_data },
+	{ .compatible = "renesas,msiof-r8a7796",   .data = &r8a779x_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, sh_msiof_match);
@@ -1149,6 +1275,11 @@
 	of_property_read_u32(np, "renesas,dtdl", &info->dtdl);
 	of_property_read_u32(np, "renesas,syncdl", &info->syncdl);
 
+	if (of_property_read_bool(np, "slave"))
+		info->mode = SPI_MSIOF_SLAVE;
+	else
+		info->mode = SPI_MSIOF_MASTER;
+
 	info->num_chipselect = num_cs;
 
 	return info;
@@ -1221,10 +1352,7 @@
 		return 0;
 	}
 
-	/* The DMA engine uses the second register set, if present */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res)
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	master = p->master;
 	master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
@@ -1301,6 +1429,8 @@
 	struct spi_master *master;
 	const struct of_device_id *of_id;
 	struct sh_msiof_spi_priv *p;
+	struct clk *ref_clk;
+	u32 clk_rate = 0;
 	int i;
 	int ret;
 
@@ -1331,6 +1461,8 @@
 	}
 
 	init_completion(&p->done);
+	init_completion(&p->done_dma_tx);
+	init_completion(&p->done_dma_rx);
 
 	p->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(p->clk)) {
@@ -1370,6 +1502,7 @@
 		p->tx_fifo_size = p->info->tx_fifo_override;
 	if (p->info->rx_fifo_override)
 		p->rx_fifo_size = p->info->rx_fifo_override;
+	p->mode = p->info->mode;
 
 	/* init master code */
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1394,6 +1527,23 @@
 		goto err2;
 	}
 
+	if (msiof_rcar_is_gen3(&master->dev)) {
+		ref_clk = devm_clk_get(&pdev->dev, "msiof_ref_clk");
+		if (!IS_ERR(ref_clk))
+			clk_rate = clk_get_rate(ref_clk);
+		if (clk_rate) {
+			clk_prepare_enable(p->clk);
+			clk_set_rate(p->clk, clk_rate);
+			clk_disable_unprepare(p->clk);
+		}
+	}
+
+	ret = RCAR_PRR_INIT();
+	if (ret) {
+		dev_err(&pdev->dev, "rcar workaround init error.\n");
+		goto err2;
+	}
+
 	return 0;
 
  err2:
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index e3c19f3..b016a5a 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2006 SWAPP
  *	Andrea Paterniani <a.paterniani@swapp-eng.it>
  * Copyright (C) 2007 David Brownell (simplification, cleanup)
+ * Copyright (C) 2015 Renesas Electronics Corporation
  *
  * 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
@@ -695,6 +696,7 @@
 static const struct of_device_id spidev_dt_ids[] = {
 	{ .compatible = "rohm,dh2228fv" },
 	{ .compatible = "lineartechnology,ltc2488" },
+	{ .compatible = "renesas,sh-msiof" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/staging/board/Makefile b/drivers/staging/board/Makefile
index 6842745..7a6fa98 100644
--- a/drivers/staging/board/Makefile
+++ b/drivers/staging/board/Makefile
@@ -1,3 +1,4 @@
 obj-y	:= board.o
 obj-$(CONFIG_ARCH_EMEV2)	+= kzm9d.o
 obj-$(CONFIG_ARCH_R8A7740)	+= armadillo800eva.o
+obj-$(CONFIG_ARCH_R8A7795)	+= salvator-x.o
diff --git a/drivers/staging/board/salvator-x.c b/drivers/staging/board/salvator-x.c
new file mode 100644
index 0000000..313cc94
--- /dev/null
+++ b/drivers/staging/board/salvator-x.c
@@ -0,0 +1,67 @@
+/*
+ * Staging board support for Salvator-X.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cma.h>
+#include <linux/dma-contiguous.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include "board.h"
+#include "../../../mm/cma.h"
+
+struct cma *find_largest_nondefault_cma(void)
+{
+	unsigned long largest_size;
+	int k, largest_idx;
+
+	largest_size = 0;
+	largest_idx = -ENOENT;
+
+	for (k = 0; k < cma_area_count; k++) {
+		if (&cma_areas[k] == dma_contiguous_default_area)
+			continue;
+
+		if (cma_get_size(&cma_areas[k]) > largest_size) {
+			largest_size = cma_get_size(&cma_areas[k]);
+			largest_idx = k;
+		}
+	}
+
+	if (largest_idx != -ENOENT)
+		return &cma_areas[largest_idx];
+
+	return NULL;
+}
+
+struct cma *rcar_gen3_dma_contiguous;
+EXPORT_SYMBOL(rcar_gen3_dma_contiguous);
+
+static void __init salvator_x_board_staging_init(void)
+{
+	phys_addr_t cma_base;
+	unsigned long cma_size;
+
+	rcar_gen3_dma_contiguous = find_largest_nondefault_cma();
+
+	if (rcar_gen3_dma_contiguous) {
+		cma_base = cma_get_base(rcar_gen3_dma_contiguous);
+		cma_size = cma_get_size(rcar_gen3_dma_contiguous) / SZ_1M;
+
+		pr_info("%s: Located CMA at %pa, size %ld MiB\n",
+			__func__, &cma_base, cma_size);
+	}
+}
+
+board_staging("renesas,salvator-x", salvator_x_board_staging_init);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2d702ca..bb288d2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -223,6 +223,14 @@
 	  Enable this to plug the R-Car thermal sensor driver into the Linux
 	  thermal framework.
 
+config RCAR_GEN3_THERMAL
+	tristate "Renesas R-Car Gen3 thermal driver"
+	depends on ARCH_RENESAS || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux
+	  thermal framework.
+
 config KIRKWOOD_THERMAL
 	tristate "Temperature sensor on Marvell Kirkwood SoCs"
 	depends on MACH_KIRKWOOD || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 10b07c1..d41d5dd 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
 obj-$(CONFIG_ROCKCHIP_THERMAL)	+= rockchip_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
+obj-$(CONFIG_RCAR_GEN3_THERMAL)	+= rcar_gen3_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y				+= samsung/
 obj-$(CONFIG_DOVE_THERMAL)  	+= dove_thermal.o
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
new file mode 100644
index 0000000..7377ff4
--- /dev/null
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -0,0 +1,618 @@
+/*
+ *  R-Car Gen3 THS/CIVM thermal sensor driver
+ *  Based on drivers/thermal/rcar_thermal.c
+ *
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/soc/renesas/rcar_prr.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+/* Register offset */
+#define REG_GEN3_CTSR		0x20
+#define REG_GEN3_THCTR		0x20
+#define REG_GEN3_IRQSTR		0x04
+#define REG_GEN3_IRQMSK		0x08
+#define REG_GEN3_IRQCTL		0x0C
+#define REG_GEN3_IRQEN		0x10
+#define REG_GEN3_IRQTEMP1	0x14
+#define REG_GEN3_IRQTEMP2	0x18
+#define REG_GEN3_IRQTEMP3	0x1C
+#define REG_GEN3_TEMP		0x28
+#define REG_GEN3_THCODE1	0x50
+#define REG_GEN3_THCODE2	0x54
+#define REG_GEN3_THCODE3	0x58
+
+#define PTAT_BASE		0xE6198000
+#define REG_GEN3_PTAT1		0x5C
+#define REG_GEN3_PTAT2		0x60
+#define REG_GEN3_PTAT3		0x64
+#define PTAT_SIZE		REG_GEN3_PTAT3
+
+/* CTSR bit */
+#define PONM            (0x1 << 8)
+#define AOUT            (0x1 << 7)
+#define THBGR           (0x1 << 5)
+#define VMEN            (0x1 << 4)
+#define VMST            (0x1 << 1)
+#define THSST           (0x1 << 0)
+
+/* THCTR bit */
+#define CTCTL		(0x1 << 24)
+#define THCNTSEN(x)	(x << 16)
+
+#define BIT_LEN_12	0x1
+
+#define CTEMP_MASK	0xFFF
+
+#define IRQ_TEMP1_BIT	(0x1 << 0)
+#define IRQ_TEMP2_BIT	(0x1 << 1)
+#define IRQ_TEMP3_BIT	(0x1 << 2)
+#define IRQ_TEMPD1_BIT	(0x1 << 3)
+#define IRQ_TEMPD2_BIT	(0x1 << 4)
+#define IRQ_TEMPD3_BIT	(0x1 << 5)
+
+#define MCELSIUS(temp)			((temp) * 1000)
+#define TEMP_IRQ_SHIFT(tsc_id)	(0x1 << tsc_id)
+#define TEMPD_IRQ_SHIFT(tsc_id)	(0x1 << (tsc_id + 3))
+#define GEN3_FUSE_MASK	0xFFF
+
+/* Equation coefficients for thermal calculation formula.*/
+struct equation_coefs {
+	long a1;
+	long b1;
+	long a2;
+	long b2;
+};
+
+
+struct fuse_factors {
+	int thcode_1;
+	int thcode_2;
+	int thcode_3;
+	int ptat_1;
+	int ptat_2;
+	int ptat_3;
+};
+
+struct rcar_thermal_priv {
+	void __iomem *base;
+	struct device *dev;
+	struct thermal_zone_device *zone;
+	struct delayed_work work;
+	struct fuse_factors factor;
+	struct equation_coefs coef;
+	spinlock_t lock;
+	int id;
+	int irq;
+	const struct rcar_thermal_data *data;
+};
+
+struct rcar_thermal_data {
+	int (*thermal_init)(struct rcar_thermal_priv *priv);
+};
+
+#define rcar_priv_to_dev(priv)		((priv)->dev)
+#define rcar_has_irq_support(priv)	((priv)->irq)
+
+/* Temperature calculation  */
+#define CODETSD(x)		((x) * 1000)
+#define TJ_1 96000L
+#define TJ_3 (-41000L)
+
+#define rcar_thermal_read(p, r) _rcar_thermal_read(p, r)
+static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
+{
+	return ioread32(priv->base + reg);
+}
+
+#define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, r, d)
+static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
+				u32 reg, u32 data)
+{
+	iowrite32(data, priv->base + reg);
+}
+
+static int round_temp(int temp)
+{
+	int tmp1, tmp2;
+	int result = 0;
+
+	tmp1 = abs(temp) % 1000;
+	tmp2 = abs(temp) / 1000;
+
+	if (tmp1 < 250)
+		result = CODETSD(tmp2);
+	else if (tmp1 < 750 && tmp1 >= 250)
+		result = CODETSD(tmp2) + 500;
+	else
+		result = CODETSD(tmp2) + 1000;
+
+	return ((temp < 0) ? (result * (-1)) : result);
+}
+
+static int thermal_read_fuse_factor(struct rcar_thermal_priv *priv)
+{
+	void __iomem *ptat_base;
+	int err;
+
+	err = RCAR_PRR_INIT();
+	if (err)
+		return err;
+
+	ptat_base = ioremap_nocache(PTAT_BASE, PTAT_SIZE);
+	if (!ptat_base) {
+		dev_err(rcar_priv_to_dev(priv), "Cannot map FUSE register\n");
+		return -ENOMEM;
+	}
+
+	/* For H3 WS1.0, H3 WS1.1 and M3 ES1.0
+	 * these registers have not been programmed yet.
+	 * We will use fixed value as temporary solution.
+	 */
+	if ((RCAR_PRR_IS_PRODUCT(H3) && (RCAR_PRR_CHK_CUT(H3, WS11) <= 0))
+		|| (RCAR_PRR_IS_PRODUCT(M3) &&
+			(RCAR_PRR_CHK_CUT(M3, ES10) == 0))) {
+		priv->factor.ptat_1 = 2351;
+		priv->factor.ptat_2 = 1509;
+		priv->factor.ptat_3 = 435;
+		switch (priv->id) {
+		case 0:
+			priv->factor.thcode_1 = 3248;
+			priv->factor.thcode_2 = 2800;
+			priv->factor.thcode_3 = 2221;
+			break;
+		case 1:
+			priv->factor.thcode_1 = 3245;
+			priv->factor.thcode_2 = 2795;
+			priv->factor.thcode_3 = 2216;
+			break;
+		case 2:
+			priv->factor.thcode_1 = 3250;
+			priv->factor.thcode_2 = 2805;
+			priv->factor.thcode_3 = 2237;
+			break;
+		}
+	} else {
+		priv->factor.thcode_1 = rcar_thermal_read(priv,
+						REG_GEN3_THCODE1)
+				& GEN3_FUSE_MASK;
+		priv->factor.thcode_2 = rcar_thermal_read(priv,
+						REG_GEN3_THCODE2)
+				& GEN3_FUSE_MASK;
+		priv->factor.thcode_3 = rcar_thermal_read(priv,
+						REG_GEN3_THCODE3)
+				& GEN3_FUSE_MASK;
+		priv->factor.ptat_1 = ioread32(ptat_base + REG_GEN3_PTAT1)
+				& GEN3_FUSE_MASK;
+		priv->factor.ptat_2 = ioread32(ptat_base + REG_GEN3_PTAT2)
+				& GEN3_FUSE_MASK;
+		priv->factor.ptat_3 = ioread32(ptat_base + REG_GEN3_PTAT3)
+				& GEN3_FUSE_MASK;
+	}
+
+	iounmap(ptat_base);
+
+	return 0;
+}
+
+static void thermal_coefficient_calculation(struct rcar_thermal_priv *priv)
+{
+	int tj_2 = 0;
+	long a1, b1;
+	long a2, b2;
+	long a1_num, a1_den;
+	long a2_num, a2_den;
+
+	tj_2 = (CODETSD((priv->factor.ptat_2 - priv->factor.ptat_3) * 137)
+		/ (priv->factor.ptat_1 - priv->factor.ptat_3)) - CODETSD(41);
+
+	/*
+	 * The following code is to calculate coefficients.
+	 */
+	/* Coefficient a1 and b1 */
+	a1_num = CODETSD(priv->factor.thcode_2 - priv->factor.thcode_3);
+	a1_den = tj_2 - TJ_3;
+	a1 = (10000 * a1_num) / a1_den;
+	b1 = (10000 * priv->factor.thcode_3) - ((a1 * TJ_3) / 1000);
+
+	/* Coefficient a2 and b2 */
+	a2_num = CODETSD(priv->factor.thcode_2 - priv->factor.thcode_1);
+	a2_den = tj_2 - TJ_1;
+	a2 = (10000 * a2_num) / a2_den;
+	b2 = (10000 * priv->factor.thcode_1) - ((a2 * TJ_1) / 1000);
+
+	priv->coef.a1 = DIV_ROUND_CLOSEST(a1, 10);
+	priv->coef.b1 = DIV_ROUND_CLOSEST(b1, 10);
+	priv->coef.a2 = DIV_ROUND_CLOSEST(a2, 10);
+	priv->coef.b2 = DIV_ROUND_CLOSEST(b2, 10);
+}
+
+int thermal_temp_converter(struct equation_coefs coef,
+					int temp_code)
+{
+	int temp, temp1, temp2;
+
+	temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1;
+	temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2;
+	temp = (temp1 + temp2) / 2;
+
+	return round_temp(temp);
+}
+
+int thermal_celsius_to_temp(struct equation_coefs coef,
+					int ctemp)
+{
+	int temp_code, temp1, temp2;
+
+	temp1 = (ctemp * coef.a1 / 1000 + coef.b1) / 1000;
+	temp2 = (ctemp * coef.a2 / 1000 + coef.b2) / 1000;
+	temp_code = (temp1 + temp2) / 2;
+
+	return temp_code;
+}
+
+/*
+ *		Zone device functions
+ */
+static int rcar_gen3_thermal_update_temp(struct rcar_thermal_priv *priv)
+{
+	u32 ctemp;
+	unsigned long flags;
+	int temp_cel, temp_code;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ctemp = rcar_thermal_read(priv, REG_GEN3_TEMP) & CTEMP_MASK;
+	if (rcar_has_irq_support(priv)) {
+		temp_cel = thermal_temp_converter(priv->coef, ctemp);
+
+		/* set the interrupts to exceed the temperature */
+		temp_code = thermal_celsius_to_temp(priv->coef,
+						    temp_cel + MCELSIUS(1));
+		rcar_thermal_write(priv, REG_GEN3_IRQTEMP1, temp_code);
+
+		/* set the interrupts to fall below the temperature */
+		temp_code = thermal_celsius_to_temp(priv->coef,
+						    temp_cel - MCELSIUS(1));
+		rcar_thermal_write(priv, REG_GEN3_IRQTEMP2, temp_code);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
+{
+	struct rcar_thermal_priv *priv = devdata;
+	int ctemp;
+	unsigned long flags;
+	u32 ctemp_code;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ctemp_code = rcar_thermal_read(priv, REG_GEN3_TEMP) & CTEMP_MASK;
+	ctemp = thermal_temp_converter(priv->coef, ctemp_code);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if ((ctemp < MCELSIUS(-40)) || (ctemp > MCELSIUS(125))) {
+		struct device *dev = rcar_priv_to_dev(priv);
+
+		dev_dbg(dev, "Temperature is not measured correctly!\n");
+
+		return -EIO;
+	}
+
+	*temp = ctemp;
+
+	return 0;
+}
+
+static int rcar_gen3_r8a7795_thermal_init(struct rcar_thermal_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rcar_thermal_write(priv, REG_GEN3_CTSR,  THBGR);
+	rcar_thermal_write(priv, REG_GEN3_CTSR,  0x0);
+
+	udelay(1000);
+
+	rcar_thermal_write(priv, REG_GEN3_CTSR, PONM);
+	rcar_thermal_write(priv, REG_GEN3_IRQCTL, 0x3F);
+	rcar_thermal_write(priv, REG_GEN3_IRQEN,
+			   IRQ_TEMP1_BIT | IRQ_TEMPD2_BIT);
+	rcar_thermal_write(priv, REG_GEN3_CTSR,
+			PONM | AOUT | THBGR | VMEN);
+	udelay(100);
+
+	rcar_thermal_write(priv, REG_GEN3_CTSR,
+			PONM | AOUT | THBGR | VMEN | VMST | THSST);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static int rcar_gen3_r8a7796_thermal_init(struct rcar_thermal_priv *priv)
+{
+	unsigned long flags;
+	unsigned long reg_val;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rcar_thermal_write(priv, REG_GEN3_THCTR,  0x0);
+	udelay(1000);
+	rcar_thermal_write(priv, REG_GEN3_IRQCTL, 0x3F);
+	rcar_thermal_write(priv, REG_GEN3_IRQEN,
+			   IRQ_TEMP1_BIT | IRQ_TEMPD2_BIT);
+	rcar_thermal_write(priv, REG_GEN3_THCTR, CTCTL | THCNTSEN(BIT_LEN_12));
+	reg_val = rcar_thermal_read(priv, REG_GEN3_THCTR);
+	reg_val &= ~CTCTL;
+	reg_val |= THSST;
+	rcar_thermal_write(priv, REG_GEN3_THCTR, reg_val);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+/*
+ *		Interrupt
+ */
+#define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
+#define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
+static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
+{
+	unsigned long flags;
+
+	if (!rcar_has_irq_support(priv))
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rcar_thermal_write(priv, REG_GEN3_IRQMSK,
+		enable ? (IRQ_TEMP1_BIT | IRQ_TEMPD2_BIT) : 0);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void rcar_gen3_thermal_work(struct work_struct *work)
+{
+	struct rcar_thermal_priv *priv;
+
+	priv = container_of(work, struct rcar_thermal_priv, work.work);
+
+	rcar_gen3_thermal_update_temp(priv);
+	thermal_zone_device_update(priv->zone);
+
+	rcar_thermal_irq_enable(priv);
+}
+
+static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
+{
+	struct rcar_thermal_priv *priv = data;
+	unsigned long flags;
+	int status;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	status = rcar_thermal_read(priv, REG_GEN3_IRQSTR);
+	rcar_thermal_write(priv, REG_GEN3_IRQSTR, 0);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (status == 0)
+		return IRQ_NONE;
+
+	if (status & (IRQ_TEMP1_BIT | IRQ_TEMPD2_BIT)) {
+		rcar_thermal_irq_disable(priv);
+		schedule_delayed_work(&priv->work, 0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
+	.get_temp	= rcar_gen3_thermal_get_temp,
+};
+
+/*
+ *		Platform functions
+ */
+static int rcar_gen3_thermal_remove(struct platform_device *pdev)
+{
+	struct rcar_thermal_priv *priv = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	rcar_thermal_irq_disable(priv);
+	thermal_zone_of_sensor_unregister(dev, priv->zone);
+
+	pm_runtime_put(dev);
+	pm_runtime_disable(dev);
+
+	return 0;
+}
+
+static const struct rcar_thermal_data r8a7795_data = {
+	.thermal_init = rcar_gen3_r8a7795_thermal_init,
+};
+
+static const struct rcar_thermal_data r8a7796_data = {
+	.thermal_init = rcar_gen3_r8a7796_thermal_init,
+};
+
+static const struct of_device_id rcar_thermal_dt_ids[] = {
+	{ .compatible = "renesas,thermal-r8a7795", .data = &r8a7795_data},
+	{ .compatible = "renesas,thermal-r8a7796", .data = &r8a7796_data},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
+
+static int rcar_gen3_thermal_probe(struct platform_device *pdev)
+{
+	struct rcar_thermal_priv *priv;
+	struct device *dev = &pdev->dev;
+	struct resource *res, *irq;
+	int ret = -ENODEV;
+	int idle;
+	struct device_node *tz_nd, *tmp_nd;
+	int i, irq_cnt;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->dev = dev;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	priv->data = of_device_get_match_data(dev);
+	if (!priv->data)
+		goto error_unregister;
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	priv->irq = 0;
+	if (irq) {
+		priv->irq = 1;
+		for_each_node_with_property(tz_nd, "polling-delay") {
+			tmp_nd = of_parse_phandle(tz_nd,
+					"thermal-sensors", 0);
+			if (tmp_nd && !strcmp(tmp_nd->full_name,
+					dev->of_node->full_name)) {
+				of_property_read_u32(tz_nd, "polling-delay",
+					&idle);
+				(idle > 0) ? (priv->irq = 0) :
+						(priv->irq = 1);
+				break;
+			}
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto error_unregister;
+
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->base)) {
+		ret = PTR_ERR(priv->base);
+		goto error_unregister;
+	}
+
+	spin_lock_init(&priv->lock);
+	INIT_DELAYED_WORK(&priv->work, rcar_gen3_thermal_work);
+
+	priv->id = of_alias_get_id(dev->of_node, "tsc");
+
+	priv->zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
+				&rcar_gen3_tz_of_ops);
+
+	if (IS_ERR(priv->zone)) {
+		dev_err(dev, "Can't register thermal zone\n");
+		ret = PTR_ERR(priv->zone);
+		priv->zone = NULL;
+		goto error_unregister;
+	}
+
+	priv->data->thermal_init(priv);
+	ret = thermal_read_fuse_factor(priv);
+	if (ret)
+		goto error_unregister;
+	thermal_coefficient_calculation(priv);
+	ret = rcar_gen3_thermal_update_temp(priv);
+
+	if (ret < 0)
+		goto error_unregister;
+
+	rcar_thermal_irq_enable(priv);
+
+	/* Interrupt */
+	if (rcar_has_irq_support(priv)) {
+		irq_cnt = platform_irq_count(pdev);
+		for (i = 0; i < irq_cnt; i++) {
+			irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+			ret = devm_request_irq(dev, irq->start,
+					       rcar_gen3_thermal_irq,
+					       IRQF_SHARED,
+					       dev_name(dev), priv);
+			if (ret) {
+				dev_err(dev, "IRQ request failed\n ");
+				goto error_unregister;
+			}
+		}
+	}
+
+	dev_info(dev, "Thermal sensor probed\n");
+
+	return 0;
+
+error_unregister:
+	rcar_gen3_thermal_remove(pdev);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_gen3_thermal_suspend(struct device *dev)
+{
+	struct rcar_thermal_priv *priv = dev_get_drvdata(dev);
+
+	pr_debug("%s\n", __func__);
+	rcar_thermal_irq_disable(priv);
+
+	return 0;
+}
+
+static int rcar_gen3_thermal_resume(struct device *dev)
+{
+	struct rcar_thermal_priv *priv = dev_get_drvdata(dev);
+
+	pr_debug("%s\n", __func__);
+	priv->data->thermal_init(priv);
+	rcar_thermal_irq_enable(priv);
+	rcar_gen3_thermal_update_temp(priv);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops,
+			rcar_gen3_thermal_suspend,
+			rcar_gen3_thermal_resume);
+
+#define DEV_PM_OPS (&rcar_gen3_thermal_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct platform_driver rcar_gen3_thermal_driver = {
+	.driver	= {
+		.name	= "rcar_gen3_thermal",
+		.pm	= DEV_PM_OPS,
+		.of_match_table = rcar_thermal_dt_ids,
+	},
+	.probe		= rcar_gen3_thermal_probe,
+	.remove		= rcar_gen3_thermal_remove,
+};
+module_platform_driver(rcar_gen3_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("R-Car Gen3 THS/CIVM driver");
+MODULE_AUTHOR("Renesas Electronics Corporation");
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 70b8b68..cf7528f 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1434,11 +1434,8 @@
 	int copied;
 
 	copied = tty_insert_flip_string(tport, buf, count);
-	if (copied < count) {
-		dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
-			 count - copied);
+	if (copied < count)
 		port->icount.buf_overrun++;
-	}
 
 	port->icount.rx += copied;
 
@@ -1453,8 +1450,6 @@
 		if (s->active_rx == s->cookie_rx[i])
 			return i;
 
-	dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__,
-		s->active_rx);
 	return -1;
 }
 
@@ -1515,9 +1510,9 @@
 
 	dma_async_issue_pending(chan);
 
+	spin_unlock_irqrestore(&port->lock, flags);
 	dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
 		__func__, s->cookie_rx[active], active, s->active_rx);
-	spin_unlock_irqrestore(&port->lock, flags);
 	return;
 
 fail:
@@ -1540,8 +1535,11 @@
 	dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
 			 DMA_TO_DEVICE);
 	dma_release_channel(chan);
-	if (enable_pio)
+	if (enable_pio) {
+		spin_lock_irqsave(&port->lock, flags);
 		sci_start_tx(port);
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
 }
 
 static void sci_submit_rx(struct sci_port *s)
@@ -1565,8 +1563,6 @@
 		if (dma_submit_error(s->cookie_rx[i]))
 			goto fail;
 
-		dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
-			s->cookie_rx[i], i);
 	}
 
 	s->active_rx = s->cookie_rx[0];
@@ -1580,7 +1576,6 @@
 	for (i = 0; i < 2; i++)
 		s->cookie_rx[i] = -EINVAL;
 	s->active_rx = -EINVAL;
-	dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n");
 	sci_rx_dma_release(s, true);
 }
 
@@ -1650,10 +1645,10 @@
 	int active, count;
 	u16 scr;
 
-	spin_lock_irqsave(&port->lock, flags);
-
 	dev_dbg(port->dev, "DMA Rx timed out\n");
 
+	spin_lock_irqsave(&port->lock, flags);
+
 	active = sci_dma_rx_find_active(s);
 	if (active < 0) {
 		spin_unlock_irqrestore(&port->lock, flags);
@@ -1662,9 +1657,9 @@
 
 	status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
 	if (status == DMA_COMPLETE) {
+		spin_unlock_irqrestore(&port->lock, flags);
 		dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
 			s->active_rx, active);
-		spin_unlock_irqrestore(&port->lock, flags);
 
 		/* Let packet complete handler take care of the packet */
 		return;
@@ -1688,8 +1683,6 @@
 	/* Handle incomplete DMA receive */
 	dmaengine_terminate_all(s->chan_rx);
 	read = sg_dma_len(&s->sg_rx[active]) - state.residue;
-	dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read,
-		s->active_rx);
 
 	if (read) {
 		count = sci_dma_rx_push(s, s->rx_buf[active], read);
@@ -1761,8 +1754,7 @@
 
 	dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
 
-	if (!port->dev->of_node &&
-	    (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0))
+	if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
 		return;
 
 	s->cookie_tx = -EINVAL;
@@ -2135,11 +2127,17 @@
 
 static unsigned int sci_get_mctrl(struct uart_port *port)
 {
+	struct sci_port *s = to_sci_port(port);
+	unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
+
 	/*
 	 * CTS/RTS is handled in hardware when supported, while nothing
 	 * else is wired up. Keep it simple and simply assert DSR/CAR.
 	 */
-	return TIOCM_DSR | TIOCM_CAR;
+	if (s->cfg->capabilities & SCIx_HAVE_RTSCTS)
+		mctrl |= TIOCM_CTS;
+
+	return mctrl;
 }
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
@@ -2147,6 +2145,7 @@
 	struct sci_port *s = to_sci_port(port);
 	const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
 	unsigned short scscr, scsptr;
+	unsigned long flags;
 
 	/* check wheter the port has SCSPTR */
 	if (!reg->size) {
@@ -2157,6 +2156,7 @@
 		return;
 	}
 
+	spin_lock_irqsave(&port->lock, flags);
 	scsptr = serial_port_in(port, SCSPTR);
 	scscr = serial_port_in(port, SCSCR);
 
@@ -2170,12 +2170,12 @@
 
 	serial_port_out(port, SCSPTR, scsptr);
 	serial_port_out(port, SCSCR, scscr);
+	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static int sci_startup(struct uart_port *port)
 {
 	struct sci_port *s = to_sci_port(port);
-	unsigned long flags;
 	int ret;
 
 	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -2186,11 +2186,6 @@
 
 	sci_request_dma(port);
 
-	spin_lock_irqsave(&port->lock, flags);
-	sci_start_tx(port);
-	sci_start_rx(port);
-	spin_unlock_irqrestore(&port->lock, flags);
-
 	return 0;
 }
 
@@ -2198,12 +2193,17 @@
 {
 	struct sci_port *s = to_sci_port(port);
 	unsigned long flags;
+	u16 scr;
 
 	dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
 	spin_lock_irqsave(&port->lock, flags);
 	sci_stop_rx(port);
 	sci_stop_tx(port);
+	/* Stop RX and TX, disable related interrupts, keep clock source */
+	scr = serial_port_in(port, SCSCR);
+	serial_port_out(port, SCSCR, scr & (SCSCR_CKE1 | SCSCR_CKE0));
+
 	spin_unlock_irqrestore(&port->lock, flags);
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2358,6 +2358,15 @@
 	reg = sci_getreg(port, SCFCR);
 	if (reg->size)
 		serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+
+	sci_clear_SCxSR(port,
+			SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
+			SCxSR_BREAK_CLEAR(port));
+	if (sci_getreg(port, SCLSR)->size) {
+		status = serial_port_in(port, SCLSR);
+		status &= ~(SCLSR_TO | SCLSR_ORER);
+		serial_port_out(port, SCLSR, status);
+	}
 }
 
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -2371,6 +2380,7 @@
 	int min_err = INT_MAX, err;
 	unsigned long max_freq = 0;
 	int best_clk = -1;
+	unsigned long flags;
 
 	if ((termios->c_cflag & CSIZE) == CS7)
 		smr_val |= SCSMR_CHR;
@@ -2480,6 +2490,8 @@
 		serial_port_out(port, SCCKS, sccks);
 	}
 
+	spin_lock_irqsave(&port->lock, flags);
+
 	sci_reset(port);
 
 	uart_update_timeout(port, termios->c_cflag, baud);
@@ -2497,9 +2509,6 @@
 			case 27: smr_val |= SCSMR_SRC_27; break;
 			}
 		smr_val |= cks;
-		dev_dbg(port->dev,
-			 "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
-			 scr_val, smr_val, brr, sccks, dl, srr);
 		serial_port_out(port, SCSCR, scr_val);
 		serial_port_out(port, SCSMR, smr_val);
 		serial_port_out(port, SCBRR, brr);
@@ -2513,7 +2522,6 @@
 		scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
 		smr_val |= serial_port_in(port, SCSMR) &
 			   (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
-		dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
 		serial_port_out(port, SCSCR, scr_val);
 		serial_port_out(port, SCSMR, smr_val);
 	}
@@ -2542,7 +2550,6 @@
 	}
 
 	scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
-	dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
 	serial_port_out(port, SCSCR, scr_val);
 	if ((srr + 1 == 5) &&
 	    (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
@@ -2591,8 +2598,6 @@
 			bits++;
 		s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) /
 					     (baud / 10), 10);
-		dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
-			s->rx_timeout * 1000 / HZ, port->timeout);
 		if (s->rx_timeout < msecs_to_jiffies(20))
 			s->rx_timeout = msecs_to_jiffies(20);
 	}
@@ -2601,6 +2606,8 @@
 	if ((termios->c_cflag & CREAD) != 0)
 		sci_start_rx(port);
 
+	spin_unlock_irqrestore(&port->lock, flags);
+
 	sci_port_disable(s);
 }
 
@@ -3165,7 +3172,8 @@
 	struct device_node *np = pdev->dev.of_node;
 	const struct of_device_id *match;
 	struct plat_sci_port *p;
-	int id;
+	int id, index;
+	struct of_phandle_args dma_spec;
 
 	if (!IS_ENABLED(CONFIG_OF) || !np)
 		return NULL;
@@ -3191,6 +3199,22 @@
 	p->type = SCI_OF_TYPE(match->data);
 	p->regtype = SCI_OF_REGTYPE(match->data);
 	p->scscr = SCSCR_RE | SCSCR_TE;
+	if (of_property_read_bool(np, "ctsrts"))
+		p->capabilities = SCIx_HAVE_RTSCTS;
+
+	index = of_property_match_string(np, "dma-names", "tx");
+	if (index >= 0)
+		index = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+						   index, &dma_spec);
+	if (index >= 0)
+		p->dma_slave_tx = dma_spec.args[0];
+
+	index = of_property_match_string(np, "dma-names", "rx");
+	if (index >= 0)
+		index = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+						   index, &dma_spec);
+	if (index >= 0)
+		p->dma_slave_rx = dma_spec.args[0];
 
 	return p;
 }
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 7a4fa18..c590418 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -105,6 +105,7 @@
 #define SCFCR_LOOP	BIT(0)	/* Loopback Test */
 
 /* SCLSR (Line Status Register) on (H)SCIF */
+#define SCLSR_TO	BIT(2)	/* Timeout */
 #define SCLSR_ORER	BIT(0)	/* Overrun Error */
 
 /* SCSPTR (Serial Port Register), optional */
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 37e327c..04d1740 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -125,6 +125,9 @@
 		.compatible = "renesas,xhci-r8a7795",
 		.data = &xhci_plat_renesas_rcar_gen3,
 	}, {
+		.compatible = "renesas,xhci-r8a7796",
+		.data = &xhci_plat_renesas_rcar_gen3,
+	}, {
 		.compatible = "renesas,rcar-gen2-xhci",
 		.data = &xhci_plat_renesas_rcar_gen2,
 	}, {
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index 9d58963..d532b1c 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -92,6 +92,7 @@
 	struct device_node *node = dev->of_node;
 
 	return of_device_is_compatible(node, "renesas,xhci-r8a7795") ||
+		of_device_is_compatible(node, "renesas,xhci-r8a7796") ||
 		of_device_is_compatible(node, "renesas,rcar-gen3-xhci");
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index fa7e1ef..e70b5b8 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4886,7 +4886,7 @@
 		xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
 	xhci_print_registers(xhci);
 
-	xhci->quirks = quirks;
+	xhci->quirks |= quirks;
 
 	get_quirks(dev, xhci);
 
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index baeb7d2..012a37a 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -482,6 +482,10 @@
 		.data = (void *)USBHS_TYPE_RCAR_GEN3,
 	},
 	{
+		.compatible = "renesas,usbhs-r8a7796",
+		.data = (void *)USBHS_TYPE_RCAR_GEN3,
+	},
+	{
 		.compatible = "renesas,rcar-gen2-usbhs",
 		.data = (void *)USBHS_TYPE_RCAR_GEN2,
 	},
@@ -514,7 +518,8 @@
 	if (gpio > 0)
 		dparam->enable_gpio = gpio;
 
-	if (dparam->type == USBHS_TYPE_RCAR_GEN2)
+	if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
+	    dparam->type == USBHS_TYPE_RCAR_GEN3)
 		dparam->has_usb_dmac = 1;
 
 	return info;
@@ -697,7 +702,7 @@
 probe_end_pipe_exit:
 	usbhs_pipe_remove(priv);
 
-	dev_info(&pdev->dev, "probe failed\n");
+	dev_info(&pdev->dev, "probe failed (%d)\n", ret);
 
 	return ret;
 }
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 30345c2..7828c5f 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -1064,9 +1064,14 @@
 		goto usbhs_mod_gadget_probe_err_gpriv;
 	}
 
-	gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
+	gpriv->transceiver = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
+	if (PTR_ERR(gpriv->transceiver) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err_add_udc;
+	}
+
 	dev_info(dev, "%stransceiver found\n",
-		 gpriv->transceiver ? "" : "no ");
+		 !IS_ERR_OR_NULL(gpriv->transceiver) ? "" : "no ");
 
 	/*
 	 * CAUTION
diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c
index 6ba5529..3f1d97c 100644
--- a/drivers/watchdog/renesas_wdt.c
+++ b/drivers/watchdog/renesas_wdt.c
@@ -76,6 +76,15 @@
 	return 0;
 }
 
+static int rwdt_set_timeout(struct watchdog_device *wdev,
+			    unsigned int new_timeout)
+{
+	wdev->timeout = new_timeout;
+	rwdt_init_timeout(wdev);
+
+	return 0;
+}
+
 static int rwdt_start(struct watchdog_device *wdev)
 {
 	struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
@@ -121,6 +130,7 @@
 	.start = rwdt_start,
 	.stop = rwdt_stop,
 	.ping = rwdt_init_timeout,
+	.set_timeout = rwdt_set_timeout,
 	.get_timeleft = rwdt_get_timeleft,
 };
 
diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h
index acd6af8..fd5ab0f 100644
--- a/include/drm/drm_gem_cma_helper.h
+++ b/include/drm/drm_gem_cma_helper.h
@@ -10,6 +10,7 @@
  * @paddr: physical address of the backing memory
  * @sgt: scatter/gather table for imported PRIME buffers
  * @vaddr: kernel virtual address of the backing memory
+ * @dev: device used for backing memory alloc/free
  */
 struct drm_gem_cma_object {
 	struct drm_gem_object base;
@@ -18,6 +19,7 @@
 
 	/* For objects with DMA memory allocated by GEM CMA */
 	void *vaddr;
+	struct device *dev;
 };
 
 static inline struct drm_gem_cma_object *
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 7a26286..4a88db8 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -99,11 +99,17 @@
  */
 #define TMIO_MMC_SDIO_STATUS_QUIRK	(1 << 8)
 
+/* The start or stop of SD clock don't wait 10msec. */
+#define TMIO_MMC_CLK_NO_SLEEP		(1 << 9)
+
 /*
  * Some controllers allows to set SDx actual clock
  */
 #define TMIO_MMC_CLK_ACTUAL		(1 << 10)
 
+/* Some controllers have UHS-I sampling clock controller */
+#define TMIO_MMC_HAS_UHS_SCC		(1 << 11)
+
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
@@ -125,6 +131,8 @@
 	unsigned int			cd_gpio;
 	int				alignment_shift;
 	dma_addr_t			dma_rx_offset;
+	unsigned int			max_blk_count;
+	unsigned short			max_segs;
 	void (*set_pwr)(struct platform_device *host, int state);
 	void (*set_clk_div)(struct platform_device *host, int state);
 };
diff --git a/include/linux/of.h b/include/linux/of.h
index 77ddace..0ec3a01 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -585,7 +585,7 @@
 	return NULL;
 }
 
-static inline int of_parse_phandle_with_args(struct device_node *np,
+static inline int of_parse_phandle_with_args(const struct device_node *np,
 					     const char *list_name,
 					     const char *cells_name,
 					     int index,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6a27454..361478f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1128,6 +1128,9 @@
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(const struct pci_dev *, u8, u8));
+void pci_fixup_irqs_local(struct pci_bus *,
+		    u8 (*)(struct pci_dev *, u8 *),
+		    int (*)(const struct pci_dev *, u8, u8));
 #define HAVE_PCI_REQ_REGIONS	2
 int __must_check pci_request_regions(struct pci_dev *, const char *);
 int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 17018f3..908b67c 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -235,6 +235,9 @@
 	if (!pwm)
 		return -EINVAL;
 
+	if (duty_ns < 0 || period_ns < 0)
+		return -EINVAL;
+
 	pwm_get_state(pwm, &state);
 	if (state.duty_cycle == duty_ns && state.period == period_ns)
 		return 0;
diff --git a/include/linux/soc/renesas/rcar_ems_ctrl.h b/include/linux/soc/renesas/rcar_ems_ctrl.h
new file mode 100644
index 0000000..57ef8ad
--- /dev/null
+++ b/include/linux/soc/renesas/rcar_ems_ctrl.h
@@ -0,0 +1,11 @@
+#ifndef __RCAR_EMS_CTRL_H__
+#define __RCAR_EMS_CTRL_H__
+
+#define RCAR_EMS_MODE_OFF       0
+#define RCAR_EMS_MODE_ON        1
+
+extern int register_rcar_ems_notifier(struct notifier_block *nb);
+extern void unregister_rcar_ems_notifier(struct notifier_block *nb);
+extern int rcar_ems_get_mode(void);
+
+#endif /* __RCAR_EMS_CTRL_H__  */
diff --git a/include/linux/spi/sh_msiof.h b/include/linux/spi/sh_msiof.h
index b087a85..f723aa4 100644
--- a/include/linux/spi/sh_msiof.h
+++ b/include/linux/spi/sh_msiof.h
@@ -1,10 +1,16 @@
 #ifndef __SPI_SH_MSIOF_H__
 #define __SPI_SH_MSIOF_H__
 
+enum {
+	SPI_MSIOF_MASTER,
+	SPI_MSIOF_SLAVE,
+};
+
 struct sh_msiof_spi_info {
 	int tx_fifo_override;
 	int rx_fifo_override;
 	u16 num_chipselect;
+	int mode;
 	unsigned int dma_tx_id;
 	unsigned int dma_rx_id;
 	u32 dtdl;
diff --git a/include/media/rcar-fcp.h b/include/media/rcar-fcp.h
index 4c7fc77..ed29027 100644
--- a/include/media/rcar-fcp.h
+++ b/include/media/rcar-fcp.h
@@ -20,6 +20,7 @@
 struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np);
 void rcar_fcp_put(struct rcar_fcp_device *fcp);
 int rcar_fcp_enable(struct rcar_fcp_device *fcp);
+struct device *rcar_fcp_device(struct rcar_fcp_device *fcp);
 void rcar_fcp_disable(struct rcar_fcp_device *fcp);
 #else
 static inline struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np)
@@ -31,6 +32,10 @@
 {
 	return -ENOSYS;
 }
+static inline struct device *rcar_fcp_device(struct rcar_fcp_device *fcp)
+{
+	return NULL;
+}
 static inline void rcar_fcp_disable(struct rcar_fcp_device *fcp) { }
 #endif
 
diff --git a/include/media/rcar_csi2.h b/include/media/rcar_csi2.h
new file mode 100644
index 0000000..1a040fa
--- /dev/null
+++ b/include/media/rcar_csi2.h
@@ -0,0 +1,66 @@
+/*
+ * include/media/rcar_csi2.h
+ *     This file is the driver header
+ *     for the Renesas R-Car MIPI CSI-2 unit.
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This file is based on the include/media/sh_mobile_csi2.h
+ *
+ * Driver header for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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 RCAR_MIPI_CSI
+#define RCAR_MIPI_CSI
+
+#include <linux/list.h>
+
+enum rcar_csi2_phy {
+	RCAR_CSI2_PHY_CSI40,  /* CSI0 */
+	RCAR_CSI2_PHY_CSI20,  /* CSI1 */
+	RCAR_CSI2_PHY_CSI41,  /* CSI2 */
+	RCAR_CSI2_PHY_CSI21,  /* CSI3 */
+};
+
+enum rcar_csi2_link {
+	RCAR_CSI2_LINK_CSI40,
+	RCAR_CSI2_LINK_CSI20,
+	RCAR_CSI2_LINK_CSI41,
+	RCAR_CSI2_LINK_CSI21,
+};
+
+enum rcar_csi2_type {
+	RCAR_CSI2_CSI4X,
+	RCAR_CSI2_CSI2X,
+};
+
+#define RCAR_CSI2_CRC	(1 << 0)
+#define RCAR_CSI2_ECC	(1 << 1)
+
+struct platform_device;
+
+struct rcar_csi2_client_config {
+	enum rcar_csi2_phy phy;
+	enum rcar_csi2_link link;
+	unsigned char lanes;		/* bitmask[3:0] */
+	unsigned char channel;		/* 0..3 */
+	struct platform_device *pdev;	/* client platform device */
+	const char *name;		/* async matching: client name */
+};
+
+struct v4l2_device;
+
+struct rcar_csi2_pdata {
+	enum rcar_csi2_type type;
+	unsigned int flags;
+	struct rcar_csi2_client_config *clients;
+	int num_clients;
+};
+
+#endif
diff --git a/include/media/vsp1.h b/include/media/vsp1.h
index 9322d977..6d9fd98 100644
--- a/include/media/vsp1.h
+++ b/include/media/vsp1.h
@@ -1,7 +1,7 @@
 /*
  * vsp1.h  --  R-Car VSP1 API
  *
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2016 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -26,16 +26,22 @@
 struct vsp1_du_atomic_config {
 	u32 pixelformat;
 	unsigned int pitch;
-	dma_addr_t mem[2];
+	dma_addr_t mem[3];
 	struct v4l2_rect src;
 	struct v4l2_rect dst;
 	unsigned int alpha;
 	unsigned int zpos;
+	bool interlaced;
 };
 
 void vsp1_du_atomic_begin(struct device *dev);
 int vsp1_du_atomic_update(struct device *dev, unsigned int rpf,
 			  const struct vsp1_du_atomic_config *cfg);
 void vsp1_du_atomic_flush(struct device *dev);
+int vsp1_du_if_set_mute(struct device *dev, bool on);
+int vsp1_du_setup_wb(struct device *dev, u32 pixelformat, unsigned int pitch,
+		      dma_addr_t mem[2]);
+void vsp1_du_wait_wb(struct device *dev, u32 count);
+
 
 #endif /* __MEDIA_VSP1_H__ */
diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild
index 9355dd8..061983a 100644
--- a/include/uapi/drm/Kbuild
+++ b/include/uapi/drm/Kbuild
@@ -12,6 +12,7 @@
 header-y += qxl_drm.h
 header-y += r128_drm.h
 header-y += radeon_drm.h
+header-y += rcar_du_drm.h
 header-y += savage_drm.h
 header-y += sis_drm.h
 header-y += tegra_drm.h
diff --git a/include/uapi/drm/rcar_du_drm.h b/include/uapi/drm/rcar_du_drm.h
new file mode 100644
index 0000000..43420db
--- /dev/null
+++ b/include/uapi/drm/rcar_du_drm.h
@@ -0,0 +1,42 @@
+/*
+ * rcar_du_drm.h  --  R-Car Display Unit DRM driver
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_DRM_H__
+#define __RCAR_DU_DRM_H__
+
+struct rcar_du_vmute {
+	int crtc_id;	/* CRTCs ID */
+	int on;		/* Vmute function ON/OFF */
+};
+
+/* DRM_IOCTL_RCAR_DU_SET_SCRSHOT:VSPD screen shot */
+struct rcar_du_screen_shot {
+	unsigned long	buff;
+	unsigned int	buff_len;
+	unsigned int	crtc_id;
+	unsigned int	fmt;
+	unsigned int	width;
+	unsigned int	height;
+};
+
+/* rcar-du + vspd specific ioctls */
+#define DRM_RCAR_DU_SET_VMUTE		0
+#define DRM_RCAR_DU_SCRSHOT		4
+
+#define DRM_IOCTL_DRM_RCAR_DU_SET_VMUTE \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RCAR_DU_SET_VMUTE, \
+		struct rcar_du_vmute)
+
+#define DRM_IOCTL_DRM_RCAR_DU_SCRSHOT \
+	DRM_IOW(DRM_COMMAND_BASE + DRM_RCAR_DU_SCRSHOT, \
+		struct rcar_du_screen_shot)
+
+#endif /* __RCAR_DU_DRM_H__ */
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4040eb9..64192ba 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1926,7 +1926,7 @@
 		goto out_unlock;
 	}
 
-	sockc.tsflags = 0;
+	sockc.tsflags = sk->sk_tsflags;
 	if (msg->msg_controllen) {
 		err = sock_cmsg_send(sk, msg, &sockc);
 		if (unlikely(err)) {
@@ -2677,7 +2677,7 @@
 		dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
 	}
 
-	sockc.tsflags = 0;
+	sockc.tsflags = po->sk.sk_tsflags;
 	if (msg->msg_controllen) {
 		err = sock_cmsg_send(&po->sk, msg, &sockc);
 		if (unlikely(err))
@@ -2880,7 +2880,7 @@
 	if (unlikely(!(dev->flags & IFF_UP)))
 		goto out_unlock;
 
-	sockc.tsflags = 0;
+	sockc.tsflags = sk->sk_tsflags;
 	sockc.mark = sk->sk_mark;
 	if (msg->msg_controllen) {
 		err = sock_cmsg_send(sk, msg, &sockc);
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 49354d1..2145957 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -33,11 +33,15 @@
 	struct clk *clkout[CLKOUTMAX];
 	struct clk_onecell_data onecell;
 	struct rsnd_mod mod;
+	u32 flags;
 
 	int rbga_rate_for_441khz; /* RBGA */
 	int rbgb_rate_for_48khz;  /* RBGB */
 };
 
+#define LRCLK_ASYNC	(1 << 0)
+#define adg_mode_flags(adg)	(adg->flags)
+
 #define for_each_rsnd_clk(pos, adg, i)		\
 	for (i = 0;				\
 	     (i < CLKMAX) &&			\
@@ -355,6 +359,16 @@
 
 	rsnd_adg_set_ssi_clk(ssi_mod, data);
 
+	if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) {
+		struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+		u32 ckr = 0;
+
+		if (0 == (rate % 8000))
+			ckr = 0x80000000;
+
+		rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr);
+	}
+
 	dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
 		rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
 		data, rate);
@@ -518,7 +532,7 @@
 		}
 	}
 
-	rsnd_mod_bset(adg_mod, SSICKR, 0x00FF0000, ckr);
+	rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr);
 	rsnd_mod_write(adg_mod, BRRA,  rbga);
 	rsnd_mod_write(adg_mod, BRRB,  rbgb);
 
@@ -532,6 +546,7 @@
 {
 	struct rsnd_adg *adg;
 	struct device *dev = rsnd_priv_to_dev(priv);
+	struct device_node *np = dev->of_node;
 
 	adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
 	if (!adg) {
@@ -545,6 +560,9 @@
 	rsnd_adg_get_clkin(priv, adg);
 	rsnd_adg_get_clkout(priv, adg);
 
+	if (of_get_property(np, "clkout-lr-asynchronous", NULL))
+		adg->flags = LRCLK_ASYNC;
+
 	priv->adg = adg;
 
 	return 0;
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index e39f916..969a516 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -226,8 +226,12 @@
 	ifscr = 0;
 	fsrate = 0;
 	if (fin != fout) {
+		u64 n;
+
 		ifscr = 1;
-		fsrate = 0x0400000 / fout * fin;
+		n = (u64)0x0400000 * fin;
+		do_div(n, fout);
+		fsrate = n;
 	}
 
 	/*